<commit_before>extern crate rust_htslib;

use crate::bcf::report::table_report::fasta_reader::read_fasta;
use rust_htslib::bam::record::CigarStringView;
use rust_htslib::{bam, bam::Read};
use serde::Serialize;
use std::path::Path;

#[derive(Serialize, Clone, Debug, PartialEq)]
pub enum Marker {
    A,
    T,
    C,
    G,
    N,
    Deletion,
    Insertion,
    Match,
    Pairing,
}

#[derive(Clone, Debug)]
pub struct Alignment {
    sequence: String,
    pos: i64,
    length: u16,
    flags: Vec<u16>,
    name: String,
    cigar: CigarStringView,
    paired: bool,
    mate_pos: i64,
    tid: i32,
    mate_tid: i32,
}

#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct AlignmentNucleobase {
    pub marker_type: Marker,
    pub bases: String,
    pub start_position: f64,
    pub end_position: f64,
    pub flags: Vec<u16>,
    pub name: String,
    pub read_start: u32,
    pub read_end: u32,
}

#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct AlignmentMatch {
    pub marker_type: Marker,
    pub start_position: f64,
    pub end_position: f64,
    pub flags: Vec<u16>,
    pub name: String,
    pub read_start: u32,
    pub read_end: u32,
}

pub fn decode_flags(code: u16) -> Vec<u16> {
    let mut flags_map = Vec::new();
    flags_map.push(0x1);
    flags_map.push(0x2);
    flags_map.push(0x4);
    flags_map.push(0x8);
    flags_map.push(0x10);
    flags_map.push(0x20);
    flags_map.push(0x40);
    flags_map.push(0x80);
    flags_map.push(0x100);
    flags_map.push(0x200);
    flags_map.push(0x400);
    flags_map.push(0x800);

    let mut read_map = Vec::new();

    for flag in flags_map {
        if (flag & code.clone()) == flag {
            read_map.push(flag);
        }
    }

    read_map
}

pub fn read_indexed_bam(path: &Path, chrom: String, from: u64, to: u64) -> Vec<Alignment> {
    let mut bam = bam::IndexedReader::from_path(&path).unwrap();
    let tid = bam.header().tid(chrom.as_bytes()).unwrap();

    let mut alignments: Vec<Alignment> = Vec::new();

    bam.fetch(tid, from, to).unwrap();

    for r in bam.records() {
        let rec = r.unwrap();

        let a = make_alignment(&rec);

        alignments.push(a);
    }

    alignments
}

fn make_alignment(record: &bam::Record) -> Alignment {
    let has_pair = record.is_paired();

    let mate_pos = record.mpos();

    let tid = record.tid();
    let mtid = record.mtid();

    //Cigar String
    let cigstring = record.cigar();

    //Position
    let pos = record.pos();

    //Länge
    let le = record.seq().len() as u16;

    //Sequenz
    let seq = record.seq().as_bytes();
    let sequenz = String::from_utf8(seq).unwrap();

    //Flags
    let flgs = record.flags();
    let flag_string = decode_flags(flgs);

    //Name
    let n = record.qname().to_owned();
    let name = String::from_utf8(n).unwrap();

    let read = Alignment {
        sequence: sequenz,
        pos: pos,
        length: le,
        cigar: cigstring,
        flags: flag_string,
        name: name,
        paired: has_pair,
        mate_pos: mate_pos,
        tid: tid,
        mate_tid: mtid,
    };

    read
}

pub fn make_nucleobases(
    fasta_path: &Path,
    chrom: String,
    snippets: Vec<Alignment>,
    from: u64,
    to: u64,
) -> (Vec<AlignmentNucleobase>, Vec<AlignmentMatch>) {
    let mut bases: Vec<AlignmentNucleobase> = Vec::new();
    let mut matches: Vec<AlignmentMatch> = Vec::new();

    let ref_bases = read_fasta(fasta_path, chrom, from, to);

    for s in snippets {
        let mut cigar_offset: i64 = 0;
        let mut read_offset: i64 = 0;
        let base_string = s.sequence.clone();
        let char_vec: Vec<char> = base_string.chars().collect();

        let mut soft_clip_begin = true;

        let p = s.clone();

        if p.paired && (p.pos + p.length as i64) < p.mate_pos && p.tid == p.mate_tid {
            let pairing = AlignmentMatch {
                marker_type: Marker::Pairing,
                start_position: (p.pos + p.length as i64) as f64 - 0.5,
                end_position: p.mate_pos as f64 - 0.5,
                flags: p.flags.clone(),
                name: p.name.clone(),
                read_start: p.pos.clone() as u32,
                read_end: (p.mate_pos.clone() + 100) as u32,
            };

            matches.push(pairing);
        }

        for c in s.cigar.iter() {
            let mut match_count = 0;
            let mut match_start = 0;
            let mut match_ending = false;

            match c {
                rust_htslib::bam::record::Cigar::Match(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::Match(*c).len() {
                        let snip = s.clone();
                        let b = char_vec[cigar_offset as usize];

                        if snip.pos + read_offset >= from as i64
                            && snip.pos + read_offset < to as i64
                        {
                            let ref_index = snip.pos + read_offset - from as i64;
                            let ref_base = &ref_bases[ref_index as usize];

                            if ref_base.get_marker_type() == b {
                                // Create long rule while bases match
                                if match_count == 0 {
                                    match_start = snip.pos as i64 + read_offset;
                                }
                                match_count += 1;
                                match_ending = true;

                            //m = Marker::Match; // Match with reference fasta
                            } else {
                                let (mtch, base) = make_markers(
                                    snip.clone(),
                                    b,
                                    read_offset,
                                    match_start,
                                    match_count,
                                );
                                match mtch {
                                    Some(m) => matches.push(m),
                                    _ => {}
                                }
                                bases.push(base);

                                match_count = 0;
                                match_start = 0;

                                match_ending = false;
                            }
                        }
                        cigar_offset += 1;
                        read_offset += 1;
                    }

                    if match_ending {
                        let mtch = end_mismatch_detection(s.clone(), match_start, match_count);
                        matches.push(mtch);
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::Ins(c) => {
                    let snip = s.clone();
                    let p: f64 = snip.pos as f64 + read_offset as f64 - 0.5;
                    let m: Marker = Marker::Insertion;
                    let rs;
                    let re;

                    let mut b = String::from("");
                    for _i in 0..rust_htslib::bam::record::Cigar::Ins(*c).len() {
                        let char = char_vec[cigar_offset as usize];
                        b.push(char);

                        cigar_offset += 1;
                    }

                    if snip.paired && snip.tid == snip.mate_tid {
                        if snip.pos < snip.mate_pos {
                            re = snip.mate_pos + 100;
                            rs = snip.pos;
                        } else {
                            rs = snip.mate_pos;
                            re = snip.pos + snip.length as i64;
                        }
                    } else {
                        rs = snip.pos;
                        re = snip.pos + snip.length as i64;
                    }

                    let base = AlignmentNucleobase {
                        marker_type: m,
                        bases: b,
                        start_position: p.clone() as f64 - 0.5,
                        end_position: p as f64 + 0.5,
                        flags: snip.flags,
                        name: snip.name,
                        read_start: rs as u32,
                        read_end: re as u32,
                    };

                    if from as f64 <= (base.start_position + 0.5)
                        && (base.start_position + 0.5) <= to as f64
                    {
                        bases.push(base);
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::Del(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::Del(*c).len() {
                        let snip = s.clone();
                        let m = Marker::Deletion;
                        let p = snip.pos as i64 + read_offset;
                        let f = snip.flags;
                        let n = snip.name;
                        let rs;
                        let re;
                        let b = String::from("");

                        if snip.paired && snip.tid == snip.mate_tid {
                            if snip.pos < snip.mate_pos {
                                re = snip.mate_pos + 100;
                                rs = snip.pos;
                            } else {
                                rs = snip.mate_pos;
                                re = snip.pos + snip.length as i64;
                            }
                        } else {
                            rs = snip.pos;
                            re = snip.pos + snip.length as i64;
                        }

                        let base = AlignmentNucleobase {
                            marker_type: m,
                            bases: b,
                            start_position: p.clone() as f64 - 0.5,
                            end_position: p as f64 + 0.5,
                            flags: f,
                            name: n,
                            read_start: rs as u32,
                            read_end: re as u32,
                        };

                        read_offset += 1;

                        if from as f64 <= (base.start_position + 0.5)
                            && (base.start_position + 0.5) <= to as f64
                        {
                            bases.push(base);
                        }
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::SoftClip(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::SoftClip(*c).len() {
                        let snip = s.clone();
                        let b = char_vec[cigar_offset as usize];

                        if snip.pos + read_offset >= from as i64
                            && snip.pos + read_offset < to as i64
                        {
                            let ref_index = snip.pos + read_offset - from as i64;
                            let ref_base = &ref_bases[ref_index as usize];

                            if ref_base.get_marker_type() == b {
                                // Create long rule while bases match
                                if match_count == 0 {
                                    match_start = snip.pos as i64 + read_offset;
                                }
                                match_count += 1;
                                match_ending = true;
                            } else {
                                let (mtch, base) = make_markers(
                                    snip.clone(),
                                    b,
                                    read_offset,
                                    match_start,
                                    match_count,
                                );
                                match mtch {
                                    Some(m) => matches.push(m),
                                    _ => {}
                                }
                                bases.push(base);

                                match_count = 0;
                                match_start = 0;

                                match_ending = false;
                            }
                        }

                        cigar_offset += 1;
                        if !soft_clip_begin {
                            read_offset += 1;
                        }
                    }

                    if match_ending {
                        let mtch = end_mismatch_detection(s.clone(), match_start, match_count);
                        matches.push(mtch);
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::HardClip(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::HardClip(*c).len() {
                        cigar_offset += 1;
                    }

                    soft_clip_begin = false;
                }
                _ => {
                    soft_clip_begin = false;
                }
            }
        }
    }
    (bases, matches)
}

fn make_markers(
    snip: Alignment,
    b: char,
    read_offset: i64,
    match_start: i64,
    match_count: i64,
) -> (Option<AlignmentMatch>, AlignmentNucleobase) {
    let m: Marker;

    match b {
        // Mismatch
        'A' => m = Marker::A,
        'T' => m = Marker::T,
        'C' => m = Marker::C,
        'N' => m = Marker::N,
        'G' => m = Marker::G,
        _ => m = Marker::Deletion,
    }

    let p = snip.pos as i64 + read_offset;
    let f = snip.flags;
    let n = snip.name;

    let rs: i64;
    let re: i64;

    if snip.paired && snip.tid == snip.mate_tid {
        if snip.pos < snip.mate_pos {
            re = snip.mate_pos + 100;
            rs = snip.pos;
        } else {
            rs = snip.mate_pos;
            re = snip.pos + snip.length as i64;
        }
    } else {
        rs = snip.pos;
        re = snip.pos + snip.length as i64;
    }

    let mut mtch = None;

    if match_count > 0 {
        // First mismatch detection must lead to new creation of all previous matches
        mtch = Some(AlignmentMatch {
            marker_type: Marker::Match,
            start_position: match_start as f64 - 0.5,
            end_position: (match_start + match_count - 1) as f64 + 0.5,
            flags: f.clone(),
            name: n.clone(),
            read_start: rs.clone() as u32,
            read_end: re.clone() as u32,
        });
    }

    let base = AlignmentNucleobase {
        marker_type: m,
        bases: b.to_string(),
        start_position: p.clone() as f64 - 0.5,
        end_position: p as f64 + 0.5,
        flags: f,
        name: n,
        read_start: rs as u32,
        read_end: re as u32,
    };
    (mtch, base)
}

fn end_mismatch_detection(snip: Alignment, match_start: i64, match_count: i64) -> AlignmentMatch {
    let f = snip.flags;
    let n = snip.name;

    let rs: i64;
    let re: i64;

    if snip.paired && snip.tid == snip.mate_tid {
        if snip.pos < snip.mate_pos {
            re = snip.mate_pos + 100;
            rs = snip.pos;
        } else {
            rs = snip.mate_pos;
            re = snip.pos + snip.length as i64;
        }
    } else {
        rs = snip.pos;
        re = snip.pos + snip.length as i64;
    }

    let mtch = AlignmentMatch {
        marker_type: Marker::Match,
        start_position: match_start as f64 - 0.5,
        end_position: (match_start + match_count - 1) as f64 + 0.5,
        flags: f.clone(),
        name: n.clone(),
        read_start: rs.clone() as u32,
        read_end: re.clone() as u32,
    };

    mtch
}
<commit_msg>remove incrementing cigar offset for hard clips (#57)<commit_after>extern crate rust_htslib;

use crate::bcf::report::table_report::fasta_reader::read_fasta;
use rust_htslib::bam::record::CigarStringView;
use rust_htslib::{bam, bam::Read};
use serde::Serialize;
use std::path::Path;

#[derive(Serialize, Clone, Debug, PartialEq)]
pub enum Marker {
    A,
    T,
    C,
    G,
    N,
    Deletion,
    Insertion,
    Match,
    Pairing,
}

#[derive(Clone, Debug)]
pub struct Alignment {
    sequence: String,
    pos: i64,
    length: u16,
    flags: Vec<u16>,
    name: String,
    cigar: CigarStringView,
    paired: bool,
    mate_pos: i64,
    tid: i32,
    mate_tid: i32,
}

#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct AlignmentNucleobase {
    pub marker_type: Marker,
    pub bases: String,
    pub start_position: f64,
    pub end_position: f64,
    pub flags: Vec<u16>,
    pub name: String,
    pub read_start: u32,
    pub read_end: u32,
}

#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct AlignmentMatch {
    pub marker_type: Marker,
    pub start_position: f64,
    pub end_position: f64,
    pub flags: Vec<u16>,
    pub name: String,
    pub read_start: u32,
    pub read_end: u32,
}

pub fn decode_flags(code: u16) -> Vec<u16> {
    let mut flags_map = Vec::new();
    flags_map.push(0x1);
    flags_map.push(0x2);
    flags_map.push(0x4);
    flags_map.push(0x8);
    flags_map.push(0x10);
    flags_map.push(0x20);
    flags_map.push(0x40);
    flags_map.push(0x80);
    flags_map.push(0x100);
    flags_map.push(0x200);
    flags_map.push(0x400);
    flags_map.push(0x800);

    let mut read_map = Vec::new();

    for flag in flags_map {
        if (flag & code.clone()) == flag {
            read_map.push(flag);
        }
    }

    read_map
}

pub fn read_indexed_bam(path: &Path, chrom: String, from: u64, to: u64) -> Vec<Alignment> {
    let mut bam = bam::IndexedReader::from_path(&path).unwrap();
    let tid = bam.header().tid(chrom.as_bytes()).unwrap();

    let mut alignments: Vec<Alignment> = Vec::new();

    bam.fetch(tid, from, to).unwrap();

    for r in bam.records() {
        let rec = r.unwrap();

        let a = make_alignment(&rec);

        alignments.push(a);
    }

    alignments
}

fn make_alignment(record: &bam::Record) -> Alignment {
    let has_pair = record.is_paired();

    let mate_pos = record.mpos();

    let tid = record.tid();
    let mtid = record.mtid();

    //Cigar String
    let cigstring = record.cigar();

    //Position
    let pos = record.pos();

    //Länge
    let le = record.seq().len() as u16;

    //Sequenz
    let seq = record.seq().as_bytes();
    let sequenz = String::from_utf8(seq).unwrap();

    //Flags
    let flgs = record.flags();
    let flag_string = decode_flags(flgs);

    //Name
    let n = record.qname().to_owned();
    let name = String::from_utf8(n).unwrap();

    let read = Alignment {
        sequence: sequenz,
        pos: pos,
        length: le,
        cigar: cigstring,
        flags: flag_string,
        name: name,
        paired: has_pair,
        mate_pos: mate_pos,
        tid: tid,
        mate_tid: mtid,
    };

    read
}

pub fn make_nucleobases(
    fasta_path: &Path,
    chrom: String,
    snippets: Vec<Alignment>,
    from: u64,
    to: u64,
) -> (Vec<AlignmentNucleobase>, Vec<AlignmentMatch>) {
    let mut bases: Vec<AlignmentNucleobase> = Vec::new();
    let mut matches: Vec<AlignmentMatch> = Vec::new();

    let ref_bases = read_fasta(fasta_path, chrom, from, to);

    for s in snippets {
        let mut cigar_offset: i64 = 0;
        let mut read_offset: i64 = 0;
        let base_string = s.sequence.clone();
        let char_vec: Vec<char> = base_string.chars().collect();

        let mut soft_clip_begin = true;

        let p = s.clone();

        if p.paired && (p.pos + p.length as i64) < p.mate_pos && p.tid == p.mate_tid {
            let pairing = AlignmentMatch {
                marker_type: Marker::Pairing,
                start_position: (p.pos + p.length as i64) as f64 - 0.5,
                end_position: p.mate_pos as f64 - 0.5,
                flags: p.flags.clone(),
                name: p.name.clone(),
                read_start: p.pos.clone() as u32,
                read_end: (p.mate_pos.clone() + 100) as u32,
            };

            matches.push(pairing);
        }

        for c in s.cigar.iter() {
            let mut match_count = 0;
            let mut match_start = 0;
            let mut match_ending = false;

            match c {
                rust_htslib::bam::record::Cigar::Match(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::Match(*c).len() {
                        let snip = s.clone();
                        let b = char_vec[cigar_offset as usize];

                        if snip.pos + read_offset >= from as i64
                            && snip.pos + read_offset < to as i64
                        {
                            let ref_index = snip.pos + read_offset - from as i64;
                            let ref_base = &ref_bases[ref_index as usize];

                            if ref_base.get_marker_type() == b {
                                // Create long rule while bases match
                                if match_count == 0 {
                                    match_start = snip.pos as i64 + read_offset;
                                }
                                match_count += 1;
                                match_ending = true;

                            //m = Marker::Match; // Match with reference fasta
                            } else {
                                let (mtch, base) = make_markers(
                                    snip.clone(),
                                    b,
                                    read_offset,
                                    match_start,
                                    match_count,
                                );
                                match mtch {
                                    Some(m) => matches.push(m),
                                    _ => {}
                                }
                                bases.push(base);

                                match_count = 0;
                                match_start = 0;

                                match_ending = false;
                            }
                        }
                        cigar_offset += 1;
                        read_offset += 1;
                    }

                    if match_ending {
                        let mtch = end_mismatch_detection(s.clone(), match_start, match_count);
                        matches.push(mtch);
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::Ins(c) => {
                    let snip = s.clone();
                    let p: f64 = snip.pos as f64 + read_offset as f64 - 0.5;
                    let m: Marker = Marker::Insertion;
                    let rs;
                    let re;

                    let mut b = String::from("");
                    for _i in 0..rust_htslib::bam::record::Cigar::Ins(*c).len() {
                        let char = char_vec[cigar_offset as usize];
                        b.push(char);

                        cigar_offset += 1;
                    }

                    if snip.paired && snip.tid == snip.mate_tid {
                        if snip.pos < snip.mate_pos {
                            re = snip.mate_pos + 100;
                            rs = snip.pos;
                        } else {
                            rs = snip.mate_pos;
                            re = snip.pos + snip.length as i64;
                        }
                    } else {
                        rs = snip.pos;
                        re = snip.pos + snip.length as i64;
                    }

                    let base = AlignmentNucleobase {
                        marker_type: m,
                        bases: b,
                        start_position: p.clone() as f64 - 0.5,
                        end_position: p as f64 + 0.5,
                        flags: snip.flags,
                        name: snip.name,
                        read_start: rs as u32,
                        read_end: re as u32,
                    };

                    if from as f64 <= (base.start_position + 0.5)
                        && (base.start_position + 0.5) <= to as f64
                    {
                        bases.push(base);
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::Del(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::Del(*c).len() {
                        let snip = s.clone();
                        let m = Marker::Deletion;
                        let p = snip.pos as i64 + read_offset;
                        let f = snip.flags;
                        let n = snip.name;
                        let rs;
                        let re;
                        let b = String::from("");

                        if snip.paired && snip.tid == snip.mate_tid {
                            if snip.pos < snip.mate_pos {
                                re = snip.mate_pos + 100;
                                rs = snip.pos;
                            } else {
                                rs = snip.mate_pos;
                                re = snip.pos + snip.length as i64;
                            }
                        } else {
                            rs = snip.pos;
                            re = snip.pos + snip.length as i64;
                        }

                        let base = AlignmentNucleobase {
                            marker_type: m,
                            bases: b,
                            start_position: p.clone() as f64 - 0.5,
                            end_position: p as f64 + 0.5,
                            flags: f,
                            name: n,
                            read_start: rs as u32,
                            read_end: re as u32,
                        };

                        read_offset += 1;

                        if from as f64 <= (base.start_position + 0.5)
                            && (base.start_position + 0.5) <= to as f64
                        {
                            bases.push(base);
                        }
                    }

                    soft_clip_begin = false;
                }
                rust_htslib::bam::record::Cigar::SoftClip(c) => {
                    for _i in 0..rust_htslib::bam::record::Cigar::SoftClip(*c).len() {
                        let snip = s.clone();
                        let b = char_vec[cigar_offset as usize];

                        if snip.pos + read_offset >= from as i64
                            && snip.pos + read_offset < to as i64
                        {
                            let ref_index = snip.pos + read_offset - from as i64;
                            let ref_base = &ref_bases[ref_index as usize];

                            if ref_base.get_marker_type() == b {
                                // Create long rule while bases match
                                if match_count == 0 {
                                    match_start = snip.pos as i64 + read_offset;
                                }
                                match_count += 1;
                                match_ending = true;
                            } else {
                                let (mtch, base) = make_markers(
                                    snip.clone(),
                                    b,
                                    read_offset,
                                    match_start,
                                    match_count,
                                );
                                match mtch {
                                    Some(m) => matches.push(m),
                                    _ => {}
                                }
                                bases.push(base);

                                match_count = 0;
                                match_start = 0;

                                match_ending = false;
                            }
                        }

                        cigar_offset += 1;
                        if !soft_clip_begin {
                            read_offset += 1;
                        }
                    }

                    if match_ending {
                        let mtch = end_mismatch_detection(s.clone(), match_start, match_count);
                        matches.push(mtch);
                    }

                    soft_clip_begin = false;
                }
                _ => {
                    soft_clip_begin = false;
                }
            }
        }
    }
    (bases, matches)
}

fn make_markers(
    snip: Alignment,
    b: char,
    read_offset: i64,
    match_start: i64,
    match_count: i64,
) -> (Option<AlignmentMatch>, AlignmentNucleobase) {
    let m: Marker;

    match b {
        // Mismatch
        'A' => m = Marker::A,
        'T' => m = Marker::T,
        'C' => m = Marker::C,
        'N' => m = Marker::N,
        'G' => m = Marker::G,
        _ => m = Marker::Deletion,
    }

    let p = snip.pos as i64 + read_offset;
    let f = snip.flags;
    let n = snip.name;

    let rs: i64;
    let re: i64;

    if snip.paired && snip.tid == snip.mate_tid {
        if snip.pos < snip.mate_pos {
            re = snip.mate_pos + 100;
            rs = snip.pos;
        } else {
            rs = snip.mate_pos;
            re = snip.pos + snip.length as i64;
        }
    } else {
        rs = snip.pos;
        re = snip.pos + snip.length as i64;
    }

    let mut mtch = None;

    if match_count > 0 {
        // First mismatch detection must lead to new creation of all previous matches
        mtch = Some(AlignmentMatch {
            marker_type: Marker::Match,
            start_position: match_start as f64 - 0.5,
            end_position: (match_start + match_count - 1) as f64 + 0.5,
            flags: f.clone(),
            name: n.clone(),
            read_start: rs.clone() as u32,
            read_end: re.clone() as u32,
        });
    }

    let base = AlignmentNucleobase {
        marker_type: m,
        bases: b.to_string(),
        start_position: p.clone() as f64 - 0.5,
        end_position: p as f64 + 0.5,
        flags: f,
        name: n,
        read_start: rs as u32,
        read_end: re as u32,
    };
    (mtch, base)
}

fn end_mismatch_detection(snip: Alignment, match_start: i64, match_count: i64) -> AlignmentMatch {
    let f = snip.flags;
    let n = snip.name;

    let rs: i64;
    let re: i64;

    if snip.paired && snip.tid == snip.mate_tid {
        if snip.pos < snip.mate_pos {
            re = snip.mate_pos + 100;
            rs = snip.pos;
        } else {
            rs = snip.mate_pos;
            re = snip.pos + snip.length as i64;
        }
    } else {
        rs = snip.pos;
        re = snip.pos + snip.length as i64;
    }

    let mtch = AlignmentMatch {
        marker_type: Marker::Match,
        start_position: match_start as f64 - 0.5,
        end_position: (match_start + match_count - 1) as f64 + 0.5,
        flags: f.clone(),
        name: n.clone(),
        read_start: rs.clone() as u32,
        read_end: re.clone() as u32,
    };

    mtch
}
<|endoftext|>


<commit_before>use rustyline::completion::FilenameCompleter;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use fnv::FnvHashMap;

use std::error::Error;

use rdbg_core::core::debugger;
use rdbg_core::commands;

static PROMPT: &'static str = "\x1b[1;32mrdbg>\x1b[0m ";

pub struct CommandInterpreter {
    debugger: debugger::Debugger,
    commands: FnvHashMap<&'static str, commands::Command>,
}

impl CommandInterpreter {
    pub fn new(debugger: debugger::Debugger) -> CommandInterpreter {
        CommandInterpreter {
            debugger: debugger,
            commands: commands::Command::map(),
        }
    }

    pub fn read_line(&mut self) -> Result<(), Box<Error>> {
        let history_file = "/tmp/.rdbg_history";
        debug!("Starting debugger session");

        let mut rl = Editor::new().history_ignore_space(true);
        let completer = FilenameCompleter::new();
        rl.set_completer(Some(completer));

        if let Err(_) = rl.load_history(history_file) {
            info!("No previous command history file found at: {}", history_file);
        }

        loop {
            let readline = rl.readline(PROMPT);
            match readline {
                Ok(line) => {
                    debug!("User Command: {}", line);

                    rl.add_history_entry(&line);
                    if line == "quit" {
                        break;
                    }

                    if line == "help" {
                        self.command_help(&[]);
                    }
                    else {
                        self.handle_command(&line);
                    }
                },
                Err(ReadlineError::Interrupted) => { break },  // Handle Ctrl-C
                Err(ReadlineError::Eof) => { break },  // Handle Ctrl-D
                Err(err) => { error!("Unknown Error (Rustyline): {:?}", err); break },
            }
        }
        rl.save_history(history_file).unwrap();
        Ok(())
    }

    fn handle_command(&mut self, cmd: &str) {
        // add check for help along with function to split the line
        if let Some(cmd) = self.commands.get(cmd) {
            let status = (cmd.execute)(&[], &mut self.debugger);
            println!("{}", status);
        }
        else {
            self.handle_unknown_command(cmd);
        }
    }

    fn command_help(&self, args: &[&str]) {
        if args.len() == 0 {
            println!("This is the help message");
        }
        else if let Some(cmd) = self.commands.get(args[0]) {
            println!("{}", cmd.help);
        }
        else {
            self.handle_unknown_command(args[0]);
        }
    }

    fn handle_unknown_command(&self, cmd: &str) {
        println!("Undefined command: \"{}\".  Try \"help\"", cmd);
    }
}

<commit_msg>Added proper argument handling for commmands<commit_after>use rustyline::completion::FilenameCompleter;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use fnv::FnvHashMap;

use std::error::Error;

use rdbg_core::core::debugger;
use rdbg_core::commands;

static PROMPT: &'static str = "\x1b[1;32mrdbg>\x1b[0m ";

pub struct CommandInterpreter {
    debugger: debugger::Debugger,
    commands: FnvHashMap<&'static str, commands::Command>,
}

impl CommandInterpreter {
    pub fn new(debugger: debugger::Debugger) -> CommandInterpreter {
        CommandInterpreter {
            debugger: debugger,
            commands: commands::Command::map(),
        }
    }

    pub fn read_line(&mut self) -> Result<(), Box<Error>> {
        let history_file = "/tmp/.rdbg_history";
        debug!("Starting debugger session");

        let mut rl = Editor::new().history_ignore_space(true);
        let completer = FilenameCompleter::new();
        rl.set_completer(Some(completer));

        if let Err(_) = rl.load_history(history_file) {
            info!("No previous command history file found at: {}", history_file);
        }

        loop {
            let readline = rl.readline(PROMPT);
            match readline {
                Ok(line) => {
                    debug!("User Command: {}", line);
                    rl.add_history_entry(&line);

                    let v: Vec<&str> = line.split(' ').collect();
                    if v[0] == "quit" {
                        break;
                    }

                    if v[0] == "help" {
                        self.command_help(&v);
                    }
                    else {
                        self.handle_command(&v);
                    }
                },
                Err(ReadlineError::Interrupted) => { break },  // Handle Ctrl-C
                Err(ReadlineError::Eof) => { break },  // Handle Ctrl-D
                Err(err) => { error!("Unknown Error (Rustyline): {:?}", err); break },
            }
        }
        rl.save_history(history_file).unwrap();
        Ok(())
    }

    fn handle_command(&mut self, cmd: &[&str]) {
        // add check for help along with function to split the line

        let args = &cmd[1..];
        if let Some(cmd) = self.commands.get(cmd[0]) {
            let status = (cmd.execute)(args, &mut self.debugger);
            println!("{}", status);
        }
        else {
            self.handle_unknown_command(cmd[0]);
        }
    }

    fn command_help(&self, args: &[&str]) {
        if args.len() == 1 {
            println!("This is the help message");
        }
        else if let Some(cmd) = self.commands.get(args[1]) {
            println!("{}", cmd.help);
        }
        else {
            self.handle_unknown_command(args[1]);
        }
    }

    fn handle_unknown_command(&self, cmd: &str) {
        println!("Undefined command: \"{}\".  Try \"help\"", cmd);
    }
}

<|endoftext|>


<commit_before>use std::libc::{c_char, c_int, c_void, c_uint, c_ushort};

#[link_args = "-lnspr4"]
#[nolink]

pub type PRBool = c_int;
pub type PRStatus = c_int;

pub static PRTrue: PRBool = 1;
pub static PRFalse: PRBool = 0;

pub static PRSuccess: PRStatus = 0;
pub static PRFailure: PRStatus = -1;

pub static PR_AF_INET: c_ushort = 2;

pub struct PRNetAddr {
     family: c_ushort,
     port: c_ushort,
     ip: c_uint,
     pad: [c_char, ..8],

}
extern "C" {
fn PR_OpenTCPSocket(af: c_ushort) -> *c_void;
fn PR_Connect(fd: *c_void, addr: *PRNetAddr, timout: c_uint) -> PRStatus;
fn PR_Close(fd: *c_void) -> PRStatus;
fn PR_StringToNetAddr(string: *c_char, addr: *c_void) -> PRStatus;
fn PR_GetError() -> c_int;
fn PR_ErrorToName(error: c_int) -> *c_char;
fn PR_htons(conversion: c_ushort) -> c_ushort;
fn PR_htonl(conversion: c_uint) -> c_uint;
fn PR_Write(fd: *c_void, buf: *c_void, amount: c_int) -> c_int;
fn PR_Read(fd: *c_void, buf: *c_void, amount: c_int) -> c_int;
}
<commit_msg>Make 'em pub<commit_after>use std::libc::{c_char, c_int, c_void, c_uint, c_ushort};

#[link_args = "-lnspr4"]
#[nolink]

pub type PRBool = c_int;
pub type PRStatus = c_int;

pub static PRTrue: PRBool = 1;
pub static PRFalse: PRBool = 0;

pub static PRSuccess: PRStatus = 0;
pub static PRFailure: PRStatus = -1;

pub static PR_AF_INET: c_ushort = 2;

pub struct PRNetAddr {
     family: c_ushort,
     port: c_ushort,
     ip: c_uint,
     pad: [c_char, ..8],

}
extern "C" {
pub fn PR_OpenTCPSocket(af: c_ushort) -> *c_void;
pub fn PR_Connect(fd: *c_void, addr: *PRNetAddr, timout: c_uint) -> PRStatus;
pub fn PR_Close(fd: *c_void) -> PRStatus;
pub fn PR_StringToNetAddr(string: *c_char, addr: *c_void) -> PRStatus;
pub fn PR_GetError() -> c_int;
pub fn PR_ErrorToName(error: c_int) -> *c_char;
pub fn PR_htons(conversion: c_ushort) -> c_ushort;
pub fn PR_htonl(conversion: c_uint) -> c_uint;
pub fn PR_Write(fd: *c_void, buf: *c_void, amount: c_int) -> c_int;
pub fn PR_Read(fd: *c_void, buf: *c_void, amount: c_int) -> c_int;
}
<|endoftext|>


<commit_before>use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

cfg_rt! {
    /// Yields execution back to the Tokio runtime.
    ///
    /// A task yields by awaiting on `yield_now()`, and may resume when that
    /// future completes (with no output.) The current task will be re-added as
    /// a pending task at the _back_ of the pending queue. Any other pending
    /// tasks will be scheduled. No other waking is required for the task to
    /// continue.
    ///
    /// See also the usage example in the [task module](index.html#yield_now).
    #[must_use = "yield_now does nothing unless polled/`await`-ed"]
    pub async fn yield_now() {
        /// Yield implementation
        struct YieldNow {
            yielded: bool,
        }

        impl Future for YieldNow {
            type Output = ();

            fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
                if self.yielded {
                    return Poll::Ready(());
                }

                self.yielded = true;
                cx.waker().wake_by_ref();
                Poll::Pending
            }
        }

        YieldNow { yielded: false }.await
    }
}
<commit_msg>task: document non-guarantees of yield_now (#4091)<commit_after>use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Yields execution back to the Tokio runtime.
///
/// A task yields by awaiting on `yield_now()`, and may resume when that future
/// completes (with no output.) The current task will be re-added as a pending
/// task at the _back_ of the pending queue. Any other pending tasks will be
/// scheduled. No other waking is required for the task to continue.
///
/// See also the usage example in the [task module](index.html#yield_now).
///
/// ## Non-guarantees
///
/// This function may not yield all the way up to the executor if there are any
/// special combinators above it in the call stack. For example, if a
/// [`tokio::select!`] has another branch complete during the same poll as the
/// `yield_now()`, then the yield is not propagated all the way up to the
/// runtime.
///
/// It is generally not guaranteed that the runtime behaves like you expect it
/// to when deciding which task to schedule next after a call to `yield_now()`.
/// In particular, the runtime may choose to poll the task that just ran
/// `yield_now()` again immediately without polling any other tasks first. For
/// example, the runtime will not drive the IO driver between every poll of a
/// task, and this could result in the runtime polling the current task again
/// immediately even if there is another task that could make progress if that
/// other task is waiting for a notification from the IO driver.
///
/// In general, changes to the order in which the runtime polls tasks is not
/// considered a breaking change, and your program should be correct no matter
/// which order the runtime polls your tasks in.
///
/// [`tokio::select!`]: macro@crate::select
#[must_use = "yield_now does nothing unless polled/`await`-ed"]
#[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
pub async fn yield_now() {
    /// Yield implementation
    struct YieldNow {
        yielded: bool,
    }

    impl Future for YieldNow {
        type Output = ();

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
            if self.yielded {
                return Poll::Ready(());
            }

            self.yielded = true;
            cx.waker().wake_by_ref();
            Poll::Pending
        }
    }

    YieldNow { yielded: false }.await
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

extern crate onmf;

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

extern crate num;
use num::{Float};

extern crate ndarray;
use ndarray::{ArrayBase};

macro_rules! bench_ortho_nmf {
    ($bencher:expr, $float:ty, $nhidden:expr, $nobserved:expr, $nsamples:expr) => {{
        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        let mut ortho_nmf = onmf::OrthogonalNMF::<$float>::init_random01(
            $nhidden, $nobserved, $nsamples, &mut rng);

        let samples = DMat::<$float>::new_ones($nsamples, $nobserved);

        let alpha: $float = 0.1 * 1.01.powi(0);
        $bencher.iter(|| {
            ortho_nmf.iterate(alpha, &samples);
        });
    }}
}

macro_rules! bench_ortho_nmf_blas {
    ($bencher:expr, $nhidden:expr, $nobserved:expr, $nsamples:expr) => {{
        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        let mut ortho_nmf = onmf::OrthogonalNMFBlas::init_random01(
            $nhidden, $nobserved, $nsamples, &mut rng);

        let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem(($nsamples, $nobserved), 1.);

        let alpha: f64 = 0.1 * 1.01.powi(0);
        $bencher.iter(|| {
            ortho_nmf.iterate(alpha, &mut samples);
        });
    }}
}

#[bench]
fn bench_ortho_nmf_f64_10_256_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 256, 11);
}
#[bench]
fn bench_ortho_nmf_f32_10_256_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 256, 11);
}
#[bench]
fn bench_ortho_nmf_blas_10_256_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 256, 11);
}

#[bench]
fn bench_ortho_nmf_f64_10_256_20(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 256, 20);
}
#[bench]
fn bench_ortho_nmf_f32_10_256_20(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 256, 20);
}
#[bench]
fn bench_ortho_nmf_blas_10_256_20(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 256, 20);
}

#[bench]
fn bench_ortho_nmf_f64_10_256_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 256, 30);
}
#[bench]
fn bench_ortho_nmf_f32_10_256_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 256, 30);
}
#[bench]
fn bench_ortho_nmf_blas_10_256_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 256, 30);
}

#[bench]
fn bench_ortho_nmf_f64_10_512_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 512, 11);
}
#[bench]
fn bench_ortho_nmf_f32_10_512_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 512, 11);
}
#[bench]
fn bench_ortho_nmf_blas_10_512_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 512, 11);
}

#[bench]
fn bench_ortho_nmf_f64_20_512_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 20, 512, 30);
}
#[bench]
fn bench_ortho_nmf_f32_20_512_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 20, 512, 30);
}
#[bench]
fn bench_ortho_nmf_blas_20_512_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 20, 512, 30);
}
<commit_msg>add more benches<commit_after>#![feature(test)]
extern crate test;

extern crate onmf;

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

extern crate num;
use num::{Float};

extern crate ndarray;
use ndarray::{ArrayBase};

// TODO make a macro that creates these benches

macro_rules! bench_ortho_nmf {
    ($bencher:expr, $float:ty, $nhidden:expr, $nobserved:expr, $nsamples:expr) => {{
        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        let mut ortho_nmf = onmf::OrthogonalNMF::<$float>::init_random01(
            $nhidden, $nobserved, $nsamples, &mut rng);

        let samples = DMat::<$float>::new_ones($nsamples, $nobserved);

        let alpha: $float = 0.1 * 1.01.powi(0);
        $bencher.iter(|| {
            ortho_nmf.iterate(alpha, &samples);
        });
    }}
}

macro_rules! bench_ortho_nmf_blas {
    ($bencher:expr, $nhidden:expr, $nobserved:expr, $nsamples:expr) => {{
        let seed: &[_] = &[1, 2, 3, 4];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        let mut ortho_nmf = onmf::OrthogonalNMFBlas::init_random01(
            $nhidden, $nobserved, $nsamples, &mut rng);

        let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem(($nsamples, $nobserved), 1.);

        let alpha: f64 = 0.1 * 1.01.powi(0);
        $bencher.iter(|| {
            ortho_nmf.iterate(alpha, &mut samples);
        });
    }}
}

#[bench]
fn bench_ortho_nmf_blas_8_32_16(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 8, 32, 16);
}

#[bench]
fn bench_ortho_nmf_blas_6_32_206(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 6, 32, 206);
}

#[bench]
fn bench_ortho_nmf_blas_10_64_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 64, 30);
}
#[bench]
fn bench_ortho_nmf_blas_10_64_60(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 64, 60);
}

#[bench]
fn bench_ortho_nmf_blas_10_64_100(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 64, 100);
}

#[bench]
fn bench_ortho_nmf_f64_10_256_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 256, 11);
}
#[bench]
fn bench_ortho_nmf_f32_10_256_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 256, 11);
}
#[bench]
fn bench_ortho_nmf_blas_10_256_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 256, 11);
}

#[bench]
fn bench_ortho_nmf_f64_10_256_20(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 256, 20);
}
#[bench]
fn bench_ortho_nmf_f32_10_256_20(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 256, 20);
}
#[bench]
fn bench_ortho_nmf_blas_10_256_20(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 256, 20);
}

#[bench]
fn bench_ortho_nmf_f64_10_256_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 256, 30);
}
#[bench]
fn bench_ortho_nmf_f32_10_256_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 256, 30);
}
#[bench]
fn bench_ortho_nmf_blas_10_256_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 256, 30);
}

#[bench]
fn bench_ortho_nmf_f64_10_512_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 10, 512, 11);
}
#[bench]
fn bench_ortho_nmf_f32_10_512_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 10, 512, 11);
}
#[bench]
fn bench_ortho_nmf_blas_10_512_11(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 10, 512, 11);
}

#[bench]
fn bench_ortho_nmf_f64_20_512_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f64, 20, 512, 30);
}
#[bench]
fn bench_ortho_nmf_f32_20_512_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf!(bencher, f32, 20, 512, 30);
}
#[bench]
fn bench_ortho_nmf_blas_20_512_30(bencher: &mut test::Bencher) {
    bench_ortho_nmf_blas!(bencher, 20, 512, 30);
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod types;

use self::types::*;
use common::combinator::Parser;
use common::util::*;
use std::iter::FromIterator;

pub fn tokenize<T: Iterator<Item = char>>(input: T) -> Result<Vec<Token>> {
    let mut l = Lexer::new(input);

    let mut result = Vec::default();

    loop {
        let _ = skip_whitespaces(&mut l);
        match l.preview() {
            None => break,
            _ => {
                result.push(try!(lex_token(&mut l)));
            }
        }
    }

    Ok(result)
}

fn skip_whitespaces(l: &mut Lexer) -> Result<Vec<char>> {
    l.many(|l| l.predicate(|x| [' ', '\t', '\n', '\r'].contains(x)))
}

fn lex_token(l: &mut Lexer) -> Result<Token> {
    l.choose(&[&lex_operator,
               &lex_punctuation,
               &lex_string,
               &lex_reserved_or_ident])
}

macro_rules! parse_map {
    ($pat:expr, $tok:ident) => {
        &|l| {
            let pos = l.current_pos();
            let lit: String = try!(l.string($pat.chars()));
            Ok(token!($tok, pos.0, pos.1, lit))
        }
    }
}

fn lex_operator(l: &mut Lexer) -> Result<Token> {
    l.choose(&[parse_map!("==", Eq),
               parse_map!("=", Assign),
               parse_map!("+", Plus),
               parse_map!("-", Minus),
               parse_map!("*", Multiply),
               parse_map!("/", Divide),
               parse_map!("!=", NotEq),
               parse_map!("!", Not),
               parse_map!(">", GreaterThan),
               parse_map!("<", LessThan)])
}

fn lex_punctuation(l: &mut Lexer) -> Result<Token> {
    l.choose(&[parse_map!(":", Colon),
               parse_map!(";", SemiColon),
               parse_map!(",", Comma),
               parse_map!("(", LParen),
               parse_map!(")", RParen),
               parse_map!("{", LBrace),
               parse_map!("}", RBrace),
               parse_map!("[", LBracket),
               parse_map!("]", RBracket)])
}

fn lex_string(l: &mut Lexer) -> Result<Token> {
    let pos = l.current_pos();
    let mut result = Vec::default();

    result.push(try!(l.atom('"')));
    loop {
        let c = try!(l.next());
        result.push(c);
        match c {
            '\\' => result.push(try!(l.next())),
            '"' => break,
            _ => continue,
        }
    }

    Ok(token!(StringLiteral, pos.0, pos.1, String::from_iter(result)))
}

fn lex_reserved_or_ident(l: &mut Lexer) -> Result<Token> {
    let pos = l.current_pos();
    let fst = try!(l.predicate(is_letter)).to_string();
    let rest: String = try!(l.many(|l| l.predicate(is_letter_or_digit)));
    let name = fst + &rest;

    Ok(match name.as_ref() {
           "let" => token!(Let, pos.0, pos.1, name),
           "fn" => token!(Function, pos.0, pos.1, name),
           "if" => token!(If, pos.0, pos.1, name),
           "else" => token!(Else, pos.0, pos.1, name),
           "return" => token!(Return, pos.0, pos.1, name),
           "true" => token!(BoolLiteral, pos.0, pos.1, name),
           "false" => token!(BoolLiteral, pos.0, pos.1, name),
           _ => token!(Ident, pos.0, pos.1, name),
       })
}

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

    fn lex(input: &str) -> Vec<Token> {
        tokenize(String::from(input).chars()).unwrap()
    }

    fn vec_eq<T: PartialEq + Debug>(xs: &Vec<T>, ys: &Vec<T>) {
        if xs.len() != ys.len() {
            panic!("{:?} != {:?}", xs, ys);
        }
        for i in 0..xs.len() {
            if xs[i] != ys[i] {
                panic!("{:?} != {:?}", xs, ys);
            }
        }
    }

    #[test]
    fn special_chars() {
        vec_eq(&lex("=+(){},;"),
               &vec![token!(Assign, 1, 1, '='),
                     token!(Plus, 1, 2, '+'),
                     token!(LParen, 1, 3, '('),
                     token!(RParen, 1, 4, ')'),
                     token!(LBrace, 1, 5, '{'),
                     token!(RBrace, 1, 6, '}'),
                     token!(Comma, 1, 7, ','),
                     token!(SemiColon, 1, 8, ';')]);
    }

    #[test]
    fn complex_code() {
        vec_eq(&lex("
let five = 5;
let ten = 10;
let add = fn(x, y) {
    x + y;
};
let result = add(five, ten);
               "),
               &vec![token!(Let, 2, 1, "let"),
                     token!(Ident, 2, 5, "five"),
                     token!(Assign, 2, 10, "="),
                     token!(IntLiteral, 2, 12, "5"),
                     token!(SemiColon, 2, 13, ";"),
                     token!(Let, 3, 1, "let"),
                     token!(Ident, 3, 5, "ten"),
                     token!(Assign, 3, 9, "="),
                     token!(IntLiteral, 3, 11, "10"),
                     token!(SemiColon, 3, 13, ";"),
                     token!(Let, 4, 1, "let"),
                     token!(Ident, 4, 5, "add"),
                     token!(Assign, 4, 9, "="),
                     token!(Function, 4, 11, "fn"),
                     token!(LParen, 4, 13, "("),
                     token!(Ident, 4, 14, "x"),
                     token!(Comma, 4, 15, ","),
                     token!(Ident, 4, 17, "y"),
                     token!(RParen, 4, 18, ")"),
                     token!(LBrace, 4, 20, "{"),
                     token!(Ident, 5, 5, "x"),
                     token!(Plus, 5, 7, "+"),
                     token!(Ident, 5, 9, "y"),
                     token!(SemiColon, 5, 10, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(SemiColon, 6, 2, ";"),
                     token!(Let, 7, 1, "let"),
                     token!(Ident, 7, 5, "result"),
                     token!(Assign, 7, 12, "="),
                     token!(Ident, 7, 14, "add"),
                     token!(LParen, 7, 17, "("),
                     token!(Ident, 7, 18, "five"),
                     token!(Comma, 7, 22, ","),
                     token!(Ident, 7, 24, "ten"),
                     token!(RParen, 7, 27, ")"),
                     token!(SemiColon, 7, 28, ";")]);
    }

    #[test]
    fn complex_code2() {
        vec_eq(&lex("
if (a == 10) {
  return a;
} else if (a != 20) {
  return !a;
} else if (a > 20) {
  return -30 / 40 * 50;
} else if (a < 30) {
  return true;
}
return false;
                    "),
               &vec![token!(If, 2, 1, "if"),
                     token!(LParen, 2, 3, "("),
                     token!(Ident, 2, 4, "a"),
                     token!(Eq, 2, 6, "=="),
                     token!(IntLiteral, 2, 9, "10"),
                     token!(RParen, 2, 11, ")"),
                     token!(LBrace, 2, 13, "{"),
                     token!(Return, 3, 3, "return"),
                     token!(Ident, 3, 10, "a"),
                     token!(SemiColon, 3, 11, ";"),
                     token!(RBrace, 4, 1, "}"),
                     token!(Else, 4, 3, "else"),
                     token!(If, 4, 8, "if"),
                     token!(LParen, 4, 11, "("),
                     token!(Ident, 4, 12, "a"),
                     token!(NotEq, 4, 14, "!="),
                     token!(IntLiteral, 4, 17, "20"),
                     token!(RParen, 4, 19, ")"),
                     token!(LBrace, 4, 21, "{"),
                     token!(Return, 5, 3, "return"),
                     token!(Not, 5, 10, "!"),
                     token!(Ident, 5, 11, "a"),
                     token!(SemiColon, 5, 13, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(Else, 6, 3, "else"),
                     token!(If, 6, 8, "if"),
                     token!(LParen, 6, 11, "("),
                     token!(Ident, 6, 12, "a"),
                     token!(GreaterThan, 6, 14, ">"),
                     token!(IntLiteral, 6, 16, "20"),
                     token!(RParen, 6, 18, ")"),
                     token!(LBrace, 6, 20, "{"),
                     token!(Return, 7, 3, "return"),
                     token!(Minus, 7, 10, "-"),
                     token!(IntLiteral, 7, 11, "30"),
                     token!(Divide, 7, 14, "/"),
                     token!(IntLiteral, 7, 16, "40"),
                     token!(Multiply, 7, 19, "*"),
                     token!(IntLiteral, 7, 21, "50"),
                     token!(SemiColon, 7, 23, ";"),
                     token!(RBrace, 8, 1, "}"),
                     token!(Else, 8, 3, "else"),
                     token!(If, 8, 8, "if"),
                     token!(LParen, 8, 11, "("),
                     token!(Ident, 8, 12, "a"),
                     token!(LessThan, 8, 14, "<"),
                     token!(IntLiteral, 8, 16, "30"),
                     token!(RParen, 8, 18, ")"),
                     token!(LBrace, 8, 20, "{"),
                     token!(Return, 9, 3, "return"),
                     token!(BoolLiteral, 9, 10, "true"),
                     token!(SemiColon, 9, 14, ";"),
                     token!(RBrace, 10, 1, "}"),
                     token!(Return, 11, 1, "return"),
                     token!(BoolLiteral, 11, 8, "false"),
                     token!(SemiColon, 11, 13, ";")]);
    }

    #[test]
    fn id_with_numbers() {
        vec_eq(&lex("hello2 hel301oo120"),
               &vec![token!(Ident, 1, 1, "hello2"),
                     token!(Ident, 1, 8, "hel301oo120")]);
    }

    #[test]
    fn string_literals() {
        vec_eq(&lex("\"foobar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foobar\"")]);
        vec_eq(&lex("\"foo bar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo bar\"")]);
        vec_eq(&lex("\"foo\\nbar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\nbar\"")]);
        vec_eq(&lex("\"foo\\tbar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\tbar\"")]);
        vec_eq(&lex("\"foo\\\"bar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\\"bar\"")]);
    }

    #[test]
    fn array_tokens() {
        vec_eq(&lex("[1, 2];"),
               &vec![token!(LBracket, 1, 1, "["),
                     token!(IntLiteral, 1, 2, "1"),
                     token!(Comma, 1, 3, ","),
                     token!(IntLiteral, 1, 5, "2"),
                     token!(RBracket, 1, 6, "]"),
                     token!(SemiColon, 1, 7, ";")]);
    }

    #[test]
    fn hash_tokens() {
        vec_eq(&lex("{\"hello\": \"world\"}"),
               &vec![token!(LBrace, 1, 1, "{"),
                    token!(StringLiteral, 1, 2, "\"hello\""),
                    token!(Colon, 1, 9, ":"),
                    token!(StringLiteral, 1, 11, "\"world\""),
                    token!(RBrace, 1, 18, "}")]);
    }
}
<commit_msg>Implement lexer for integer literal<commit_after>#[macro_use]
pub mod types;

use self::types::*;
use common::combinator::Parser;
use common::util::*;
use std::iter::FromIterator;

pub fn tokenize<T: Iterator<Item = char>>(input: T) -> Result<Vec<Token>> {
    let mut l = Lexer::new(input);

    let mut result = Vec::default();

    loop {
        let _ = skip_whitespaces(&mut l);
        match l.preview() {
            None => break,
            _ => {
                result.push(try!(lex_token(&mut l)));
            }
        }
    }

    Ok(result)
}

fn skip_whitespaces(l: &mut Lexer) -> Result<Vec<char>> {
    l.many(|l| l.predicate(|x| [' ', '\t', '\n', '\r'].contains(x)))
}

fn lex_token(l: &mut Lexer) -> Result<Token> {
    l.choose(&[&lex_operator,
               &lex_punctuation,
               &lex_string,
               &lex_reserved_or_ident,
               &lex_integer])
}

macro_rules! parse_map {
    ($pat:expr, $tok:ident) => {
        &|l| {
            let pos = l.current_pos();
            let lit: String = try!(l.string($pat.chars()));
            Ok(token!($tok, pos.0, pos.1, lit))
        }
    }
}

fn lex_operator(l: &mut Lexer) -> Result<Token> {
    l.choose(&[parse_map!("==", Eq),
               parse_map!("=", Assign),
               parse_map!("+", Plus),
               parse_map!("-", Minus),
               parse_map!("*", Multiply),
               parse_map!("/", Divide),
               parse_map!("!=", NotEq),
               parse_map!("!", Not),
               parse_map!(">", GreaterThan),
               parse_map!("<", LessThan)])
}

fn lex_punctuation(l: &mut Lexer) -> Result<Token> {
    l.choose(&[parse_map!(":", Colon),
               parse_map!(";", SemiColon),
               parse_map!(",", Comma),
               parse_map!("(", LParen),
               parse_map!(")", RParen),
               parse_map!("{", LBrace),
               parse_map!("}", RBrace),
               parse_map!("[", LBracket),
               parse_map!("]", RBracket)])
}

fn lex_string(l: &mut Lexer) -> Result<Token> {
    let pos = l.current_pos();
    let mut result = Vec::default();

    result.push(try!(l.atom('"')));
    loop {
        let c = try!(l.next());
        result.push(c);
        match c {
            '\\' => result.push(try!(l.next())),
            '"' => break,
            _ => continue,
        }
    }

    Ok(token!(StringLiteral, pos.0, pos.1, String::from_iter(result)))
}

fn lex_reserved_or_ident(l: &mut Lexer) -> Result<Token> {
    let pos = l.current_pos();
    let fst = try!(l.predicate(is_letter)).to_string();
    let rest: String = try!(l.many(|l| l.predicate(is_letter_or_digit)));
    let name = fst + &rest;

    Ok(match name.as_ref() {
           "let" => token!(Let, pos.0, pos.1, name),
           "fn" => token!(Function, pos.0, pos.1, name),
           "if" => token!(If, pos.0, pos.1, name),
           "else" => token!(Else, pos.0, pos.1, name),
           "return" => token!(Return, pos.0, pos.1, name),
           "true" => token!(BoolLiteral, pos.0, pos.1, name),
           "false" => token!(BoolLiteral, pos.0, pos.1, name),
           _ => token!(Ident, pos.0, pos.1, name),
       })
}

fn lex_integer(l: &mut Lexer) -> Result<Token> {
    let pos = l.current_pos();
    let lit: String = try!(l.many(|l| l.predicate(is_digit)));
    Ok(token!(IntLiteral, pos.0, pos.1, lit))
}

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

    fn lex(input: &str) -> Vec<Token> {
        tokenize(String::from(input).chars()).unwrap()
    }

    fn vec_eq<T: PartialEq + Debug>(xs: &Vec<T>, ys: &Vec<T>) {
        if xs.len() != ys.len() {
            panic!("{:?} != {:?}", xs, ys);
        }
        for i in 0..xs.len() {
            if xs[i] != ys[i] {
                panic!("{:?} != {:?}", xs, ys);
            }
        }
    }

    #[test]
    fn special_chars() {
        vec_eq(&lex("=+(){},;"),
               &vec![token!(Assign, 1, 1, '='),
                     token!(Plus, 1, 2, '+'),
                     token!(LParen, 1, 3, '('),
                     token!(RParen, 1, 4, ')'),
                     token!(LBrace, 1, 5, '{'),
                     token!(RBrace, 1, 6, '}'),
                     token!(Comma, 1, 7, ','),
                     token!(SemiColon, 1, 8, ';')]);
    }

    #[test]
    fn complex_code() {
        vec_eq(&lex("
let five = 5;
let ten = 10;
let add = fn(x, y) {
    x + y;
};
let result = add(five, ten);
               "),
               &vec![token!(Let, 2, 1, "let"),
                     token!(Ident, 2, 5, "five"),
                     token!(Assign, 2, 10, "="),
                     token!(IntLiteral, 2, 12, "5"),
                     token!(SemiColon, 2, 13, ";"),
                     token!(Let, 3, 1, "let"),
                     token!(Ident, 3, 5, "ten"),
                     token!(Assign, 3, 9, "="),
                     token!(IntLiteral, 3, 11, "10"),
                     token!(SemiColon, 3, 13, ";"),
                     token!(Let, 4, 1, "let"),
                     token!(Ident, 4, 5, "add"),
                     token!(Assign, 4, 9, "="),
                     token!(Function, 4, 11, "fn"),
                     token!(LParen, 4, 13, "("),
                     token!(Ident, 4, 14, "x"),
                     token!(Comma, 4, 15, ","),
                     token!(Ident, 4, 17, "y"),
                     token!(RParen, 4, 18, ")"),
                     token!(LBrace, 4, 20, "{"),
                     token!(Ident, 5, 5, "x"),
                     token!(Plus, 5, 7, "+"),
                     token!(Ident, 5, 9, "y"),
                     token!(SemiColon, 5, 10, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(SemiColon, 6, 2, ";"),
                     token!(Let, 7, 1, "let"),
                     token!(Ident, 7, 5, "result"),
                     token!(Assign, 7, 12, "="),
                     token!(Ident, 7, 14, "add"),
                     token!(LParen, 7, 17, "("),
                     token!(Ident, 7, 18, "five"),
                     token!(Comma, 7, 22, ","),
                     token!(Ident, 7, 24, "ten"),
                     token!(RParen, 7, 27, ")"),
                     token!(SemiColon, 7, 28, ";")]);
    }

    #[test]
    fn complex_code2() {
        vec_eq(&lex("
if (a == 10) {
  return a;
} else if (a != 20) {
  return !a;
} else if (a > 20) {
  return -30 / 40 * 50;
} else if (a < 30) {
  return true;
}
return false;
                    "),
               &vec![token!(If, 2, 1, "if"),
                     token!(LParen, 2, 3, "("),
                     token!(Ident, 2, 4, "a"),
                     token!(Eq, 2, 6, "=="),
                     token!(IntLiteral, 2, 9, "10"),
                     token!(RParen, 2, 11, ")"),
                     token!(LBrace, 2, 13, "{"),
                     token!(Return, 3, 3, "return"),
                     token!(Ident, 3, 10, "a"),
                     token!(SemiColon, 3, 11, ";"),
                     token!(RBrace, 4, 1, "}"),
                     token!(Else, 4, 3, "else"),
                     token!(If, 4, 8, "if"),
                     token!(LParen, 4, 11, "("),
                     token!(Ident, 4, 12, "a"),
                     token!(NotEq, 4, 14, "!="),
                     token!(IntLiteral, 4, 17, "20"),
                     token!(RParen, 4, 19, ")"),
                     token!(LBrace, 4, 21, "{"),
                     token!(Return, 5, 3, "return"),
                     token!(Not, 5, 10, "!"),
                     token!(Ident, 5, 11, "a"),
                     token!(SemiColon, 5, 13, ";"),
                     token!(RBrace, 6, 1, "}"),
                     token!(Else, 6, 3, "else"),
                     token!(If, 6, 8, "if"),
                     token!(LParen, 6, 11, "("),
                     token!(Ident, 6, 12, "a"),
                     token!(GreaterThan, 6, 14, ">"),
                     token!(IntLiteral, 6, 16, "20"),
                     token!(RParen, 6, 18, ")"),
                     token!(LBrace, 6, 20, "{"),
                     token!(Return, 7, 3, "return"),
                     token!(Minus, 7, 10, "-"),
                     token!(IntLiteral, 7, 11, "30"),
                     token!(Divide, 7, 14, "/"),
                     token!(IntLiteral, 7, 16, "40"),
                     token!(Multiply, 7, 19, "*"),
                     token!(IntLiteral, 7, 21, "50"),
                     token!(SemiColon, 7, 23, ";"),
                     token!(RBrace, 8, 1, "}"),
                     token!(Else, 8, 3, "else"),
                     token!(If, 8, 8, "if"),
                     token!(LParen, 8, 11, "("),
                     token!(Ident, 8, 12, "a"),
                     token!(LessThan, 8, 14, "<"),
                     token!(IntLiteral, 8, 16, "30"),
                     token!(RParen, 8, 18, ")"),
                     token!(LBrace, 8, 20, "{"),
                     token!(Return, 9, 3, "return"),
                     token!(BoolLiteral, 9, 10, "true"),
                     token!(SemiColon, 9, 14, ";"),
                     token!(RBrace, 10, 1, "}"),
                     token!(Return, 11, 1, "return"),
                     token!(BoolLiteral, 11, 8, "false"),
                     token!(SemiColon, 11, 13, ";")]);
    }

    #[test]
    fn id_with_numbers() {
        vec_eq(&lex("hello2 hel301oo120"),
               &vec![token!(Ident, 1, 1, "hello2"),
                     token!(Ident, 1, 8, "hel301oo120")]);
    }

    #[test]
    fn string_literals() {
        vec_eq(&lex("\"foobar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foobar\"")]);
        vec_eq(&lex("\"foo bar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo bar\"")]);
        vec_eq(&lex("\"foo\\nbar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\nbar\"")]);
        vec_eq(&lex("\"foo\\tbar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\tbar\"")]);
        vec_eq(&lex("\"foo\\\"bar\""),
               &vec![token!(StringLiteral, 1, 1, "\"foo\\\"bar\"")]);
    }

    #[test]
    fn array_tokens() {
        vec_eq(&lex("[1, 2];"),
               &vec![token!(LBracket, 1, 1, "["),
                     token!(IntLiteral, 1, 2, "1"),
                     token!(Comma, 1, 3, ","),
                     token!(IntLiteral, 1, 5, "2"),
                     token!(RBracket, 1, 6, "]"),
                     token!(SemiColon, 1, 7, ";")]);
    }

    #[test]
    fn hash_tokens() {
        vec_eq(&lex("{\"hello\": \"world\"}"),
               &vec![token!(LBrace, 1, 1, "{"),
                    token!(StringLiteral, 1, 2, "\"hello\""),
                    token!(Colon, 1, 9, ":"),
                    token!(StringLiteral, 1, 11, "\"world\""),
                    token!(RBrace, 1, 18, "}")]);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate crossbeam_epoch as epoch;

#[cfg(any(test, feature = "lock_free_delays"))]
extern crate rand;

#[cfg(any(test, feature = "lock_free_delays"))]
mod debug_delay;

#[cfg(any(test, feature = "lock_free_delays"))]
pub use debug_delay::debug_delay;

/// This function is useful for inducing random jitter into our atomic
/// operations, shaking out more possible interleavings quickly. It gets
/// fully elliminated by the compiler in non-test code.
#[cfg(not(any(test, feature = "lock_free_delays")))]
pub fn debug_delay() {}

pub use epoch::{pin, unprotected, Atomic, Guard, Owned, Shared};
<commit_msg>Update lib.rs<commit_after>#[cfg_attr(any(test, feature = "lock_free_delays"), macro_use)]
extern crate log;
extern crate crossbeam_epoch as epoch;

#[cfg(any(test, feature = "lock_free_delays"))]
extern crate rand;

#[cfg(any(test, feature = "lock_free_delays"))]
mod debug_delay;

#[cfg(any(test, feature = "lock_free_delays"))]
pub use debug_delay::debug_delay;

/// This function is useful for inducing random jitter into our atomic
/// operations, shaking out more possible interleavings quickly. It gets
/// fully elliminated by the compiler in non-test code.
#[cfg(not(any(test, feature = "lock_free_delays")))]
pub fn debug_delay() {}

pub use epoch::{pin, unprotected, Atomic, Guard, Owned, Shared};
<|endoftext|>


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

use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
use rustc::hir::def_id::DefId;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use syntax::ast::{Lit, LitKind, Name};
use syntax::source_map::{Span, Spanned};

/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
/// than calculating their length. Notably, for slices, getting the length
/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
/// good to get into the habit of using `.is_empty()`, and having it is cheap.
/// Besides, it makes the intent clearer than a manual comparison.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.len() == 0 {
///     ..
/// }
/// if y.len() != 0 {
///     ..
/// }
/// ```
/// instead use
/// ```rust
/// if x.len().is_empty() {
///     ..
/// }
/// if !y.len().is_empty() {
///     ..
/// }
/// ```
declare_clippy_lint! {
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
 could be used instead"
}

/// **What it does:** Checks for items that implement `.len()` but not
/// `.is_empty()`.
///
/// **Why is this bad?** It is good custom to have both methods, because for
/// some data structures, asking about the length will be a costly operation,
/// whereas `.is_empty()` can usually answer in constant time. Also it used to
/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
/// lint will ignore such entities.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// impl X {
///     pub fn len(&self) -> usize {
///         ..
///     }
/// }
/// ```
declare_clippy_lint! {
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

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

impl LintPass for LenZero {
    fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_macro(item.span) {
            return;
        }

        match item.node {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_macro(expr.span) {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len <= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 >= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
        if set.insert(traitt) {
            for supertrait in rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.id);
        fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i))
            .any(|i| {
                i.kind == ty::AssociatedKind::Method
                    && i.method_has_self_argument
                    && i.ident.name == "is_empty"
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.ident.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.node_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.node_id) {
            let def_id = cx.tcx.hir().local_def_id(item.id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
    }
}

fn check_len(
    cx: &LateContext<'_, '_>,
    span: Span,
    method_name: Name,
    args: &[Expr],
    lit: &Lit,
    op: &str,
    compare_to: u32,
) {
    if let Spanned {
        node: LitKind::Int(lit, _),
        ..
    } = *lit
    {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                "using `is_empty` is clearer and more explicit",
                format!(
                    "{}{}.is_empty()",
                    op,
                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
                ),
                applicability,
            );
        }
    }
}

/// Check if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
        if let ty::AssociatedKind::Method = item.kind {
            if item.ident.name == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Check the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
        cx.tcx
            .inherent_impls(id)
            .iter()
            .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
    }

    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
    match ty.sty {
        ty::Dynamic(ref tt, ..) => cx
            .tcx
            .associated_items(tt.principal().def_id())
            .any(|item| is_is_empty(cx, &item)),
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<commit_msg>rustup https://github.com/rust-lang/rust/pull/56837<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
use rustc::hir::def_id::DefId;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use syntax::ast::{Lit, LitKind, Name};
use syntax::source_map::{Span, Spanned};

/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
/// than calculating their length. Notably, for slices, getting the length
/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
/// good to get into the habit of using `.is_empty()`, and having it is cheap.
/// Besides, it makes the intent clearer than a manual comparison.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.len() == 0 {
///     ..
/// }
/// if y.len() != 0 {
///     ..
/// }
/// ```
/// instead use
/// ```rust
/// if x.len().is_empty() {
///     ..
/// }
/// if !y.len().is_empty() {
///     ..
/// }
/// ```
declare_clippy_lint! {
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
 could be used instead"
}

/// **What it does:** Checks for items that implement `.len()` but not
/// `.is_empty()`.
///
/// **Why is this bad?** It is good custom to have both methods, because for
/// some data structures, asking about the length will be a costly operation,
/// whereas `.is_empty()` can usually answer in constant time. Also it used to
/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
/// lint will ignore such entities.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// impl X {
///     pub fn len(&self) -> usize {
///         ..
///     }
/// }
/// ```
declare_clippy_lint! {
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

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

impl LintPass for LenZero {
    fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_macro(item.span) {
            return;
        }

        match item.node {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_macro(expr.span) {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len <= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 >= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
        if set.insert(traitt) {
            for supertrait in rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.id);
        fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i))
            .any(|i| {
                i.kind == ty::AssociatedKind::Method
                    && i.method_has_self_argument
                    && i.ident.name == "is_empty"
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.ident.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
        item.ident.name == name
            && if let AssociatedItemKind::Method { has_self } = item.kind {
                has_self && {
                    let did = cx.tcx.hir().local_def_id(item.id.node_id);
                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
                }
            } else {
                false
            }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.node_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.node_id) {
            let def_id = cx.tcx.hir().local_def_id(item.id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
    }
}

fn check_len(
    cx: &LateContext<'_, '_>,
    span: Span,
    method_name: Name,
    args: &[Expr],
    lit: &Lit,
    op: &str,
    compare_to: u32,
) {
    if let Spanned {
        node: LitKind::Int(lit, _),
        ..
    } = *lit
    {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                "using `is_empty` is clearer and more explicit",
                format!(
                    "{}{}.is_empty()",
                    op,
                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
                ),
                applicability,
            );
        }
    }
}

/// Check if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
        if let ty::AssociatedKind::Method = item.kind {
            if item.ident.name == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Check the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
        cx.tcx
            .inherent_impls(id)
            .iter()
            .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
    }

    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
    match ty.sty {
        ty::Dynamic(ref tt, ..) => {
            if let Some(principal) = tt.principal() {
                cx.tcx
                    .associated_items(principal.def_id())
                    .any(|item| is_is_empty(cx, &item))
            } else {
                false
            }
        },
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>mod linkedlist_test;
mod linkedlist{

    pub enum List{
        Cons(int, Box<List>),
        Nil
    }

    pub fn visual_compare(l1: &List, l2: &List) -> String{
        let equality = match equal(l1, l2){
            true  => "",
            false => "not ",
        };
        format!("{} and {} are {}equal", repr(l1), repr(l2), equality)
    }

    pub fn repr(list: &List) -> String{
        match list{
            &Nil => String::from_str("<[]>"),
            &Cons(_, _) => String::from_str("<[").append(_repr_inner(list).as_slice())
        }
    }

    pub fn _repr_inner(list: &List) -> String{
        match list{
            &Nil => String::from_str("]>"),
            &Cons(number, box ref tail) if match tail{
                &Nil => true,
                _ => false,
            }=> number.to_str().append("]>"),
            &Cons(number, box ref tail) => number.to_str().append(", ").append(_repr_inner(tail).as_slice())
        }
    }

    pub fn equal(l1: &List, l2: &List) -> bool{
        match (l1, l2){
            (&Nil, &Nil) => true,
            (&Cons(n1, box ref tail1), &Cons(n2, box ref tail2)) if n1 == n2 => {
                equal(tail1, tail2)
            },
            _ => false,
        }
    }
}
<commit_msg>inner recursion does not need to be public<commit_after>mod linkedlist_test;
mod linkedlist{

    pub enum List{
        Cons(int, Box<List>),
        Nil
    }

    pub fn visual_compare(l1: &List, l2: &List) -> String{
        let equality = match equal(l1, l2){
            true  => "",
            false => "not ",
        };
        format!("{} and {} are {}equal", repr(l1), repr(l2), equality)
    }

    pub fn repr(list: &List) -> String{
        match list{
            &Nil => String::from_str("<[]>"),
            &Cons(_, _) => String::from_str("<[").append(_repr_inner(list).as_slice())
        }
    }

    fn _repr_inner(list: &List) -> String{
        match list{
            &Nil => String::from_str("]>"),
            &Cons(number, box ref tail) if match tail{
                &Nil => true,
                _ => false,
            }=> number.to_str().append("]>"),
            &Cons(number, box ref tail) => number.to_str().append(", ").append(_repr_inner(tail).as_slice())
        }
    }

    pub fn equal(l1: &List, l2: &List) -> bool{
        match (l1, l2){
            (&Nil, &Nil) => true,
            (&Cons(n1, box ref tail1), &Cons(n2, box ref tail2)) if n1 == n2 => {
                equal(tail1, tail2)
            },
            _ => false,
        }
    }
}
<|endoftext|>