<commit_before>use byteorder::{ByteOrder, LittleEndian};
use log::{debug};
use goblin::{Object};
use failure::{Error, Fail};

use super::super::super::arch::{RVA};
use super::super::super::loader::Permissions;
use super::super::super::workspace::Workspace;
use super::super::{Analyzer};
use std::collections::{HashSet};

#[derive(Debug, Fail)]
pub enum RelocAnalyzerError {
    #[fail(display = "Invalid relocation type")]
    InvalidRelocType,
}

pub struct RelocAnalyzer {}

impl RelocAnalyzer {
    pub fn new() -> RelocAnalyzer {
        RelocAnalyzer {}
    }
}

struct Section {
    start: RVA,
    end: RVA,
}

// TODO: make this much faster
fn is_in_insn(ws: &Workspace, rva: RVA) -> bool {
    let start: usize = rva.into();
    // TODO: underflow
    // TODO: remove harded max insn length
    let end: usize = start - 0x10;

    for i in (start..end).rev() {
        let i = RVA::from(i);
        if let Some(meta) = ws.get_meta(i) {
            if !meta.is_insn() {
                continue;
            }

            if let Ok(len) = meta.get_insn_length() {
                if i + len > rva {
                    return true;
                }
            }
        }
    }
    return false;
}

fn is_ptr(ws: &Workspace, rva: RVA) -> bool {
    if let Ok(ptr) = ws.read_va(rva) {
        if let Some(ptr) = ws.rva(ptr) {
            return ws.probe(ptr, 1);
        }
    }
    return false;
}

pub enum RelocationType {
    ImageRelBasedAbsolute,
    ImageRelBasedHigh,
    ImageRelBasedLow,
    ImageRelBasedHighLow,
    ImageRelBasedHighAdj,

    // ImageRelBasedMIPS_JmpAddr,
    // ImageRelBasedARM_MOV32,
    // ImageRelBasedRiscV_High20,
    ImageRelArch1,

    ImageRelReserved,

    // ImageRelBasedTHUMB_MOV32,
    // ImageRelBasedRiscV_Low12I,
    ImageRelArch2,

    ImageRelBasedRiscVLow12S,
    ImageRelBasedMIPSJmpAddr16,
    ImageRelBasedDir64,
}

pub struct Reloc {
    pub typ: RelocationType,
    pub offset: RVA,
}

fn parse_reloc(base: RVA, entry: u16) -> Result<Reloc, Error> {
    let reloc_type   = (entry & 0b1111000000000000) >> 12;
    let reloc_offset =  entry & 0b0000111111111111;

    // TODO: this should probably be on `RelocationType` as a `From` trait.
    let reloc_type = match reloc_type {
        0 => RelocationType::ImageRelBasedAbsolute,
        1 => RelocationType::ImageRelBasedHigh,
        2 => RelocationType::ImageRelBasedLow,
        3 => RelocationType::ImageRelBasedHighLow,
        4 => RelocationType::ImageRelBasedHighAdj,
        5 => RelocationType::ImageRelArch1,
        6 => RelocationType::ImageRelReserved,
        7 => RelocationType::ImageRelArch2,
        8 => RelocationType::ImageRelBasedRiscVLow12S,
        9 => RelocationType::ImageRelBasedMIPSJmpAddr16,
        10 => RelocationType::ImageRelBasedDir64,
        _ => return Err(RelocAnalyzerError::InvalidRelocType.into()),
    };

    Ok(Reloc {
        typ: reloc_type,
        offset: base + RVA::from(reloc_offset as i64),
    })
}

fn split_u32(e: u32) -> (u16, u16) {
    let m = ((e & 0x0000FFFF) >>  0) as u16;
    let n = ((e & 0xFFFF0000) >> 16) as u16;
    (m, n)
}

/// ```
/// use lancelot::rsrc::*;
/// use lancelot::arch::*;
/// use lancelot::workspace::Workspace;
/// use lancelot::analysis::pe::relocs;
///
/// let mut ws = Workspace::from_bytes("k32.dll", &get_buf(Rsrc::K32))
///    .disable_analysis()
///    .load().unwrap();
/// let relocs = relocs::get_relocs(&ws).unwrap();
/// assert_eq!(relocs[0].offset,   RVA(0x76008));
/// assert_eq!(relocs[277].offset, RVA(0xA8000));
/// ```
pub fn get_relocs(ws: &Workspace) -> Result<Vec<Reloc>, Error> {
    let pe = match Object::parse(&ws.buf) {
        Ok(Object::PE(pe)) => pe,
        _ => return Ok(vec![]),
    };

    let opt_header = match pe.header.optional_header {
        Some(opt_header) => opt_header,
        _ => return Ok(vec![]),
    };

    let reloc_directory = match opt_header.data_directories.get_base_relocation_table() {
        Some(reloc_directory) => reloc_directory,
        _ => return Ok(vec![]),
    };

    let dir_start = RVA::from(reloc_directory.virtual_address as i64);
    let buf = ws.read_bytes(dir_start, reloc_directory.size as usize)?;

    let entries: Vec<u32> = buf
        .chunks_exact(0x4)
        .map(|b| LittleEndian::read_u32(b))
        .collect();

    let mut ret = vec![];
    let mut index = 0;
    loop {
        // parse base relocation chunk
        // until there's no data left

        let page_rva = entries.get(index);
        let block_size = entries.get(index+1);
        let (page_rva, block_size) = match (page_rva, block_size) {
            (Some(0),        _               ) => break,
            (_,              Some(0)         ) => break,
            (Some(page_rva), Some(block_size)) => (RVA::from(*page_rva as i64), *block_size),
            _ => break,
        };

        // cast from u32 to usize
        let chunk_entries_count = ((block_size) / 4) as usize;

        for i in 2..chunk_entries_count {
            if let Some(&entry) = entries.get(index + i) {
                let (m, n) = split_u32(entry);

                let reloc1 = parse_reloc(page_rva, m)?;
                if !ws.probe(reloc1.offset, 4) {
                    break
                }
                ret.push(reloc1);

                let reloc2 = parse_reloc(page_rva, n)?;
                if !ws.probe(reloc2.offset, 4) {
                    break
                }
                ret.push(reloc2);
            } else {
                break
            }
        };

        index += chunk_entries_count;
    }

    Ok(ret)
}

fn sections_contain(sections: &[Section], rva: RVA) -> bool {
    sections.iter().find(|section| section.start <= rva && section.end < rva).is_some()
}

impl Analyzer for RelocAnalyzer {
    fn get_name(&self) -> String {
        "PE relocation analyzer".to_string()
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::analysis::Analyzer;
    /// use lancelot::workspace::Workspace;
    /// use lancelot::analysis::pe::RelocAnalyzer;
    ///
    /// let mut ws = Workspace::from_bytes("k32.dll", &get_buf(Rsrc::K32))
    ///    .disable_analysis()
    ///    .load().unwrap();
    ///
    /// let anal = RelocAnalyzer::new();
    /// anal.analyze(&mut ws).unwrap();
    ///
    /// assert!(ws.get_meta(RVA(0xC7F0)).unwrap().is_insn());
    /// ```
    fn analyze(&self, ws: &mut Workspace)-> Result<(), Error> {
        let x_sections: Vec<Section> = ws.module.sections.iter()
            .filter(|section| section.perms.intersects(Permissions::X))
            .map(|section| Section {
                start: section.addr,
                end: section.end(),
            })
            .collect();

        let relocs = get_relocs(ws)?;
        debug!("found {} total relocs", relocs.len());

        let mut unique_targets: HashSet<RVA> = HashSet::new();
        unique_targets.extend(relocs
            .iter()
            .map(|reloc| reloc.offset)
            .map(|rva| ws.read_va(rva))
            .filter_map(Result::ok)
            .filter_map(|va| ws.rva(va)));

        debug!("reduced to {} unique reloc targets", unique_targets.len());

        // scan the relocations
        // looking for pointers into the .text section
        // to things that
        //   1. are not already in an instruction
        //   2. don't appear to be a pointer
        // and assume this is code.
        let o: Vec<RVA> = unique_targets
            .iter()
            .filter(|&&rva| sections_contain(&x_sections, rva))
            .filter(|&&rva| !is_in_insn(ws, rva))
            .filter(|&&rva| !is_ptr(ws, rva))
            .map(|&rva| rva)
            // TODO: maybe ensure that the insn decodes.
            .collect();

        debug!("found {} relocs that point to instructions", o.len());

        o.iter().for_each(|&rva| {
            debug!("found ptr from .text section to .text section at {:#x}", rva);

            // TODO: consume result
            ws.make_insn(rva).unwrap();
            // TODO: consume result
            ws.analyze().unwrap();
        });
        Ok(())
    }
}
<commit_msg>relocs: use std::Range instead of Section<commit_after>use byteorder::{ByteOrder, LittleEndian};
use log::{debug, trace};
use goblin::{Object};
use failure::{Error, Fail};
use std::ops::Range;

use super::super::super::arch::{RVA};
use super::super::super::loader::Permissions;
use super::super::super::workspace::Workspace;
use super::super::{Analyzer};
use std::collections::{HashSet};

#[derive(Debug, Fail)]
pub enum RelocAnalyzerError {
    #[fail(display = "Invalid relocation type")]
    InvalidRelocType,
}

pub struct RelocAnalyzer {}

impl RelocAnalyzer {
    pub fn new() -> RelocAnalyzer {
        RelocAnalyzer {}
    }
}

// TODO: make this much faster
fn is_in_insn(ws: &Workspace, rva: RVA) -> bool {
    let start: usize = rva.into();
    // TODO: underflow
    // TODO: remove harded max insn length
    let end: usize = start - 0x10;

    for i in (start..end).rev() {
        let i = RVA::from(i);
        if let Some(meta) = ws.get_meta(i) {
            if !meta.is_insn() {
                continue;
            }

            if let Ok(len) = meta.get_insn_length() {
                if i + len > rva {
                    return true;
                }
            }
        }
    }
    return false;
}

fn is_ptr(ws: &Workspace, rva: RVA) -> bool {
    if let Ok(ptr) = ws.read_va(rva) {
        if let Some(ptr) = ws.rva(ptr) {
            return ws.probe(ptr, 1);
        }
    }
    return false;
}

pub enum RelocationType {
    ImageRelBasedAbsolute,
    ImageRelBasedHigh,
    ImageRelBasedLow,
    ImageRelBasedHighLow,
    ImageRelBasedHighAdj,

    // ImageRelBasedMIPS_JmpAddr,
    // ImageRelBasedARM_MOV32,
    // ImageRelBasedRiscV_High20,
    ImageRelArch1,

    ImageRelReserved,

    // ImageRelBasedTHUMB_MOV32,
    // ImageRelBasedRiscV_Low12I,
    ImageRelArch2,

    ImageRelBasedRiscVLow12S,
    ImageRelBasedMIPSJmpAddr16,
    ImageRelBasedDir64,
}

pub struct Reloc {
    pub typ: RelocationType,
    pub offset: RVA,
}

fn parse_reloc(base: RVA, entry: u16) -> Result<Reloc, Error> {
    let reloc_type   = (entry & 0b1111000000000000) >> 12;
    let reloc_offset =  entry & 0b0000111111111111;

    // TODO: this should probably be on `RelocationType` as a `From` trait.
    let reloc_type = match reloc_type {
        0 => RelocationType::ImageRelBasedAbsolute,
        1 => RelocationType::ImageRelBasedHigh,
        2 => RelocationType::ImageRelBasedLow,
        3 => RelocationType::ImageRelBasedHighLow,
        4 => RelocationType::ImageRelBasedHighAdj,
        5 => RelocationType::ImageRelArch1,
        6 => RelocationType::ImageRelReserved,
        7 => RelocationType::ImageRelArch2,
        8 => RelocationType::ImageRelBasedRiscVLow12S,
        9 => RelocationType::ImageRelBasedMIPSJmpAddr16,
        10 => RelocationType::ImageRelBasedDir64,
        _ => return Err(RelocAnalyzerError::InvalidRelocType.into()),
    };

    Ok(Reloc {
        typ: reloc_type,
        offset: base + RVA::from(reloc_offset as i64),
    })
}

fn split_u32(e: u32) -> (u16, u16) {
    let m = ((e & 0x0000FFFF) >>  0) as u16;
    let n = ((e & 0xFFFF0000) >> 16) as u16;
    (m, n)
}

/// ```
/// use lancelot::rsrc::*;
/// use lancelot::arch::*;
/// use lancelot::workspace::Workspace;
/// use lancelot::analysis::pe::relocs;
///
/// let mut ws = Workspace::from_bytes("k32.dll", &get_buf(Rsrc::K32))
///    .disable_analysis()
///    .load().unwrap();
/// let relocs = relocs::get_relocs(&ws).unwrap();
/// assert_eq!(relocs[0].offset,   RVA(0x76008));
/// assert_eq!(relocs[277].offset, RVA(0xA8000));
/// ```
pub fn get_relocs(ws: &Workspace) -> Result<Vec<Reloc>, Error> {
    let pe = match Object::parse(&ws.buf) {
        Ok(Object::PE(pe)) => pe,
        _ => return Ok(vec![]),
    };

    let opt_header = match pe.header.optional_header {
        Some(opt_header) => opt_header,
        _ => return Ok(vec![]),
    };

    let reloc_directory = match opt_header.data_directories.get_base_relocation_table() {
        Some(reloc_directory) => reloc_directory,
        _ => return Ok(vec![]),
    };

    let dir_start = RVA::from(reloc_directory.virtual_address as i64);
    let buf = ws.read_bytes(dir_start, reloc_directory.size as usize)?;

    let entries: Vec<u32> = buf
        .chunks_exact(0x4)
        .map(|b| LittleEndian::read_u32(b))
        .collect();

    let mut ret = vec![];
    let mut index = 0;
    loop {
        // parse base relocation chunk
        // until there's no data left

        let page_rva = entries.get(index);
        let block_size = entries.get(index+1);
        let (page_rva, block_size) = match (page_rva, block_size) {
            (Some(0),        _               ) => break,
            (_,              Some(0)         ) => break,
            (Some(page_rva), Some(block_size)) => (RVA::from(*page_rva as i64), *block_size),
            _ => break,
        };

        // cast from u32 to usize
        let chunk_entries_count = ((block_size) / 4) as usize;

        for i in 2..chunk_entries_count {
            if let Some(&entry) = entries.get(index + i) {
                let (m, n) = split_u32(entry);

                let reloc1 = parse_reloc(page_rva, m)?;
                if !ws.probe(reloc1.offset, 4) {
                    break
                }
                ret.push(reloc1);

                let reloc2 = parse_reloc(page_rva, n)?;
                if !ws.probe(reloc2.offset, 4) {
                    break
                }
                ret.push(reloc2);
            } else {
                break
            }
        };

        index += chunk_entries_count;
    }

    Ok(ret)
}

fn sections_contain(sections: &[Range<RVA>], rva: RVA) -> bool {
    sections.iter()
        .find(|section| section.contains(&rva))
        .is_some()
}

impl Analyzer for RelocAnalyzer {
    fn get_name(&self) -> String {
        "PE relocation analyzer".to_string()
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::analysis::Analyzer;
    /// use lancelot::workspace::Workspace;
    /// use lancelot::analysis::pe::RelocAnalyzer;
    ///
    /// let mut ws = Workspace::from_bytes("k32.dll", &get_buf(Rsrc::K32))
    ///    .disable_analysis()
    ///    .load().unwrap();
    ///
    /// let anal = RelocAnalyzer::new();
    /// anal.analyze(&mut ws).unwrap();
    ///
    /// assert!(ws.get_meta(RVA(0xC7F0)).unwrap().is_insn());
    /// ```
    fn analyze(&self, ws: &mut Workspace)-> Result<(), Error> {
        let x_sections: Vec<Range<RVA>> = ws.module.sections.iter()
            .filter(|section| section.perms.intersects(Permissions::X))
            .map(|section| Range {
                start: section.addr,
                end: section.end(),
            })
            .collect();

        let relocs = get_relocs(ws)?;
        debug!("found {} total relocs", relocs.len());

        for reloc in relocs.iter() {
            let target = ws.rva(ws.read_va(reloc.offset)?).expect("reloc target not in image");
            trace!("found reloc {} -> {} {}",
                   reloc.offset,
                   target,
                if sections_contain(&x_sections, target) {"(code)"} else {""}
            );
        }

        // scan for relocations to code.
        //
        // a relocation is a hardcoded offset that must be fixed up if the desired base address
        //  cannot be used.
        // for example, the function pointer passed to CreateThread will be a hardcoded address
        //  of the start of the function.
        //
        // relocated pointers may point to the .data section, e.g. strings or other constants.
        // we want to ignore these.
        // we are only interested in targets in executable sections.
        // we assume these are pointers to instructions/code.
        //
        // looking for pointers into the .text section
        // to things that
        //   1. are not already in an instruction
        //   2. don't appear to be a pointer
        // and assume this is code.

        let mut unique_targets: HashSet<RVA> = HashSet::new();
        unique_targets.extend(relocs
            .iter()
            .map(|reloc| reloc.offset)
            .map(|rva| ws.read_va(rva))
            .filter_map(Result::ok)
            .filter_map(|va| ws.rva(va)));

        debug!("reduced to {} unique reloc targets", unique_targets.len());

       let o: Vec<RVA> = unique_targets
            .iter()
            .filter(|&&rva| sections_contain(&x_sections, rva))
            .filter(|&&rva| !is_in_insn(ws, rva))
            .filter(|&&rva| !is_ptr(ws, rva))
            .map(|&rva| rva)
            // TODO: maybe ensure that the insn decodes.
            .collect();

        debug!("found {} relocs that point to instructions", o.len());

        o.iter().for_each(|&rva| {
            debug!("found pointer via relocations from executable section to {} (code)", rva);

            // TODO: consume result
            ws.make_insn(rva).unwrap();
            // TODO: consume result
            ws.analyze().unwrap();
        });
        Ok(())
    }
}
<|endoftext|>


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

use middle::ty::{BuiltinBounds};
use middle::ty::RegionVid;
use middle::ty;
use middle::typeck::infer::then;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::{TypeTrace, Subtype};
use collections::HashMap;
use syntax::ast::{Many, Once, NodeId};
use syntax::ast::{ExternFn, ImpureFn, UnsafeFn};
use syntax::ast::{Onceness, Purity};
use util::ppaux::mt_to_str;

pub struct Lub<'f>(CombineFields<'f>);  // least-upper-bound: common supertype

impl<'f> Lub<'f> {
    pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Lub(ref v) = *self; v }
    pub fn bot_ty(&self, b: ty::t) -> cres<ty::t> { Ok(b) }
    pub fn ty_bot(&self, b: ty::t) -> cres<ty::t> {
        self.bot_ty(b) // commutative
    }
}

impl<'f> Combine for Lub<'f> {
    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.get_ref().infcx }
    fn tag(&self) -> ~str { ~"lub" }
    fn a_is_expected(&self) -> bool { self.get_ref().a_is_expected }
    fn trace(&self) -> TypeTrace { self.get_ref().trace }

    fn sub<'a>(&'a self) -> Sub<'a> { Sub(*self.get_ref()) }
    fn lub<'a>(&'a self) -> Lub<'a> { Lub(*self.get_ref()) }
    fn glb<'a>(&'a self) -> Glb<'a> { Glb(*self.get_ref()) }

    fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
        let tcx = self.get_ref().infcx.tcx;

        debug!("{}.mts({}, {})",
               self.tag(),
               mt_to_str(tcx, a),
               mt_to_str(tcx, b));

        if a.mutbl != b.mutbl {
            return Err(ty::terr_mutability)
        }

        let m = a.mutbl;
        match m {
          MutImmutable => {
            self.tys(a.ty, b.ty).and_then(|t| Ok(ty::mt {ty: t, mutbl: m}) )
          }

          MutMutable => {
            self.get_ref().infcx.try(|| {
                eq_tys(self, a.ty, b.ty).then(|| {
                    Ok(ty::mt {ty: a.ty, mutbl: m})
                })
            }).or_else(|e| Err(e))
          }
        }
    }

    fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
        Glb(*self.get_ref()).tys(a, b)
    }

    fn purities(&self, a: Purity, b: Purity) -> cres<Purity> {
        match (a, b) {
          (UnsafeFn, _) | (_, UnsafeFn) => Ok(UnsafeFn),
          (ImpureFn, _) | (_, ImpureFn) => Ok(ImpureFn),
          (ExternFn, ExternFn) => Ok(ExternFn),
        }
    }

    fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
        match (a, b) {
            (Once, _) | (_, Once) => Ok(Once),
            (Many, Many) => Ok(Many)
        }
    }

    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
        // More bounds is a subtype of fewer bounds, so
        // the LUB (mutual supertype) is the intersection.
        Ok(a.intersection(b))
    }

    fn contraregions(&self, a: ty::Region, b: ty::Region)
                    -> cres<ty::Region> {
        return Glb(*self.get_ref()).regions(a, b);
    }

    fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
        debug!("{}.regions({:?}, {:?})",
               self.tag(),
               a.inf_str(self.get_ref().infcx),
               b.inf_str(self.get_ref().infcx));

        Ok(self.get_ref().infcx.region_vars.lub_regions(Subtype(self.get_ref().trace), a, b))
    }

    fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
        // Note: this is a subtle algorithm.  For a full explanation,
        // please see the large comment in `region_inference.rs`.

        // Take a snapshot.  We'll never roll this back, but in later
        // phases we do want to be able to examine "all bindings that
        // were created as part of this type comparison", and making a
        // snapshot is a convenient way to do that.
        let snapshot = self.get_ref().infcx.region_vars.start_snapshot();

        // Instantiate each bound region with a fresh region variable.
        let (a_with_fresh, a_map) =
            self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
                self.get_ref().trace, a);
        let (b_with_fresh, _) =
            self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
                self.get_ref().trace, b);

        // Collect constraints.
        let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
        debug!("sig0 = {}", sig0.inf_str(self.get_ref().infcx));

        // Generalize the regions appearing in sig0 if possible
        let new_vars =
            self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
        let sig1 =
            fold_regions_in_sig(
                self.get_ref().infcx.tcx,
                &sig0,
                |r| generalize_region(self, snapshot, new_vars.as_slice(),
                                      sig0.binder_id, &a_map, r));
        return Ok(sig1);

        fn generalize_region(this: &Lub,
                             snapshot: uint,
                             new_vars: &[RegionVid],
                             new_scope: NodeId,
                             a_map: &HashMap<ty::BoundRegion, ty::Region>,
                             r0: ty::Region)
                             -> ty::Region {
            // Regions that pre-dated the LUB computation stay as they are.
            if !is_var_in_set(new_vars, r0) {
                assert!(!r0.is_bound());
                debug!("generalize_region(r0={:?}): not new variable", r0);
                return r0;
            }

            let tainted = this.get_ref().infcx.region_vars.tainted(snapshot, r0);

            // Variables created during LUB computation which are
            // *related* to regions that pre-date the LUB computation
            // stay as they are.
            if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) {
                debug!("generalize_region(r0={:?}): \
                        non-new-variables found in {:?}",
                       r0, tainted);
                assert!(!r0.is_bound());
                return r0;
            }

            // Otherwise, the variable must be associated with at
            // least one of the variables representing bound regions
            // in both A and B.  Replace the variable with the "first"
            // bound region from A that we find it to be associated
            // with.
            for (a_br, a_r) in a_map.iter() {
                if tainted.iter().any(|x| x == a_r) {
                    debug!("generalize_region(r0={:?}): \
                            replacing with {:?}, tainted={:?}",
                           r0, *a_br, tainted);
                    return ty::ReLateBound(new_scope, *a_br);
                }
            }

            this.get_ref().infcx.tcx.sess.span_bug(
                this.get_ref().trace.origin.span(),
                format!("Region {:?} is not associated with \
                        any bound region from A!", r0))
        }
    }

    fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
        super_lattice_tys(self, a, b)
    }
}
<commit_msg>middle: typeck: infer: lub: remove dead code<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use middle::ty::{BuiltinBounds};
use middle::ty::RegionVid;
use middle::ty;
use middle::typeck::infer::then;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::{TypeTrace, Subtype};
use collections::HashMap;
use syntax::ast::{Many, Once, NodeId};
use syntax::ast::{ExternFn, ImpureFn, UnsafeFn};
use syntax::ast::{Onceness, Purity};
use util::ppaux::mt_to_str;

pub struct Lub<'f>(CombineFields<'f>);  // least-upper-bound: common supertype

impl<'f> Lub<'f> {
    pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Lub(ref v) = *self; v }
}

impl<'f> Combine for Lub<'f> {
    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.get_ref().infcx }
    fn tag(&self) -> ~str { ~"lub" }
    fn a_is_expected(&self) -> bool { self.get_ref().a_is_expected }
    fn trace(&self) -> TypeTrace { self.get_ref().trace }

    fn sub<'a>(&'a self) -> Sub<'a> { Sub(*self.get_ref()) }
    fn lub<'a>(&'a self) -> Lub<'a> { Lub(*self.get_ref()) }
    fn glb<'a>(&'a self) -> Glb<'a> { Glb(*self.get_ref()) }

    fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
        let tcx = self.get_ref().infcx.tcx;

        debug!("{}.mts({}, {})",
               self.tag(),
               mt_to_str(tcx, a),
               mt_to_str(tcx, b));

        if a.mutbl != b.mutbl {
            return Err(ty::terr_mutability)
        }

        let m = a.mutbl;
        match m {
          MutImmutable => {
            self.tys(a.ty, b.ty).and_then(|t| Ok(ty::mt {ty: t, mutbl: m}) )
          }

          MutMutable => {
            self.get_ref().infcx.try(|| {
                eq_tys(self, a.ty, b.ty).then(|| {
                    Ok(ty::mt {ty: a.ty, mutbl: m})
                })
            }).or_else(|e| Err(e))
          }
        }
    }

    fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
        Glb(*self.get_ref()).tys(a, b)
    }

    fn purities(&self, a: Purity, b: Purity) -> cres<Purity> {
        match (a, b) {
          (UnsafeFn, _) | (_, UnsafeFn) => Ok(UnsafeFn),
          (ImpureFn, _) | (_, ImpureFn) => Ok(ImpureFn),
          (ExternFn, ExternFn) => Ok(ExternFn),
        }
    }

    fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
        match (a, b) {
            (Once, _) | (_, Once) => Ok(Once),
            (Many, Many) => Ok(Many)
        }
    }

    fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
        // More bounds is a subtype of fewer bounds, so
        // the LUB (mutual supertype) is the intersection.
        Ok(a.intersection(b))
    }

    fn contraregions(&self, a: ty::Region, b: ty::Region)
                    -> cres<ty::Region> {
        return Glb(*self.get_ref()).regions(a, b);
    }

    fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
        debug!("{}.regions({:?}, {:?})",
               self.tag(),
               a.inf_str(self.get_ref().infcx),
               b.inf_str(self.get_ref().infcx));

        Ok(self.get_ref().infcx.region_vars.lub_regions(Subtype(self.get_ref().trace), a, b))
    }

    fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
        // Note: this is a subtle algorithm.  For a full explanation,
        // please see the large comment in `region_inference.rs`.

        // Take a snapshot.  We'll never roll this back, but in later
        // phases we do want to be able to examine "all bindings that
        // were created as part of this type comparison", and making a
        // snapshot is a convenient way to do that.
        let snapshot = self.get_ref().infcx.region_vars.start_snapshot();

        // Instantiate each bound region with a fresh region variable.
        let (a_with_fresh, a_map) =
            self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
                self.get_ref().trace, a);
        let (b_with_fresh, _) =
            self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
                self.get_ref().trace, b);

        // Collect constraints.
        let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
        debug!("sig0 = {}", sig0.inf_str(self.get_ref().infcx));

        // Generalize the regions appearing in sig0 if possible
        let new_vars =
            self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
        let sig1 =
            fold_regions_in_sig(
                self.get_ref().infcx.tcx,
                &sig0,
                |r| generalize_region(self, snapshot, new_vars.as_slice(),
                                      sig0.binder_id, &a_map, r));
        return Ok(sig1);

        fn generalize_region(this: &Lub,
                             snapshot: uint,
                             new_vars: &[RegionVid],
                             new_scope: NodeId,
                             a_map: &HashMap<ty::BoundRegion, ty::Region>,
                             r0: ty::Region)
                             -> ty::Region {
            // Regions that pre-dated the LUB computation stay as they are.
            if !is_var_in_set(new_vars, r0) {
                assert!(!r0.is_bound());
                debug!("generalize_region(r0={:?}): not new variable", r0);
                return r0;
            }

            let tainted = this.get_ref().infcx.region_vars.tainted(snapshot, r0);

            // Variables created during LUB computation which are
            // *related* to regions that pre-date the LUB computation
            // stay as they are.
            if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) {
                debug!("generalize_region(r0={:?}): \
                        non-new-variables found in {:?}",
                       r0, tainted);
                assert!(!r0.is_bound());
                return r0;
            }

            // Otherwise, the variable must be associated with at
            // least one of the variables representing bound regions
            // in both A and B.  Replace the variable with the "first"
            // bound region from A that we find it to be associated
            // with.
            for (a_br, a_r) in a_map.iter() {
                if tainted.iter().any(|x| x == a_r) {
                    debug!("generalize_region(r0={:?}): \
                            replacing with {:?}, tainted={:?}",
                           r0, *a_br, tainted);
                    return ty::ReLateBound(new_scope, *a_br);
                }
            }

            this.get_ref().infcx.tcx.sess.span_bug(
                this.get_ref().trace.origin.span(),
                format!("Region {:?} is not associated with \
                        any bound region from A!", r0))
        }
    }

    fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
        super_lattice_tys(self, a, b)
    }
}
<|endoftext|>


<commit_before>use std::collections::BitSet;
use std::cell::{RefCell, Ref, RefMut};

use value::{Id};
use relation::{Change, Relation};
use view::{View, Table};
use compiler;

#[derive(Clone, Debug)]
pub struct Node {
    pub id: Id,
    pub view: View,
    pub upstream: Vec<usize>,
    pub downstream: Vec<usize>,
}

pub type Changes = Vec<(Id, Change)>;

#[derive(Clone, Debug)]
pub struct Flow {
    pub nodes: Vec<Node>,
    pub outputs: Vec<RefCell<Relation>>,
    pub dirty: BitSet,
}

impl Flow {
    pub fn new() -> Self {
        let flow = Flow {
            nodes: Vec::new(),
            outputs: Vec::new(),
            dirty: BitSet::new(),
        };
        compiler::bootstrap(flow)
    }

    pub fn get_ix(&self, id: &str) -> Option<usize> {
        self.nodes.iter().position(|node| &node.id[..] == id)
    }

    pub fn get_output(&self, id: &str) -> Ref<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow()
    }

    pub fn get_output_mut(&self, id: &str) -> RefMut<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow_mut()
    }

    pub fn change(&mut self, changes: Changes) {
        for (id, changes) in changes.into_iter() {
            match self.get_ix(&*id) {
                Some(ix) => match self.nodes[ix].view {
                    View::Table(_) => {
                        // TODO should we be checking diffs after the fact?
                        self.outputs[ix].borrow_mut().change(changes);
                        for ix in self.nodes[ix].downstream.iter() {
                            self.dirty.insert(*ix);
                        }
                    }
                    _ => panic!("Tried to insert into a non-table view with id: {:?}", id),
                },
                None => panic!("Tried to insert into a non-existent view with id: {:?}", id),
            }
        }
    }

    pub fn as_changes(&self) -> Changes {
        (0..self.nodes.len()).map(|ix|
            (
                self.nodes[ix].id.clone(),
                self.outputs[ix].borrow().as_insert()
            )
        ).collect()
    }

    pub fn changes_from(&self, old_self: Self) -> Changes {
        let mut changes = Vec::new();
        for (ix, node) in self.nodes.iter().enumerate() {
            match old_self.get_ix(&node.id[..]) {
                Some(old_ix) => {
                    let new_output = self.outputs[ix].borrow();
                    let old_output = old_self.outputs[old_ix].borrow();
                    if new_output.fields == old_output.fields {
                        let change = new_output.change_from(&*old_output);
                        changes.push((node.id.clone(), change));
                    } else {
                        changes.push((node.id.clone(), new_output.as_insert()));
                        changes.push((node.id.clone(), old_output.as_remove()));
                    }
                }
                None => {
                    let new_output = self.outputs[ix].borrow();
                    changes.push((node.id.clone(), new_output.as_insert()));
                }
            }
        }
        for (old_ix, old_node) in old_self.nodes.iter().enumerate() {
            match self.get_ix(&old_node.id[..]) {
                Some(_) => {
                    () // already handled above
                }
                None => {
                    let old_output = old_self.outputs[old_ix].borrow();
                    changes.push((old_node.id.clone(), old_output.as_remove()));
                }
            }
        }
        changes
    }

    pub fn recalculate(&mut self) {
        let Flow{ref nodes, ref mut outputs, ref mut dirty, ..} = *self;
        while let Some(ix) = dirty.iter().next() {
            dirty.remove(&ix);
            let node = &nodes[ix];
            let new_output = {
                let upstream = node.upstream.iter().map(|&ix| outputs[ix].borrow()).collect::<Vec<_>>();
                let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                node.view.run(&*outputs[ix].borrow(), &inputs[..])
            };
            match new_output {
                None => (), // view does not want to update
                Some(new_output) => {
                    let change = new_output.change_from(&*outputs[ix].borrow());
                    if (change.insert.len() != 0) || (change.remove.len() != 0) {
                        for ix in node.downstream.iter() {
                            dirty.insert(*ix);
                        }
                    }
                    outputs[ix] = RefCell::new(new_output);
                }
            }
        }
    }

    pub fn tick(&mut self) -> bool {
        let mut changed = false;
        for (ix, node) in self.nodes.iter().enumerate() {
            match node.view {
                View::Table(Table{ref insert, ref remove}) => {
                    let upstream = node.upstream.iter().map(|ix| self.outputs[*ix].borrow()).collect::<Vec<_>>();
                    let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                    let mut inserts = match *insert {
                        Some(ref select) => select.select(&inputs[..]),
                        None => vec![],
                    };
                    let mut removes = match *remove {
                        Some(ref select) => select.select(&inputs[..]),
                        None => vec![],
                    };
                    inserts.sort();
                    removes.sort();
                    inserts.retain(|insert| removes.binary_search(&insert).is_err());
                    removes.retain(|remove| inserts.binary_search(&remove).is_err());
                    let mut output = self.outputs[ix].borrow_mut();
                    let mut index = &mut output.index;
                    for insert in inserts {
                        changed = changed || index.insert(insert);
                    }
                    for remove in removes {
                        changed = changed || !index.remove(&remove);
                    }
                }
                _ => () // only tables tick
            }
        }
        changed
    }

    pub fn quiesce(mut self, changes: Changes) -> Self {
        time!("changing", {
            self.change(changes);
        });
        loop {
            // TODO if compiler::needs_recompile...

            time!("compiling", {
                self = compiler::recompile(self);
            });
            time!("calculating", {
                self.recalculate();
            });
            let changed = self.tick();
            if !changed {
                break
            }
        }
        self
    }
}
<commit_msg>Send removes before inserts<commit_after>use std::collections::BitSet;
use std::cell::{RefCell, Ref, RefMut};

use value::{Id};
use relation::{Change, Relation};
use view::{View, Table};
use compiler;

#[derive(Clone, Debug)]
pub struct Node {
    pub id: Id,
    pub view: View,
    pub upstream: Vec<usize>,
    pub downstream: Vec<usize>,
}

pub type Changes = Vec<(Id, Change)>;

#[derive(Clone, Debug)]
pub struct Flow {
    pub nodes: Vec<Node>,
    pub outputs: Vec<RefCell<Relation>>,
    pub dirty: BitSet,
}

impl Flow {
    pub fn new() -> Self {
        let flow = Flow {
            nodes: Vec::new(),
            outputs: Vec::new(),
            dirty: BitSet::new(),
        };
        compiler::bootstrap(flow)
    }

    pub fn get_ix(&self, id: &str) -> Option<usize> {
        self.nodes.iter().position(|node| &node.id[..] == id)
    }

    pub fn get_output(&self, id: &str) -> Ref<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow()
    }

    pub fn get_output_mut(&self, id: &str) -> RefMut<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow_mut()
    }

    pub fn change(&mut self, changes: Changes) {
        for (id, changes) in changes.into_iter() {
            match self.get_ix(&*id) {
                Some(ix) => match self.nodes[ix].view {
                    View::Table(_) => {
                        // TODO should we be checking diffs after the fact?
                        self.outputs[ix].borrow_mut().change(changes);
                        for ix in self.nodes[ix].downstream.iter() {
                            self.dirty.insert(*ix);
                        }
                    }
                    _ => panic!("Tried to insert into a non-table view with id: {:?}", id),
                },
                None => panic!("Tried to insert into a non-existent view with id: {:?}", id),
            }
        }
    }

    pub fn as_changes(&self) -> Changes {
        (0..self.nodes.len()).map(|ix|
            (
                self.nodes[ix].id.clone(),
                self.outputs[ix].borrow().as_insert()
            )
        ).collect()
    }

    pub fn changes_from(&self, old_self: Self) -> Changes {
        let mut changes = Vec::new();
        for (ix, node) in self.nodes.iter().enumerate() {
            match old_self.get_ix(&node.id[..]) {
                Some(old_ix) => {
                    let new_output = self.outputs[ix].borrow();
                    let old_output = old_self.outputs[old_ix].borrow();
                    if new_output.fields == old_output.fields {
                        let change = new_output.change_from(&*old_output);
                        changes.push((node.id.clone(), change));
                    } else {
                        changes.push((node.id.clone(), old_output.as_remove()));
                        changes.push((node.id.clone(), new_output.as_insert()));
                    }
                }
                None => {
                    let new_output = self.outputs[ix].borrow();
                    changes.push((node.id.clone(), new_output.as_insert()));
                }
            }
        }
        for (old_ix, old_node) in old_self.nodes.iter().enumerate() {
            match self.get_ix(&old_node.id[..]) {
                Some(_) => {
                    () // already handled above
                }
                None => {
                    let old_output = old_self.outputs[old_ix].borrow();
                    changes.push((old_node.id.clone(), old_output.as_remove()));
                }
            }
        }
        changes
    }

    pub fn recalculate(&mut self) {
        let Flow{ref nodes, ref mut outputs, ref mut dirty, ..} = *self;
        while let Some(ix) = dirty.iter().next() {
            dirty.remove(&ix);
            let node = &nodes[ix];
            let new_output = {
                let upstream = node.upstream.iter().map(|&ix| outputs[ix].borrow()).collect::<Vec<_>>();
                let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                node.view.run(&*outputs[ix].borrow(), &inputs[..])
            };
            match new_output {
                None => (), // view does not want to update
                Some(new_output) => {
                    let change = new_output.change_from(&*outputs[ix].borrow());
                    if (change.insert.len() != 0) || (change.remove.len() != 0) {
                        for ix in node.downstream.iter() {
                            dirty.insert(*ix);
                        }
                    }
                    outputs[ix] = RefCell::new(new_output);
                }
            }
        }
    }

    pub fn tick(&mut self) -> bool {
        let mut changed = false;
        for (ix, node) in self.nodes.iter().enumerate() {
            match node.view {
                View::Table(Table{ref insert, ref remove}) => {
                    let upstream = node.upstream.iter().map(|ix| self.outputs[*ix].borrow()).collect::<Vec<_>>();
                    let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                    let mut inserts = match *insert {
                        Some(ref select) => select.select(&inputs[..]),
                        None => vec![],
                    };
                    let mut removes = match *remove {
                        Some(ref select) => select.select(&inputs[..]),
                        None => vec![],
                    };
                    inserts.sort();
                    removes.sort();
                    inserts.retain(|insert| removes.binary_search(&insert).is_err());
                    removes.retain(|remove| inserts.binary_search(&remove).is_err());
                    let mut output = self.outputs[ix].borrow_mut();
                    let mut index = &mut output.index;
                    for insert in inserts {
                        changed = changed || index.insert(insert);
                    }
                    for remove in removes {
                        changed = changed || !index.remove(&remove);
                    }
                }
                _ => () // only tables tick
            }
        }
        changed
    }

    pub fn quiesce(mut self, changes: Changes) -> Self {
        time!("changing", {
            self.change(changes);
        });
        loop {
            // TODO if compiler::needs_recompile...

            time!("compiling", {
                self = compiler::recompile(self);
            });
            time!("calculating", {
                self.recalculate();
            });
            let changed = self.tick();
            if !changed {
                break
            }
        }
        self
    }
}
<|endoftext|>


<commit_before>macro_rules! replace(
    ($name:ident, $which:ident, $re:expr,
     $search:expr, $replace:expr, $result:expr) => (
        #[test]
        fn $name() {
            let re = regex!($re);
            assert_eq!(re.$which(text!($search), $replace), text!($result));
        }
    );
);

replace!(first, replace, r"\d", "age: 26", t!("Z"), "age: Z6");
replace!(plus, replace, r"\d+", "age: 26", t!("Z"), "age: Z");
replace!(all, replace_all, r"\d", "age: 26", t!("Z"), "age: ZZ");
replace!(groups, replace, r"(\S+)\s+(\S+)", "w1 w2", t!("$2 $1"), "w2 w1");
replace!(double_dollar, replace,
         r"(\S+)\s+(\S+)", "w1 w2", t!("$2 $$1"), "w2 $1");
// replace!(adjacent_index, replace,
         // r"([^aeiouy])ies$", "skies", t!("$1y"), "sky");
replace!(named, replace_all,
         r"(?P<first>\S+)\s+(?P<last>\S+)(?P<space>\s*)",
         "w1 w2 w3 w4", t!("$last $first$space"), "w2 w1 w4 w3");
replace!(trim, replace_all, "^[ \t]+|[ \t]+$", " \t  trim me\t   \t",
         t!(""), "trim me");
replace!(number_hypen, replace, r"(.)(.)", "ab", t!("$1-$2"), "a-b");
// replace!(number_underscore, replace, r"(.)(.)", "ab", t!("$1_$2"), "a_b");
replace!(simple_expand, replace_all, r"(\w) (\w)", "a b", t!("$2 $1"), "b a");
replace!(literal_dollar1, replace_all,
         r"(\w+) (\w+)", "a b", t!("$$1"), "$1");
replace!(literal_dollar2, replace_all,
         r"(\w+) (\w+)", "a b", t!("$2 $$c $1"), "b $c a");
replace!(no_expand1, replace,
         r"(\S+)\s+(\S+)", "w1 w2", no_expand!("$2 $1"), "$2 $1");
replace!(no_expand2, replace,
         r"(\S+)\s+(\S+)", "w1 w2", no_expand!("$$1"), "$$1");
use_!(Captures);
replace!(closure_returning_reference, replace, r"(\d+)", "age: 26",
         | captures: &Captures | &match_text!(captures.get(1).unwrap())[0..1], "age: 2");
replace!(closure_returning_value, replace, r"\d+", "age: 26",
         | _captures: &Captures | t!("Z").to_owned(), "age: Z");

// See https://github.com/rust-lang/regex/issues/314
replace!(match_at_start_replace_with_empty, replace_all, r"foo", "foobar", t!(""), "bar");

// See https://github.com/rust-lang/regex/issues/393
replace!(single_empty_match, replace, r"^", "bar", t!("foo"), "foobar");

// See https://github.com/rust-lang/regex/issues/399
replace!(capture_longest_possible_name, replace_all, r"(.)", "b", t!("${1}a $1a"), "ba ");
<commit_msg>tests: fix lifetime warning<commit_after>macro_rules! replace(
    ($name:ident, $which:ident, $re:expr,
     $search:expr, $replace:expr, $result:expr) => (
        #[test]
        fn $name() {
            let re = regex!($re);
            assert_eq!(re.$which(text!($search), $replace), text!($result));
        }
    );
);

replace!(first, replace, r"\d", "age: 26", t!("Z"), "age: Z6");
replace!(plus, replace, r"\d+", "age: 26", t!("Z"), "age: Z");
replace!(all, replace_all, r"\d", "age: 26", t!("Z"), "age: ZZ");
replace!(groups, replace, r"(\S+)\s+(\S+)", "w1 w2", t!("$2 $1"), "w2 w1");
replace!(double_dollar, replace,
         r"(\S+)\s+(\S+)", "w1 w2", t!("$2 $$1"), "w2 $1");
// replace!(adjacent_index, replace,
         // r"([^aeiouy])ies$", "skies", t!("$1y"), "sky");
replace!(named, replace_all,
         r"(?P<first>\S+)\s+(?P<last>\S+)(?P<space>\s*)",
         "w1 w2 w3 w4", t!("$last $first$space"), "w2 w1 w4 w3");
replace!(trim, replace_all, "^[ \t]+|[ \t]+$", " \t  trim me\t   \t",
         t!(""), "trim me");
replace!(number_hypen, replace, r"(.)(.)", "ab", t!("$1-$2"), "a-b");
// replace!(number_underscore, replace, r"(.)(.)", "ab", t!("$1_$2"), "a_b");
replace!(simple_expand, replace_all, r"(\w) (\w)", "a b", t!("$2 $1"), "b a");
replace!(literal_dollar1, replace_all,
         r"(\w+) (\w+)", "a b", t!("$$1"), "$1");
replace!(literal_dollar2, replace_all,
         r"(\w+) (\w+)", "a b", t!("$2 $$c $1"), "b $c a");
replace!(no_expand1, replace,
         r"(\S+)\s+(\S+)", "w1 w2", no_expand!("$2 $1"), "$2 $1");
replace!(no_expand2, replace,
         r"(\S+)\s+(\S+)", "w1 w2", no_expand!("$$1"), "$$1");
use_!(Captures);
replace!(closure_returning_reference, replace, r"(\d+)", "age: 26",
         |captures: &Captures| {
             match_text!(captures.get(1).unwrap())[0..1].to_owned()
         }, "age: 2");
replace!(closure_returning_value, replace, r"\d+", "age: 26",
         |_captures: &Captures| t!("Z").to_owned(), "age: Z");

// See https://github.com/rust-lang/regex/issues/314
replace!(match_at_start_replace_with_empty, replace_all, r"foo", "foobar", t!(""), "bar");

// See https://github.com/rust-lang/regex/issues/393
replace!(single_empty_match, replace, r"^", "bar", t!("foo"), "foobar");

// See https://github.com/rust-lang/regex/issues/399
replace!(capture_longest_possible_name, replace_all, r"(.)", "b", t!("${1}a $1a"), "ba ");
<|endoftext|>


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

//! Targets on which your draw commands are executed.
//!
//! # Render passes and framebuffers
//!
//! There are two concepts in Vulkan:
//!
//! - A *render pass* describes the target which you are going to render to. It is a collection
//!   of descriptions of one or more attachments (ie. image that are rendered to), and of one or
//!   multiples subpasses. The render pass contains the format and number of samples of each
//!   attachment, and the attachments that are attached to each subpass. They are represented
//!   in vulkano with the `RenderPass` object.
//! - A *framebuffer* contains the list of actual images that are attached. It is created from a
//!   render pass and has to match its characteristics. They are represented in vulkano with the
//!   `Framebuffer` object.
//!
//! Render passes are typically created at initialization only (for example during a loading
//! screen) because they can be costly, while framebuffers can be created and destroyed either at
//! initialization or during the frame.
//!
//! Consequently you can create graphics pipelines from a render pass object alone.
//! A `Framebuffer` object is only needed when you actually add draw commands to a command buffer.
//!
//! # Render passes
//!
//! In vulkano, a render pass is represented by the `RenderPass` struct. The `RenderPassAbstract` trait
//! also exists and is implemented on objects that hold a render pass (eg. `Arc<RenderPass<...>>`).
//!
//! The `RenderPass` struct has a template parameter that contains the description of the render
//! pass and which must implement the `RenderPassDesc` trait. In order to create a render pass, you
//! must first create an object that implements the `RenderPassDesc` trait, then call the
//! `build_render_pass` method of that trait. Example:
//!
//! ```
//! use vulkano::framebuffer::EmptySinglePassRenderPassDesc;
//! use vulkano::framebuffer::RenderPassDesc;
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! let desc = EmptySinglePassRenderPassDesc;
//! let render_pass = desc.build_render_pass(device.clone()).unwrap();
//! // The type of `render_pass` is `RenderPass<EmptySinglePassRenderPassDesc>`.
//! ```
//!
//! This example creates a render pass with no attachment and one single subpass that doesn't draw
//! on anything. While it's sometimes useful, most of the time it's not what you want.
//!
//! The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro.
//! Example:
//!
//! ```
//! # #[macro_use] extern crate vulkano;
//! # fn main() {
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! use vulkano::format::Format;
//!
//! let render_pass = single_pass_renderpass!(device.clone(),
//!     attachments: {
//!         // `foo` is a custom name we give to the first and only attachment.
//!         foo: {
//!             load: Clear,
//!             store: Store,
//!             format: Format::R8G8B8A8Unorm,
//!             samples: 1,
//!         }
//!     },
//!     pass: {
//!         color: [foo],       // Repeat the attachment name here.
//!         depth_stencil: {}
//!     }
//! ).unwrap();
//! # }
//! ```
//!
//! See the documentation of the macro for more details. TODO: put link here
//!
//! # Framebuffers
//!
//! Creating a framebuffer is done by passing the render pass object, the dimensions of the
//! framebuffer, and the list of attachments to `Framebuffer::new()`.
//!
//! One tricky part is that the type that contains the list of attachments depends on the
//! render pass description you're using (ie. the template parameter of the `RenderPass` object).
//! For example if you use an `EmptySinglePassRenderPass`, you have to pass `()` for the list of
//! attachments.
//!
//! When it comes to `single_pass_renderpass!` and `ordered_passes_renderpass!` you can build a
//! list of attachments by calling `start_attachment()`, which will return an object that has a
//! method whose name is the name of the first attachment and that can be used to specify it. This
//! method will return another object that has a method whose name is the name of the second
//! attachment, and so on. See the documentation of the macro for more details. TODO: put link here
//!
//! ## Example
//!
//! TODO

pub use self::attachments_list::AttachmentsList;
pub use self::desc::LayoutAttachmentDescription;
pub use self::desc::LayoutPassDescription;
pub use self::desc::LayoutPassDependencyDescription;
pub use self::desc::RenderPassDesc;
pub use self::desc::RenderPassDescAttachments;
pub use self::desc::RenderPassDescSubpasses;
pub use self::desc::RenderPassDescDependencies;
pub use self::desc::StoreOp;
pub use self::desc::LoadOp;
pub use self::empty::EmptySinglePassRenderPassDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferCreationError;
pub use self::framebuffer::FramebufferSys;
pub use self::sys::RenderPass;
pub use self::sys::RenderPassCreationError;
pub use self::sys::RenderPassSys;
pub use self::traits::FramebufferAbstract;
pub use self::traits::RenderPassDescClearValues;
pub use self::traits::RenderPassCompatible;
pub use self::traits::RenderPassDescAttachmentsList;
pub use self::traits::RenderPassAbstract;
pub use self::traits::RenderPassSubpassInterface;
pub use self::traits::Subpass;

#[macro_use]
mod macros;
mod attachments_list;
mod desc;
mod empty;
mod framebuffer;
mod sys;
mod traits;
<commit_msg>More documentation for framebuffers<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Targets on which your draw commands are executed.
//!
//! # Render passes and framebuffers
//!
//! There are two concepts in Vulkan:
//!
//! - A *render pass* describes the target which you are going to render to. It is a collection
//!   of descriptions of one or more attachments (ie. image that are rendered to), and of one or
//!   multiples subpasses. The render pass contains the format and number of samples of each
//!   attachment, and the attachments that are attached to each subpass. They are represented
//!   in vulkano with the `RenderPass` object.
//! - A *framebuffer* contains the list of actual images that are attached. It is created from a
//!   render pass and has to match its characteristics. They are represented in vulkano with the
//!   `Framebuffer` object.
//!
//! Render passes are typically created at initialization only (for example during a loading
//! screen) because they can be costly, while framebuffers can be created and destroyed either at
//! initialization or during the frame.
//!
//! Consequently you can create graphics pipelines from a render pass object alone.
//! A `Framebuffer` object is only needed when you actually add draw commands to a command buffer.
//!
//! # Render passes
//!
//! In vulkano a render pass is represented by the `RenderPass` struct. This struct has a template
//! parameter that contains the description of the render pass. The `RenderPassAbstract` trait is
//! implemented on all instances of `RenderPass<_>` and makes it easier to store render passes
//! without having to explicitely write its type.
//!
//! The template parameter of the `RenderPass` struct must implement the `RenderPassDesc` trait.
//! In order to create a render pass, you can create an object that implements this trait, then
//! call the `build_render_pass` method on it.
//!
//! ```
//! use vulkano::framebuffer::EmptySinglePassRenderPassDesc;
//! use vulkano::framebuffer::RenderPassDesc;
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! let desc = EmptySinglePassRenderPassDesc;
//! let render_pass = desc.build_render_pass(device.clone()).unwrap();
//! // The type of `render_pass` is `RenderPass<EmptySinglePassRenderPassDesc>`.
//! ```
//!
//! This example creates a render pass with no attachment and one single subpass that doesn't draw
//! on anything. While it's sometimes useful, most of the time it's not what you want.
//!
//! The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro.
//!
//! ```
//! # #[macro_use] extern crate vulkano;
//! # fn main() {
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! use vulkano::format::Format;
//!
//! let render_pass = single_pass_renderpass!(device.clone(),
//!     attachments: {
//!         // `foo` is a custom name we give to the first and only attachment.
//!         foo: {
//!             load: Clear,
//!             store: Store,
//!             format: Format::R8G8B8A8Unorm,
//!             samples: 1,
//!         }
//!     },
//!     pass: {
//!         color: [foo],       // Repeat the attachment name here.
//!         depth_stencil: {}
//!     }
//! ).unwrap();
//! # }
//! ```
//!
//! See the documentation of the macro for more details. TODO: put link here
//!
//! Once a `RenderPass<_>` struct is created, it implements the same render-pass-related traits as
//! its template parameter.
//!
//! # Framebuffers
//!
//! Creating a framebuffer is done by passing the render pass object, the dimensions of the
//! framebuffer, and the list of attachments to `Framebuffer::new()`.
//!
//! Just like all render pass objects implement the `RenderPassAbstract` trait, all framebuffer
//! objects implement the `FramebufferAbstract` trait. This means that you can cast any
//! `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract>` for easier storage.
//!
//! ## With a generic list of attachments
//!
//! The list of attachments passed to `Framebuffer::new()` can be of various types, but one of the
//! possibilities is to pass an object of type `Vec<Arc<ImageView>>`.
//!
//! > **Note**: If you access a render pass object through the `RenderPassAbstract` trait, passing
//! > a `Vec<Arc<ImageView>>` is the only possible method.
//!
//! The framebuffer constructor will perform various checks to make sure that the number of images
//! is correct and that each image can be used with this render pass.
//!
//! ```
//! # use std::sync::Arc;
//! # use vulkano::framebuffer::RenderPassAbstract;
//! use vulkano::framebuffer::Framebuffer;
//!
//! # let render_pass: Arc<RenderPassAbstract> = return;
//! # let my_image: Arc<vulkano::image::ImageView> = return;
//! // let render_pass: Arc<RenderPassAbstract> = ...;
//! let framebuffer = Framebuffer::new(render_pass.clone(), [1024, 768, 1],
//!                                    vec![my_image.clone() as Arc<_>]).unwrap();
//! ```
//!
//! ## With a specialized list of attachments
//!
//! The list of attachments can also be of any type `T`, as long as the render pass description
//! implements the trait `RenderPassDescAttachmentsList<T>`.
//!
//! For example if you pass a render pass object that implements
//! `RenderPassDescAttachmentsList<Foo>`, then you can pass a `Foo` as the list of attachments.
//!
//! > **Note**: The reason why `Vec<Arc<ImageView>>` always works (see previous section) is that
//! > render pass descriptions are required to always implement
//! > `RenderPassDescAttachmentsList<Vec<Arc<ImageView>>>`.
//!
//! When it comes to the `single_pass_renderpass!` and `ordered_passes_renderpass!` macros, you can
//! build a list of attachments by calling `start_attachments()` on the render pass description,
//! which will return an object that has a method whose name is the name of the first attachment
//! and that can be used to specify it. This method will return another object that has a method
//! whose name is the name of the second attachment, and so on. See the documentation of the macros
//! for more details. TODO: put link here
//!
//! ```
//! # #[macro_use] extern crate vulkano;
//! # fn main() {
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! use std::sync::Arc;
//! use vulkano::format::Format;
//! use vulkano::framebuffer::Framebuffer;
//!
//! let render_pass = single_pass_renderpass!(device.clone(),
//!     attachments: {
//!         // `foo` is a custom name we give to the first and only attachment.
//!         foo: {
//!             load: Clear,
//!             store: Store,
//!             format: Format::R8G8B8A8Unorm,
//!             samples: 1,
//!         }
//!     },
//!     pass: {
//!         color: [foo],       // Repeat the attachment name here.
//!         depth_stencil: {}
//!     }
//! ).unwrap();
//!
//! # let my_image: Arc<vulkano::image::ImageView> = return;
//! let framebuffer = {
//!     let atch = render_pass.desc().start_attachments().foo(my_image.clone() as Arc<_>);
//!     Framebuffer::new(render_pass, [1024, 768, 1], atch).unwrap()
//! };
//! # }
//! ```

pub use self::attachments_list::AttachmentsList;
pub use self::desc::LayoutAttachmentDescription;
pub use self::desc::LayoutPassDescription;
pub use self::desc::LayoutPassDependencyDescription;
pub use self::desc::RenderPassDesc;
pub use self::desc::RenderPassDescAttachments;
pub use self::desc::RenderPassDescSubpasses;
pub use self::desc::RenderPassDescDependencies;
pub use self::desc::StoreOp;
pub use self::desc::LoadOp;
pub use self::empty::EmptySinglePassRenderPassDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferCreationError;
pub use self::framebuffer::FramebufferSys;
pub use self::sys::RenderPass;
pub use self::sys::RenderPassCreationError;
pub use self::sys::RenderPassSys;
pub use self::traits::FramebufferAbstract;
pub use self::traits::RenderPassDescClearValues;
pub use self::traits::RenderPassCompatible;
pub use self::traits::RenderPassDescAttachmentsList;
pub use self::traits::RenderPassAbstract;
pub use self::traits::RenderPassSubpassInterface;
pub use self::traits::Subpass;

#[macro_use]
mod macros;
mod attachments_list;
mod desc;
mod empty;
mod framebuffer;
mod sys;
mod traits;
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
#![deny(nonminimal_bool, logic_bug)]

#[allow(unused, many_single_char_names)]
fn main() {
    let a: bool = unimplemented!();
    let b: bool = unimplemented!();
    let c: bool = unimplemented!();
    let d: bool = unimplemented!();
    let e: bool = unimplemented!();
    let _ = a && b || a; //~ ERROR this boolean expression contains a logic bug
    //|~ HELP for further information visit
    //|~ HELP this expression can be optimized out
    //|~ HELP it would look like the following
    //|~ SUGGESTION let _ = a;
    let _ = !(a && b);
    let _ = !true; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = false;
    let _ = !false; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = true;
    let _ = !!a; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = a;

    let _ = false && a; //~ ERROR this boolean expression contains a logic bug
    //|~ HELP for further information visit
    //|~ HELP this expression can be optimized out
    //|~ HELP it would look like the following
    //|~ SUGGESTION let _ = false;

    let _ = false || a; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = a;

    // don't lint on cfgs
    let _ = cfg!(you_shall_not_not_pass) && a;

    let _ = a || !b || !c || !d || !e;

    let _ = !(a && b || c);

    let _ = !(!a && b); //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = !b || a;
}
<commit_msg>add tests showing the current level of minimization with ==<commit_after>#![feature(plugin)]
#![plugin(clippy)]
#![deny(nonminimal_bool, logic_bug)]

#[allow(unused, many_single_char_names)]
fn main() {
    let a: bool = unimplemented!();
    let b: bool = unimplemented!();
    let c: bool = unimplemented!();
    let d: bool = unimplemented!();
    let e: bool = unimplemented!();
    let _ = a && b || a; //~ ERROR this boolean expression contains a logic bug
    //|~ HELP for further information visit
    //|~ HELP this expression can be optimized out
    //|~ HELP it would look like the following
    //|~ SUGGESTION let _ = a;
    let _ = !(a && b);
    let _ = !true; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = false;
    let _ = !false; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = true;
    let _ = !!a; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = a;

    let _ = false && a; //~ ERROR this boolean expression contains a logic bug
    //|~ HELP for further information visit
    //|~ HELP this expression can be optimized out
    //|~ HELP it would look like the following
    //|~ SUGGESTION let _ = false;

    let _ = false || a; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = a;

    // don't lint on cfgs
    let _ = cfg!(you_shall_not_not_pass) && a;

    let _ = a || !b || !c || !d || !e;

    let _ = !(a && b || c);

    let _ = !(!a && b); //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = !b || a;
}

#[allow(unused, many_single_char_names)]
fn equality_stuff() {
    let a: i32 = unimplemented!();
    let b: i32 = unimplemented!();
    let c: i32 = unimplemented!();
    let d: i32 = unimplemented!();
    let e: i32 = unimplemented!();
    let _ = a == b && a != b;
    let _ = a == b && c == 5 && a == b; //~ ERROR this boolean expression can be simplified
    //|~ HELP for further information visit
    //|~ SUGGESTION let _ = c == 5 && a == b;
    let _ = a < b && a >= b;
    let _ = a > b && a <= b;
    let _ = a > b && a == b;
}
<|endoftext|>


<commit_before>/// Divide a string into the longest slice that fits within maximum line
/// length and the rest of the string. Place the split before a whitespace or
/// after a hyphen if possible. Any whitespace between the two segments is
/// trimmed. Newlines will cause a segment split when encountered.
pub fn split_line<'a, F>(text: &'a str, char_width: &F, max_len: f32) -> (&'a str, &'a str)
    where F: Fn(char) -> f32 {
    assert!(max_len >= 0.0);

    if text.len() == 0 { return (text, text); }

    // Init the split position to 1 because we always want to return at least
    // 1 character in the head partition.
    let mut head_end = 1;
    let mut tail_start = 1;
    // Is the iteration currently consuming whitespace inside a possible
    // break.
    let mut eat_whitespace = false;
    let mut length = 0.0;

    for (i, c) in text.chars().enumerate() {
        length = length + char_width(c);

        // Invariant: head_end and tail_start describe a valid, but possibly
        // suboptimal return value at this point.
        if eat_whitespace {
            if c.is_whitespace() {
                tail_start = i + 1;
                if c == '\n' { return (&text[..head_end], &text[tail_start..]); }
                continue;
            } else {
                eat_whitespace = false;
            }
        }

        // We're either just encountering the first whitespace after a block
        // of text, or over non-whitespace text.
        assert!(!eat_whitespace);

        // Invariant: The length of the string processed up to this point is
        // still short enough to return.

        // Encounter the first whitespace, set head_end marker.
        if c.is_whitespace() {
            head_end = i;
            tail_start = i + 1;
            if c == '\n' { return (&text[..head_end], &text[tail_start..]); }
            eat_whitespace = true;
            continue;
        }

        assert!(!c.is_whitespace());

        // Went over the allowed length.
        if length > max_len {
            if i > 1 && head_end == 1 && tail_start == 1 {
                // Didn't encounter any better cut points, so just place cut
                // in the middle of the word where we're at.
                head_end = i;
                tail_start = i;
            }

            // Use the last good result.
            return (&text[..head_end], &text[tail_start..]);
        }

        // Hyphens are a possible cut point.
        if c == '-' {
            head_end = i;
            tail_start = i;
        }
    }

    (&text, &""[..])
}

pub fn wrap_lines<F>(mut text: &str, char_width: &F, max_len: f32) -> String
    where F: Fn(char) -> f32 {
    let mut result = String::new();
    loop {
        let (head, tail) = split_line(text, char_width, max_len);
        if head.len() == 0 && tail.len() == 0 { break; }
        result = result + head;
        if tail.len() != 0 { result = result + "\n"; }
        text = tail;
    }
    result
}

pub struct Map2DIterator<T> {
    /// Input iterator
    iter: T,
    x: i32,
    y: i32,
}

impl<T: Iterator<Item=char>> Iterator for Map2DIterator<T> {
    type Item = (char, i32, i32);

    fn next(&mut self) -> Option<(char, i32, i32)> {
        loop {
            match self.iter.next() {
                None => { return None }
                Some(c) if c == '\n' => { self.y += 1; self.x = 0; }
                Some(c) if (c as u32) < 32 => { }
                Some(c) => { self.x += 1; return Some((c, self.x - 1, self.y)) }
            }
        }
    }
}

pub trait Map2DUtil {
    fn map2d(self) -> Map2DIterator<Self>;
}

impl<T: Iterator<Item=char>> Map2DUtil for T {
    fn map2d(self) -> Map2DIterator<T> {
        Map2DIterator{ iter: self, x: 0, y: 0 }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_split_line() {
        use super::split_line;

        assert_eq!(("", ""), split_line("", &|_| 1.0, 12.0));
        assert_eq!(("a", ""), split_line("a", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the cat", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the     cat", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the  \t cat", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the \ncat", &|_| 1.0, 32.0));
        assert_eq!(("the", "   cat"), split_line("the \n   cat", &|_| 1.0, 32.0));
        assert_eq!(("the  cat", ""), split_line("the  cat", &|_| 1.0, 32.0));
        assert_eq!(("the", "cat sat"), split_line("the cat sat", &|_| 1.0, 6.0));
        assert_eq!(("the cat", "sat"), split_line("the cat sat", &|_| 1.0, 7.0));
        assert_eq!(("a", "bc"), split_line("abc", &|_| 1.0, 0.01));
        assert_eq!(("dead", "beef"), split_line("deadbeef", &|_| 1.0, 4.0));
    }
}
<commit_msg>String splitter invariants and bugfixes<commit_after>/// Divide a string into the longest slice that fits within maximum line
/// length and the rest of the string. Place the split before a whitespace or
/// after a hyphen if possible. Any whitespace between the two segments is
/// trimmed. Newlines will cause a segment split when encountered.
pub fn split_line<'a, F>(text: &'a str, char_width: &F, max_len: f32) -> (&'a str, &'a str)
    where F: Fn(char) -> f32 {
    assert!(max_len >= 0.0);

    if text.len() == 0 { return (text, text); }

    // Init the split position to 1 because we always want to return at least
    // 1 character in the head partition.
    let mut head_end = 1;
    let mut tail_start = 1;
    // Is the iteration currently consuming whitespace inside a possible
    // break.
    let mut eat_whitespace = false;
    let mut length = 0.0;

    for (i, c) in text.chars().enumerate() {
        length = length + char_width(c);

        // Invariant: head_end and tail_start describe a valid, but possibly
        // suboptimal return value at this point.
        assert!(text[..head_end].len() > 0);
        assert!(head_end <= tail_start);

        if eat_whitespace {
            if c.is_whitespace() {
                tail_start = i + 1;
                if c == '\n' { return (&text[..head_end], &text[tail_start..]); }
                continue;
            } else {
                eat_whitespace = false;
            }
        }

        // We're either just encountering the first whitespace after a block
        // of text, or over non-whitespace text.
        assert!(!eat_whitespace);

        // Invariant: The length of the string processed up to this point is
        // still short enough to return.

        // Encounter the first whitespace, set head_end marker.
        if c.is_whitespace() {
            head_end = i;
            tail_start = i + 1;
            if c == '\n' { return (&text[..head_end], &text[tail_start..]); }
            eat_whitespace = true;
            continue;
        }

        assert!(!c.is_whitespace());

        // Went over the allowed length.
        if length > max_len {
            if i > 1 && head_end == 1 && tail_start == 1 {
                // Didn't encounter any better cut points, so just place cut
                // in the middle of the word where we're at.
                head_end = i;
                tail_start = i;
            }

            // Use the last good result.
            return (&text[..head_end], &text[tail_start..]);
        }

        // Hyphens are a possible cut point.
        if c == '-' {
            head_end = i + 1;
            tail_start = i + 1;
        }
    }

    (&text, &""[..])
}

pub fn wrap_lines<F>(mut text: &str, char_width: &F, max_len: f32) -> String
    where F: Fn(char) -> f32 {
    let mut result = String::new();
    loop {
        let (head, tail) = split_line(text, char_width, max_len);
        if head.len() == 0 && tail.len() == 0 { break; }
        assert!(head.len() > 0, "Line splitter caught in infinite loop");
        assert!(tail.len() < text.len(), "Line splitter not shrinking string");
        result = result + head;
        // Must preserve a hard newline at the end if the input string had
        // one. The else branch checks for the very last char being a newline,
        // this would be clipped off otherwise.
        if tail.len() != 0 { result = result + "\n"; }
        else if text.chars().last() == Some('\n') { result = result + "\n"; }
        text = tail;
    }
    result
}

pub struct Map2DIterator<T> {
    /// Input iterator
    iter: T,
    x: i32,
    y: i32,
}

impl<T: Iterator<Item=char>> Iterator for Map2DIterator<T> {
    type Item = (char, i32, i32);

    fn next(&mut self) -> Option<(char, i32, i32)> {
        loop {
            match self.iter.next() {
                None => { return None }
                Some(c) if c == '\n' => { self.y += 1; self.x = 0; }
                Some(c) if (c as u32) < 32 => { }
                Some(c) => { self.x += 1; return Some((c, self.x - 1, self.y)) }
            }
        }
    }
}

pub trait Map2DUtil {
    fn map2d(self) -> Map2DIterator<Self>;
}

impl<T: Iterator<Item=char>> Map2DUtil for T {
    fn map2d(self) -> Map2DIterator<T> {
        Map2DIterator{ iter: self, x: 0, y: 0 }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_split_line() {
        use super::split_line;

        assert_eq!(("", ""), split_line("", &|_| 1.0, 12.0));
        assert_eq!(("a", ""), split_line("a", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the cat", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the     cat", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the  \t cat", &|_| 1.0, 5.0));
        assert_eq!(("the", "cat"), split_line("the \ncat", &|_| 1.0, 32.0));
        assert_eq!(("the", "   cat"), split_line("the \n   cat", &|_| 1.0, 32.0));
        assert_eq!(("the  cat", ""), split_line("the  cat", &|_| 1.0, 32.0));
        assert_eq!(("the", "cat sat"), split_line("the cat sat", &|_| 1.0, 6.0));
        assert_eq!(("the cat", "sat"), split_line("the cat sat", &|_| 1.0, 7.0));
        assert_eq!(("a", "bc"), split_line("abc", &|_| 1.0, 0.01));
        assert_eq!(("dead", "beef"), split_line("deadbeef", &|_| 1.0, 4.0));
        assert_eq!(("the-", "cat"), split_line("the-cat", &|_| 1.0, 5.0));
    }
}
<|endoftext|>


<commit_before>fn main() {
    for c in range(1i, 51) {
        for b in range(1, c) {
            for a in range(1, b) {
                if a * a + b * b == c * c {
                    println!("{}, {}, {}", a, b, c)
                }
            }
        }
    }
}
<commit_msg>Update triple.rs to Rust 1.0<commit_after>fn main() {
    for c in (1 .. 51) {
        for b in (1 .. c) {
            for a in (1 .. b) {
                if a * a + b * b == c * c {
                    println!("{}, {}, {}", a, b, c)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/**
 *  wc (word count) implementation in Rust
 *
 *  The purpose is to learn Rust a bit
 *
 *  author: michal.vyskocil@gmail.com
 *
 * TODO:
 *   * output is not properly formatted
 *   * word splitting is done on space only, where manual page claims whitespace
 */

use std::io::{BufferedReader, Reader, File, Lines, Buffer, IoError};
use std::os::args;

#[deriving(Show)]
pub struct WordCount {
    pub lines: uint,
    pub words: uint,
    pub chars: uint,
    pub bytes: uint
}

impl WordCount {
    fn sum(&mut self, other: &WordCount) {
        self.lines += other.lines;
        self.words += other.words;
        self.chars += other.chars;
        self.bytes += other.bytes;
    }
}

#[deriving(Show)]
struct Cfg {
    pub byte_count: bool,
    pub char_count: bool,
    pub line_count: bool,
    pub word_count: bool,
}

fn wc<'r, T: Buffer>(lines : &'r mut Lines<'r, T>) -> Result<WordCount, IoError> {
    let mut ret : WordCount = WordCount { lines: 0u, words: 0u, chars: 0u, bytes: 0u };

    for res in lines {
        let line = try!(res);
        let slice: &str = line.as_slice();

        ret.lines += 1;
        ret.words += slice.split(' ').count();
        ret.chars += slice.chars().count();
        ret.bytes += slice.bytes().count();

    }

    return Ok(ret);
}

fn parse_args(args: Vec<String>) -> (Cfg, Vec<String>) {

    let mut cfg = Cfg{byte_count: false, char_count: false, line_count: false, word_count: false};
    let mut idx = 1u;
    let mut paths = Vec::new();

    while idx < args.len() {
        match args[idx].as_slice() {
            "--lines" => cfg.line_count = true,
            "-l"      => cfg.line_count = true,
            "--bytes" => cfg.byte_count = true,
            "-c"      => cfg.byte_count = true,
            "--chars" => cfg.char_count = true,
            "-m"      => cfg.char_count = true,
            "--words" => cfg.word_count = true,
            "-w"      => cfg.word_count = true,
            _ => paths.push(args[idx].clone())  //FIXME: unecessary clone
        }
        idx += 1;
    }

    if !cfg.byte_count && (!cfg.char_count && ! cfg.line_count && !cfg.word_count) {
        cfg.char_count = true;
        cfg.line_count = true;
        cfg.word_count = true;
    }

    (cfg, paths)
}

//newline, word, character, byte, maximum line length
fn print_results(wc : &WordCount, cfg: &Cfg, path: &str) {

    let mut buf = String::new();

    if cfg.line_count {
        buf = format!("{:u}", wc.lines);
    }

    //TODO: add creates new object, investigate things like extend
    if cfg.word_count {
        buf = buf.add(&format!(" {:u}", wc.words));
    }
    if cfg.char_count {
        buf = buf.add(&format!(" {:u}", wc.chars));
    }
    if cfg.byte_count {
        buf = buf.add(&format!(" {:u}", wc.bytes));
    }

    let mut sbuf = buf.as_slice();

    if sbuf.char_at(0) == ' ' {
        sbuf = sbuf.slice_from(1);
    }

    println!("{:s} {:s}", sbuf, path);
}

fn main() {

    let (cfg, paths) = parse_args(args());
    println!("cfg: {}, paths: {}", cfg, paths);

    if paths.len() == 0 {
        fail!("Reading from stdin is not yet implemented");
    }

    let mut total : WordCount = WordCount { lines: 0u, words: 0u, chars: 0u, bytes: 0u };

    for path_i in paths.iter() {

        let path = path_i.as_slice();

        // TODO: clone is just a workaround
        let p = Path::new(path);
        // errors can be checked on opening file ...
        let f = match File::open(&p) {
            Err(why) => fail!("Can't open {}: {}", p.display(), why.desc),
            Ok(f) => f,
        };
        let mut br = BufferedReader::new(f);

        let res = match wc(&mut br.lines()) {
            Ok(res) => res,
            Err(e) => fail!(e)
        };

        total.sum(&res);
        print_results(&res, &cfg, path);
    }

    if paths.len() > 1 {
        print_results(&total, &cfg, "total");
    }

}
<commit_msg>Problem: output is not aligned<commit_after>/**
 *  wc (word count) implementation in Rust
 *
 *  The purpose is to learn Rust a bit
 *
 *  author: michal.vyskocil@gmail.com
 *
 * TODO:
 *   * output is not properly formatted
 *   * word splitting is done on space only, where manual page claims whitespace
 */

use std::io::{BufferedReader, Reader, File, Lines, Buffer, IoError};
use std::os::args;

#[deriving(Show)]
pub struct WordCount {
    pub lines: uint,
    pub words: uint,
    pub chars: uint,
    pub bytes: uint
}

impl WordCount {
    fn sum(&mut self, other: &WordCount) {
        self.lines += other.lines;
        self.words += other.words;
        self.chars += other.chars;
        self.bytes += other.bytes;
    }
}

#[deriving(Show)]
struct Cfg {
    pub byte_count: bool,
    pub char_count: bool,
    pub line_count: bool,
    pub word_count: bool,
}

fn is_pwr_ten(i: uint) -> bool {
    if i < 10 {
        return false;
    }

    let mut r: uint = i;
    while r > 10 {
        if r % 10 != 0 {
            return false;
        }
        r = r / 10;
    }

    return r == 10;
}

fn uint_len(i: uint) -> uint {

    if i < 10 {
        return 1;
    }

    let ret = (i as f64).log10().ceil() as uint;

    if is_pwr_ten(i) {
        return ret +1;
    }

    ret
}

#[test]
fn test_int_len() {

    for i in range(0u, 10002) {
        let s = format!("{:u}", i);
        //assert_eq!(s.len(), int_len(i));
        println!("{:u} {}", i, uint_len(i));
    }
}

#[test]
fn test_is_pwr_ten() {

    for i in range(0u, 1002) {
        if i == 10 || i == 100 || i == 1000 {
            assert_eq!(is_pwr_ten(i), true);
        }
        else {
            assert_eq!(is_pwr_ten(i), false);
        }
    }
}

fn wc<'r, T: Buffer>(lines : &'r mut Lines<'r, T>) -> Result<WordCount, IoError> {
    let mut ret : WordCount = WordCount { lines: 0u, words: 0u, chars: 0u, bytes: 0u };

    for res in lines {
        let line = try!(res);
        let slice: &str = line.as_slice();

        ret.lines += 1;
        ret.words += slice.split(' ').count();
        ret.chars += slice.chars().count();
        ret.bytes += slice.bytes().count();

    }

    return Ok(ret);
}

fn parse_args(args: Vec<String>) -> (Cfg, Vec<String>) {

    let mut cfg = Cfg{byte_count: false, char_count: false, line_count: false, word_count: false};
    let mut idx = 1u;
    let mut paths = Vec::new();

    while idx < args.len() {
        match args[idx].as_slice() {
            "--lines" => cfg.line_count = true,
            "-l"      => cfg.line_count = true,
            "--bytes" => cfg.byte_count = true,
            "-c"      => cfg.byte_count = true,
            "--chars" => cfg.char_count = true,
            "-m"      => cfg.char_count = true,
            "--words" => cfg.word_count = true,
            "-w"      => cfg.word_count = true,
            _ => paths.push(args[idx].clone())  //FIXME: unecessary clone
        }
        idx += 1;
    }

    if !cfg.byte_count && (!cfg.char_count && ! cfg.line_count && !cfg.word_count) {
        cfg.char_count = true;
        cfg.line_count = true;
        cfg.word_count = true;
    }

    (cfg, paths)
}

//newline, word, character, byte, maximum line length
fn print_results(results : &Vec<(WordCount, &str)>, cfg: &Cfg) {

    for i in results.iter() {

        let (wc, path) = *i;

        let mut fmtbuf: String;

        if cfg.line_count {
            fmtbuf = format!(" {:u}", wc.lines);
        }
        else {
            fmtbuf = String::from_str("");
        }

        //TODO: add creates new object, investigate things like extend
        if cfg.word_count {
            fmtbuf = format!("{:s} {:u}", fmtbuf, wc.words);
        }
        if cfg.char_count {
            fmtbuf = format!("{:s} {:u}", fmtbuf, wc.words);
        }
        if cfg.byte_count {
            fmtbuf = format!("{:s} {:u}", fmtbuf, wc.words);
        }

        println!("{:s} {:s}", fmtbuf, path);
    }

}

fn main() {

    let (cfg, paths) = parse_args(args());
    println!("cfg: {}, paths: {}", cfg, paths);

    if paths.len() == 0 {
        fail!("Reading from stdin is not yet implemented");
    }

    let mut total : WordCount = WordCount { lines: 0u, words: 0u, chars: 0u, bytes: 0u };
    let mut results = Vec::with_capacity(paths.len());

    for path_i in paths.iter() {

        let path = path_i.as_slice();

        // TODO: clone is just a workaround
        let p = Path::new(path);
        // errors can be checked on opening file ...
        let f = match File::open(&p) {
            Err(why) => fail!("Can't open {}: {}", p.display(), why.desc),
            Ok(f) => f,
        };
        let mut br = BufferedReader::new(f);

        let res = match wc(&mut br.lines()) {
            Ok(res) => res,
            Err(e) => fail!(e)
        };

        total.sum(&res);
        results.push((res, path));
    }

    if paths.len() > 1 {
        results.push((total, "total"));
    }

    print_results(&results, &cfg);

}
<|endoftext|>


<commit_before>// vim: tw=80

use mockall;
use mockall_derive::mock;
use std::default::Default;

#[test]
#[allow(unused)]
fn simple_struct() {
    #[mock]
    struct SimpleStruct {
        x: i16
    }
    #[mock]
    impl SimpleStruct {
        fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockSimpleStruct::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn generic_struct() {
    #[mock]
    struct GenericStruct<'a, T, V> {
        t: T,
        v: &'a V
    }
    #[mock]
    impl<'a, T, V> GenericStruct<'a, T, V> {
        fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockGenericStruct::<'static, u8, i8>::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
fn simple_trait() {
    #[mock]
    trait SimpleTrait {
        fn foo(&self, x: u32) -> u32;
    }

    let mut mock = MockSimpleTrait::default();
    mock.expect_foo()
        .returning(|x| x + 1);
    assert_eq!(5, mock.foo(4));
}
<commit_msg>More integration tests for mockall_derive<commit_after>// vim: tw=80

use mockall;
use mockall_derive::mock;
use std::default::Default;

#[test]
#[allow(unused)]
fn generic_struct() {
    #[mock]
    struct GenericStruct<'a, T, V> {
        t: T,
        v: &'a V
    }
    #[mock]
    impl<'a, T, V> GenericStruct<'a, T, V> {
        fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockGenericStruct::<'static, u8, i8>::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn impl_trait() {
    trait Foo {
        fn foo(&self, x: u32) -> i64;
    }

    #[mock]
    struct SomeStruct {}

    #[mock]
    impl Foo for SomeStruct {
        fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockSomeStruct::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn method_self_by_value() {
    #[mock]
    struct MethodByValue {}

    #[mock]
    impl MethodByValue {
        fn foo(self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockMethodByValue::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn pub_crate_struct() {
    #[mock]
    pub(crate) struct PubStruct {
        x: i16
    }
    #[mock]
    impl PubStruct {
        pub(crate) fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockPubStruct::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn pub_super_struct() {
    mod m {
        use super::*;
        #[mock]
        pub(super) struct PubStruct {
            x: i16
        }
        #[mock]
        impl PubStruct {
            pub(super) fn foo(&self, _x: u32) -> i64 {
                42
            }
        }
    }

    let mut mock = m::MockPubStruct::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn pub_struct() {
    #[mock]
    pub struct PubStruct {
        x: i16
    }
    #[mock]
    impl PubStruct {
        pub fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockPubStruct::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
#[allow(unused)]
fn simple_struct() {
    #[mock]
    struct SimpleStruct {
        x: i16
    }
    #[mock]
    impl SimpleStruct {
        fn foo(&self, _x: u32) -> i64 {
            42
        }
    }

    let mut mock = MockSimpleStruct::default();
    mock.expect_foo()
        .returning(|x| i64::from(x) + 1);
    assert_eq!(5, mock.foo(4));
}

#[test]
fn simple_trait() {
    #[mock]
    trait SimpleTrait {
        fn foo(&self, x: u32) -> u32;
    }

    let mut mock = MockSimpleTrait::default();
    mock.expect_foo()
        .returning(|x| x + 1);
    assert_eq!(5, mock.foo(4));
}
<|endoftext|>


<commit_before>// Copyright 2016 Serde YAML Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use serde;
use serde_yaml;

use std::fmt::Debug;

fn test_error<T>(yaml: &str, expected: &str)
    where T: serde::Deserialize + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, format!("{}", result.unwrap_err()));
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc!("
        ---
        str");
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_empty() {
    let yaml = "";
    let expected = "EOF while parsing a value";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        v: bool,
        w: bool,
    }
    let yaml = indoc!("
        ---
        v: true");
    let expected = "missing field `w` at line 2 column 2";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc!("
        ---
        *some");
    let expected = "while parsing node, found unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc!("
        ---
        0
        ---
        1");
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_variant_map_wrong_size() {
    #[derive(Deserialize, Debug)]
    enum Variant {
        V(usize),
    }
    let yaml = indoc!(r#"
        ---
        "V": 16
        "other": 32"#);
    let expected = "invalid length 2, expected map containing 1 entry";
    test_error::<Variant>(yaml, expected);
}

#[test]
fn test_variant_not_a_map() {
    #[derive(Deserialize, Debug)]
    enum Variant {
        V(usize),
    }
    let yaml = indoc!(r#"
        ---
        - "V""#);
    let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1";
    test_error::<Variant>(yaml, expected);
}
<commit_msg>Test the invalid_value and invalid_length error cases<commit_after>// Copyright 2016 Serde YAML Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use serde;
use serde_yaml;

use std::fmt::Debug;

fn test_error<T>(yaml: &str, expected: &str)
    where T: serde::Deserialize + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, format!("{}", result.unwrap_err()));
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc!("
        ---
        str");
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_empty() {
    let yaml = "";
    let expected = "EOF while parsing a value";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        v: bool,
        w: bool,
    }
    let yaml = indoc!("
        ---
        v: true");
    let expected = "missing field `w` at line 2 column 2";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc!("
        ---
        *some");
    let expected = "while parsing node, found unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc!("
        ---
        0
        ---
        1");
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_variant_map_wrong_size() {
    #[derive(Deserialize, Debug)]
    enum Variant {
        V(usize),
    }
    let yaml = indoc!(r#"
        ---
        "V": 16
        "other": 32"#);
    let expected = "invalid length 2, expected map containing 1 entry";
    test_error::<Variant>(yaml, expected);
}

#[test]
fn test_variant_not_a_map() {
    #[derive(Deserialize, Debug)]
    enum Variant {
        V(usize),
    }
    let yaml = indoc!(r#"
        ---
        - "V""#);
    let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1";
    test_error::<Variant>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc!("
        ---
        !!bool str");
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 8";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc!("
        ---
        !!int str");
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 7";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc!("
        ---
        !!float str");
    let expected = "invalid value: string \"str\", expected a float at line 2 column 9";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc!("
        ---
        !!null str");
    let expected = "invalid value: string \"str\", expected null at line 2 column 8";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc!("
        ---
        [0, 0]");
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc!("
        ---
        [0, 0, 0]");
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}
<|endoftext|>