<commit_before>use std::cmp;
use std::collections::BinaryHeap;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use super::{
    MerkleTree,
    RemoteNode,
};
use super::rust_base58::{FromBase58, ToBase58};
use super::types::*;
use utils::json::JsonEncodable;

enum CatchupStepResult {
    Finished,
    Continue,
    FailedAtNode(usize),
}

pub struct CatchupHandler {
    pub f: usize,
    pub ledger_status_same: usize,
    pub merkle_tree: MerkleTree,
    pub target_mt_size: usize,
    pub target_mt_root: Vec<u8>,
    pub new_mt_vote: usize,
    pub nodes: Vec<RemoteNode>,
    pub initiate_cmd_id: i32,
    pub is_refresh: bool,
    pub pending_catchup: Option<CatchUpProcess>,
    pub pool_id: i32,
}

impl Default for CatchupHandler {
    fn default() -> Self {
        CatchupHandler {
            f: 0,
            ledger_status_same: 0,
            merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(),
            nodes: Vec::new(),
            target_mt_size: 0,
            new_mt_vote: 0,
            target_mt_root: Vec::new(),
            pending_catchup: None,
            initiate_cmd_id: 0,
            is_refresh: false,
            pool_id: 0,
        }
    }
}

impl CatchupHandler {
    pub fn process_msg(&mut self, msg: Message, raw_msg: &String, src_ind: usize) -> Result<Option<MerkleTree>, PoolError> {
        match msg {
            Message::Pong => {
                //sending ledger status
                //TODO not send ledger status directly as response on ping, wait pongs from all nodes?
                let ls: LedgerStatus = LedgerStatus {
                    txnSeqNo: self.nodes.len(),
                    merkleRoot: self.merkle_tree.root_hash().as_slice().to_base58(),
                    ledgerId: 0,
                    ppSeqNo: None,
                    viewNo: None,
                };
                let resp_msg: Message = Message::LedgerStatus(ls);
                self.nodes[src_ind].send_msg(&resp_msg)?;
            }
            Message::LedgerStatus(ledger_status) => {
                if self.merkle_tree.root_hash().as_slice().to_base58().ne(ledger_status.merkleRoot.as_str()) {
                    return Err(PoolError::CommonError(
                        CommonError::InvalidState(
                            "Ledger merkle tree doesn't acceptable for current tree.".to_string())));
                }
                self.ledger_status_same += 1;
                if self.ledger_status_same == self.f + 1 {
                    return Ok(Some(self.merkle_tree.clone()));
                }
            }
            Message::ConsistencyProof(cons_proof) => {
                trace!("{:?}", cons_proof);
                if cons_proof.seqNoStart == self.merkle_tree.count()
                    && cons_proof.seqNoEnd > self.merkle_tree.count() {
                    self.target_mt_size = cmp::max(cons_proof.seqNoEnd, self.target_mt_size);
                    self.new_mt_vote += 1;
                    self.target_mt_root = cons_proof.newMerkleRoot.from_base58().unwrap();
                    debug!("merkle tree expected size now {}", self.target_mt_size);
                }
                if self.new_mt_vote == self.f + 1 {
                    self.start_catchup()?;
                }
            }
            Message::CatchupRep(catchup) => {
                if let Some(new_mt) = self.process_catchup_rep(catchup, src_ind)? {
                    return Ok(Some(new_mt));
                }
            }
            _ => {
                warn!("unhandled msg {:?}", msg);
            }
        };
        Ok(None)
    }

    pub fn start_catchup(&mut self) -> Result<(), PoolError> {
        trace!("start_catchup");
        if self.pending_catchup.is_some() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "CatchUp already started for the pool".to_string())));
        }
        if self.merkle_tree.count() != self.nodes.len() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "Merkle tree doesn't equal nodes count".to_string())));
        }

        let node_cnt = self.nodes.iter().filter(|node| !node.is_blacklisted).count();
        let cnt_to_catchup = self.target_mt_size - self.merkle_tree.count();
        if cnt_to_catchup <= 0 {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Nothing to CatchUp, but started".to_string())));
        }

        self.pending_catchup = Some(CatchUpProcess {
            merkle_tree: self.merkle_tree.clone(),
            pending_reps: BinaryHeap::new(),
        });

        let portion = (cnt_to_catchup + node_cnt - 1) / node_cnt; //TODO check standard round up div
        let mut catchup_req = CatchupReq {
            ledgerId: 0,
            seqNoStart: node_cnt + 1,
            seqNoEnd: node_cnt + 1 + portion - 1,
            catchupTill: self.target_mt_size,
        };
        for node in &self.nodes {
            if node.is_blacklisted {
                continue;
            }
            node.send_msg(&Message::CatchupReq(catchup_req.clone()))?;
            catchup_req.seqNoStart += portion;
            catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1,
                                            catchup_req.catchupTill);
        }
        Ok(())
    }

    pub fn process_catchup_rep(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<Option<MerkleTree>, PoolError> {
        trace!("append {:?}", catchup);
        let catchup_finished = self.catchup_step(catchup, node_idx)?;
        match catchup_finished {
            CatchupStepResult::Finished => return Ok(Some(self.finish_catchup()?)),
            CatchupStepResult::Continue => { /* nothing to do */ }
            CatchupStepResult::FailedAtNode(failed_node_idx) => {
                warn!("Fail to continue catch-up by response from node with idx {}. Node will be blacklisted and catchup will be restarted", failed_node_idx);
                self.nodes[failed_node_idx].is_blacklisted = true;
                self.pending_catchup = None;
                self.start_catchup()?
            }
        }
        Ok(None)
    }

    fn catchup_step(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupStepResult, PoolError> {
        let mut process = self.pending_catchup.as_mut()
            .ok_or(CommonError::InvalidState("Process non-existing CatchUp".to_string()))?;
        process.pending_reps.push((catchup, node_idx));
        while !process.pending_reps.is_empty()
            && process.pending_reps.peek().unwrap().0.min_tx() - 1 == process.merkle_tree.count() {
            let (mut first_resp, node_idx) = process.pending_reps.pop().unwrap();
            let mut temp_mt = process.merkle_tree.clone();
            while !first_resp.txns.is_empty() {
                let key = first_resp.min_tx().to_string();
                if let Ok(new_gen_tx) = first_resp.txns.remove(&key).unwrap().to_json() {
                    trace!("append to tree {}", new_gen_tx);
                    temp_mt.append(new_gen_tx)?;
                } else {
                    return Ok(CatchupStepResult::FailedAtNode(node_idx));
                }
            }

            if CatchupHandler::check_cons_proofs(&temp_mt, &first_resp.consProof, &self.target_mt_root, self.target_mt_size).is_err() {
                return Ok(CatchupStepResult::FailedAtNode(node_idx));
            }

            process.merkle_tree = temp_mt;
        }
        trace!("updated mt hash {}, tree {:?}", process.merkle_tree.root_hash().as_slice().to_base58(), process.merkle_tree);
        if &process.merkle_tree.count() == &self.target_mt_size {
            if process.merkle_tree.root_hash().ne(&self.target_mt_root) {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "CatchUp failed: all transactions added, proofs checked, but root hash differ with target".to_string())));
            }
            return Ok(CatchupStepResult::Finished);
        } else {
            return Ok(CatchupStepResult::Continue);
        }
    }

    fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> Result<(), CommonError> {
        let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();
        for cons_proof in cons_proofs {
            let cons_proof: &String = cons_proof;
            bytes_proofs.push(cons_proof.from_base58().map_err(|err|
                CommonError::InvalidStructure(
                    format!("Can't decode node consistency proof: {}", err)))?)
        }
        assert!(mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)?);
        Ok(())
    }

    fn finish_catchup(&mut self) -> Result<MerkleTree, PoolError> {
        Ok(self.pending_catchup.take().
            ok_or(CommonError::InvalidState("Try to finish non-existing CatchUp".to_string()))?
            .merkle_tree)
    }

    pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> {
        let cmd = if self.is_refresh {
            PoolCommand::RefreshAck(self.initiate_cmd_id, status)
        } else {
            PoolCommand::OpenAck(self.initiate_cmd_id, status.map(|()| self.pool_id))
        };
        CommandExecutor::instance()
            .send(Command::Pool(cmd))
            .map_err(|err|
                PoolError::CommonError(
                    CommonError::InvalidState("Can't send ACK cmd".to_string())))
    }
}
<commit_msg>Remove assert from CatchupHandler::check_cons_proofs.<commit_after>use std::cmp;
use std::collections::BinaryHeap;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use super::{
    MerkleTree,
    RemoteNode,
};
use super::rust_base58::{FromBase58, ToBase58};
use super::types::*;
use utils::json::JsonEncodable;

enum CatchupStepResult {
    Finished,
    Continue,
    FailedAtNode(usize),
}

pub struct CatchupHandler {
    pub f: usize,
    pub ledger_status_same: usize,
    pub merkle_tree: MerkleTree,
    pub target_mt_size: usize,
    pub target_mt_root: Vec<u8>,
    pub new_mt_vote: usize,
    pub nodes: Vec<RemoteNode>,
    pub initiate_cmd_id: i32,
    pub is_refresh: bool,
    pub pending_catchup: Option<CatchUpProcess>,
    pub pool_id: i32,
}

impl Default for CatchupHandler {
    fn default() -> Self {
        CatchupHandler {
            f: 0,
            ledger_status_same: 0,
            merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(),
            nodes: Vec::new(),
            target_mt_size: 0,
            new_mt_vote: 0,
            target_mt_root: Vec::new(),
            pending_catchup: None,
            initiate_cmd_id: 0,
            is_refresh: false,
            pool_id: 0,
        }
    }
}

impl CatchupHandler {
    pub fn process_msg(&mut self, msg: Message, raw_msg: &String, src_ind: usize) -> Result<Option<MerkleTree>, PoolError> {
        match msg {
            Message::Pong => {
                //sending ledger status
                //TODO not send ledger status directly as response on ping, wait pongs from all nodes?
                let ls: LedgerStatus = LedgerStatus {
                    txnSeqNo: self.nodes.len(),
                    merkleRoot: self.merkle_tree.root_hash().as_slice().to_base58(),
                    ledgerId: 0,
                    ppSeqNo: None,
                    viewNo: None,
                };
                let resp_msg: Message = Message::LedgerStatus(ls);
                self.nodes[src_ind].send_msg(&resp_msg)?;
            }
            Message::LedgerStatus(ledger_status) => {
                if self.merkle_tree.root_hash().as_slice().to_base58().ne(ledger_status.merkleRoot.as_str()) {
                    return Err(PoolError::CommonError(
                        CommonError::InvalidState(
                            "Ledger merkle tree doesn't acceptable for current tree.".to_string())));
                }
                self.ledger_status_same += 1;
                if self.ledger_status_same == self.f + 1 {
                    return Ok(Some(self.merkle_tree.clone()));
                }
            }
            Message::ConsistencyProof(cons_proof) => {
                trace!("{:?}", cons_proof);
                if cons_proof.seqNoStart == self.merkle_tree.count()
                    && cons_proof.seqNoEnd > self.merkle_tree.count() {
                    self.target_mt_size = cmp::max(cons_proof.seqNoEnd, self.target_mt_size);
                    self.new_mt_vote += 1;
                    self.target_mt_root = cons_proof.newMerkleRoot.from_base58().unwrap();
                    debug!("merkle tree expected size now {}", self.target_mt_size);
                }
                if self.new_mt_vote == self.f + 1 {
                    self.start_catchup()?;
                }
            }
            Message::CatchupRep(catchup) => {
                if let Some(new_mt) = self.process_catchup_rep(catchup, src_ind)? {
                    return Ok(Some(new_mt));
                }
            }
            _ => {
                warn!("unhandled msg {:?}", msg);
            }
        };
        Ok(None)
    }

    pub fn start_catchup(&mut self) -> Result<(), PoolError> {
        trace!("start_catchup");
        if self.pending_catchup.is_some() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "CatchUp already started for the pool".to_string())));
        }
        if self.merkle_tree.count() != self.nodes.len() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "Merkle tree doesn't equal nodes count".to_string())));
        }

        let node_cnt = self.nodes.iter().filter(|node| !node.is_blacklisted).count();
        let cnt_to_catchup = self.target_mt_size - self.merkle_tree.count();
        if cnt_to_catchup <= 0 {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Nothing to CatchUp, but started".to_string())));
        }

        self.pending_catchup = Some(CatchUpProcess {
            merkle_tree: self.merkle_tree.clone(),
            pending_reps: BinaryHeap::new(),
        });

        let portion = (cnt_to_catchup + node_cnt - 1) / node_cnt; //TODO check standard round up div
        let mut catchup_req = CatchupReq {
            ledgerId: 0,
            seqNoStart: node_cnt + 1,
            seqNoEnd: node_cnt + 1 + portion - 1,
            catchupTill: self.target_mt_size,
        };
        for node in &self.nodes {
            if node.is_blacklisted {
                continue;
            }
            node.send_msg(&Message::CatchupReq(catchup_req.clone()))?;
            catchup_req.seqNoStart += portion;
            catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1,
                                            catchup_req.catchupTill);
        }
        Ok(())
    }

    pub fn process_catchup_rep(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<Option<MerkleTree>, PoolError> {
        trace!("append {:?}", catchup);
        let catchup_finished = self.catchup_step(catchup, node_idx)?;
        match catchup_finished {
            CatchupStepResult::Finished => return Ok(Some(self.finish_catchup()?)),
            CatchupStepResult::Continue => { /* nothing to do */ }
            CatchupStepResult::FailedAtNode(failed_node_idx) => {
                warn!("Fail to continue catch-up by response from node with idx {}. Node will be blacklisted and catchup will be restarted", failed_node_idx);
                self.nodes[failed_node_idx].is_blacklisted = true;
                self.pending_catchup = None;
                self.start_catchup()?
            }
        }
        Ok(None)
    }

    fn catchup_step(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupStepResult, PoolError> {
        let mut process = self.pending_catchup.as_mut()
            .ok_or(CommonError::InvalidState("Process non-existing CatchUp".to_string()))?;
        process.pending_reps.push((catchup, node_idx));
        while !process.pending_reps.is_empty()
            && process.pending_reps.peek().unwrap().0.min_tx() - 1 == process.merkle_tree.count() {
            let (mut first_resp, node_idx) = process.pending_reps.pop().unwrap();
            let mut temp_mt = process.merkle_tree.clone();
            while !first_resp.txns.is_empty() {
                let key = first_resp.min_tx().to_string();
                if let Ok(new_gen_tx) = first_resp.txns.remove(&key).unwrap().to_json() {
                    trace!("append to tree {}", new_gen_tx);
                    temp_mt.append(new_gen_tx)?;
                } else {
                    return Ok(CatchupStepResult::FailedAtNode(node_idx));
                }
            }

            if CatchupHandler::check_cons_proofs(&temp_mt, &first_resp.consProof, &self.target_mt_root, self.target_mt_size)
                .map_err(map_err_err!()).is_err() {
                return Ok(CatchupStepResult::FailedAtNode(node_idx));
            }

            process.merkle_tree = temp_mt;
        }
        trace!("updated mt hash {}, tree {:?}", process.merkle_tree.root_hash().as_slice().to_base58(), process.merkle_tree);
        if &process.merkle_tree.count() == &self.target_mt_size {
            if process.merkle_tree.root_hash().ne(&self.target_mt_root) {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "CatchUp failed: all transactions added, proofs checked, but root hash differ with target".to_string())));
            }
            return Ok(CatchupStepResult::Finished);
        } else {
            return Ok(CatchupStepResult::Continue);
        }
    }

    fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> Result<(), CommonError> {
        let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();
        for cons_proof in cons_proofs {
            let cons_proof: &String = cons_proof;
            bytes_proofs.push(cons_proof.from_base58().map_err(|err|
                CommonError::InvalidStructure(
                    format!("Can't decode node consistency proof: {}", err)))?)
        }
        if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
            return Err(CommonError::InvalidStructure("Consistency proof verification failed".to_string()));
        }
        Ok(())
    }

    fn finish_catchup(&mut self) -> Result<MerkleTree, PoolError> {
        Ok(self.pending_catchup.take().
            ok_or(CommonError::InvalidState("Try to finish non-existing CatchUp".to_string()))?
            .merkle_tree)
    }

    pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> {
        let cmd = if self.is_refresh {
            PoolCommand::RefreshAck(self.initiate_cmd_id, status)
        } else {
            PoolCommand::OpenAck(self.initiate_cmd_id, status.map(|()| self.pool_id))
        };
        CommandExecutor::instance()
            .send(Command::Pool(cmd))
            .map_err(|err|
                PoolError::CommonError(
                    CommonError::InvalidState("Can't send ACK cmd".to_string())))
    }
}
<|endoftext|>


<commit_before>use super::super::{Grid, Y, X, Coord};
use grid_loop::GridLoopField;
use super::*;

use rand::{Rng, distributions};

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_decided_edges = 0;
    let temperature = 5.0f64;

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                if has_clue[(Y(y), X(x))] {
                    pos_cand.push((Y(y), X(x)));
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = Field::new(&current_problem, dic);
                field.check_all_cell();

                let isok;
                let current_decided_edges;
                if field.inconsistent() {
                    isok = false;
                    current_decided_edges = -1;
                } else {
                    current_decided_edges = field.grid_loop().num_decided_edges();

                    if prev_decided_edges < current_decided_edges {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_decided_edges - prev_decided_edges) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_decided_edges = current_decided_edges;

                    if field.fully_solved() {
                        return Some(current_problem);
                    }
                    break;
                } else {
                    current_problem[pos] = prev_clue;
                }
            }

            if updated {
                break;
            }
        }
    }

    None
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}
<commit_msg>Slitherlink: CRLF -> LF, check whether all clues are placed, consider only the clue positions near an undecided edge<commit_after>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoop, GridLoopField};
use super::*;

use rand::{Rng, distributions};

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_decided_edges = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = Field::new(&current_problem, dic);
                field.check_all_cell();

                let isok;
                let current_decided_edges;
                if field.inconsistent() {
                    isok = false;
                    current_decided_edges = -1;
                } else {
                    current_decided_edges = field.grid_loop().num_decided_edges();

                    if prev_decided_edges < current_decided_edges {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_decided_edges - prev_decided_edges) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_decided_edges = current_decided_edges;
                    if prev_clue == NO_CLUE {
                        unplaced_clues -= 1;
                    }

                    if field.fully_solved() && unplaced_clues == 0 {
                        return Some(current_problem);
                    }

                    last_field = field;
                    break;
                } else {
                    current_problem[pos] = prev_clue;
                }
            }

            if updated {
                break;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

#[test]
fn all_aggregrated_diffs_equal_latest_version(
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let ((expected, baseline_duration), (actual, diff_duration)) = std::thread::scope(
        |scope| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
            let baseline = scope.spawn(|| -> Result<_, crates_index::Error> {
                let index = crates_index::Index::new_cargo_default()?;
                let start = std::time::Instant::now();
                let mut versions = HashSet::new();
                for krate in index.crates() {
                    for version in krate.versions() {
                        versions.insert(version.checksum().to_owned());
                    }
                }
                Ok((versions, start.elapsed()))
            });

            let actual = scope.spawn(|| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
                use crates_index_diff::git;

                let start = std::time::Instant::now();
                let repo_path = crates_index::Index::new_cargo_default()?.path().to_owned();
                let index = crates_index_diff::Index::from_path_or_cloned(repo_path)?;
                let changes = index.changes_between_commits(
                    git::hash::ObjectId::empty_tree(git::hash::Kind::Sha1),
                    index
                        .repository()
                        .find_reference("refs/remotes/origin/HEAD")?
                        .target()
                        .id(),
                )?;

                use crates_index_diff::Change::*;
                let mut versions = HashSet::new();

                for change in changes {
                    match change {
                        Added(v) | Yanked(v) => {
                            versions.insert(v.checksum.to_owned());
                        }
                        Deleted {
                            versions: deleted, ..
                        } => {
                            for deleted_version in deleted {
                                versions.remove(&deleted_version.checksum);
                            }
                        }
                    }
                }
                Ok((versions, start.elapsed()))
            });

            Ok((
                baseline.join().expect("no panic")?,
                actual.join().expect("no panic")?,
            ))
        },
    )?;

    dbg!(baseline_duration, expected.len());
    dbg!(diff_duration, actual.len());
    // assert_eq!(
    //     actual.len(),
    //     expected.len(),
    //     "aggregated of all changes produces the final result"
    // );

    Ok(())
}
<commit_msg>Now the baseline result is the same. (#26)<commit_after>use std::collections::HashSet;

#[test]
fn all_aggregrated_diffs_equal_latest_version(
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let ((expected, baseline_duration), (actual, diff_duration)) = std::thread::scope(
        |scope| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
            let baseline = scope.spawn(|| -> Result<_, crates_index::Error> {
                let index = crates_index::Index::new_cargo_default()?;
                let start = std::time::Instant::now();
                let mut versions = HashSet::new();
                for krate in index.crates() {
                    for version in krate.versions() {
                        versions.insert(version.checksum().to_owned());
                    }
                }
                Ok((versions, start.elapsed()))
            });

            let actual = scope.spawn(|| -> Result<_, Box<dyn std::error::Error + Send + Sync>> {
                use crates_index_diff::git;

                let start = std::time::Instant::now();
                let repo_path = crates_index::Index::new_cargo_default()?.path().to_owned();
                let index = crates_index_diff::Index::from_path_or_cloned(repo_path)?;
                let changes = index.changes_between_commits(
                    git::hash::ObjectId::empty_tree(git::hash::Kind::Sha1),
                    index
                        .repository()
                        .find_reference("refs/remotes/origin/HEAD")?
                        .target()
                        .id(),
                )?;

                use crates_index_diff::Change::*;
                let mut versions = HashSet::new();

                for change in changes {
                    match change {
                        Added(v) | Yanked(v) => {
                            versions.insert(v.checksum.to_owned());
                        }
                        Deleted {
                            versions: deleted, ..
                        } => {
                            for deleted_version in deleted {
                                versions.remove(&deleted_version.checksum);
                            }
                        }
                    }
                }
                Ok((versions, start.elapsed()))
            });

            Ok((
                baseline.join().expect("no panic")?,
                actual.join().expect("no panic")?,
            ))
        },
    )?;

    dbg!(baseline_duration, expected.len());
    dbg!(diff_duration, actual.len());
    assert_eq!(
        actual.len(),
        expected.len(),
        "aggregated of all changes produces the final result"
    );
    assert!(actual.eq(&expected), "actual should be exactly the same");

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate duct;

use std::io::{BufRead, BufReader};
use std::fs::File;

// FIXME: rustc doesn't generate expansion info for `cfg!` anymore
#![allow(logic-bug)]

#[test]
fn examples() {
    let mut error = false;
    for file in std::fs::read_dir("clippy_tests/examples").unwrap() {
        let file = file.unwrap().path();
        // only test *.rs files
        if file.extension().map_or(true, |file| file != "rs") {
            continue;
        }
        print!("testing {}... ", file.file_stem().unwrap().to_str().unwrap());
        let skip = BufReader::new(File::open(&file).unwrap()).lines().any(|line| {
            let line = line.as_ref().unwrap().trim();
            line == "// ignore-x86" && cfg!(target_pointer_width = "32") ||
            line == "// ignore-x86_64" && cfg!(target_pointer_width = "64")
        });
        if skip {
            println!("skipping");
            continue;
        }
        cmd!("touch", &file).run().unwrap();
        let output = file.with_extension("stderr");
        cmd!("cargo", "rustc", "-q", "--example", file.file_stem().unwrap(), "--", "-Dwarnings",
             "-Zremap-path-prefix-from=examples/", "-Zremap-path-prefix-to=",
             "-Zremap-path-prefix-from=examples\\", "-Zremap-path-prefix-to="
             )
            .unchecked()
            .stderr(&output)
            .env("CLIPPY_DISABLE_WIKI_LINKS", "true")
            .dir("clippy_tests")
            .run()
            .unwrap();
        if cmd!("git", "diff", "--exit-code", output).run().is_err() {
            error = true;
            println!("ERROR");
        } else {
            println!("ok");
        }
    }
    assert!(!error, "A test failed");
}
<commit_msg>Wrong placement of inner attribute in previous commit<commit_after>// FIXME: rustc doesn't generate expansion info for `cfg!` anymore
#![allow(logic-bug)]

#[macro_use]
extern crate duct;

use std::io::{BufRead, BufReader};
use std::fs::File;

#[test]
fn examples() {
    let mut error = false;
    for file in std::fs::read_dir("clippy_tests/examples").unwrap() {
        let file = file.unwrap().path();
        // only test *.rs files
        if file.extension().map_or(true, |file| file != "rs") {
            continue;
        }
        print!("testing {}... ", file.file_stem().unwrap().to_str().unwrap());
        let skip = BufReader::new(File::open(&file).unwrap()).lines().any(|line| {
            let line = line.as_ref().unwrap().trim();
            line == "// ignore-x86" && cfg!(target_pointer_width = "32") ||
            line == "// ignore-x86_64" && cfg!(target_pointer_width = "64")
        });
        if skip {
            println!("skipping");
            continue;
        }
        cmd!("touch", &file).run().unwrap();
        let output = file.with_extension("stderr");
        cmd!("cargo", "rustc", "-q", "--example", file.file_stem().unwrap(), "--", "-Dwarnings",
             "-Zremap-path-prefix-from=examples/", "-Zremap-path-prefix-to=",
             "-Zremap-path-prefix-from=examples\\", "-Zremap-path-prefix-to="
             )
            .unchecked()
            .stderr(&output)
            .env("CLIPPY_DISABLE_WIKI_LINKS", "true")
            .dir("clippy_tests")
            .run()
            .unwrap();
        if cmd!("git", "diff", "--exit-code", output).run().is_err() {
            error = true;
            println!("ERROR");
        } else {
            println!("ok");
        }
    }
    assert!(!error, "A test failed");
}
<|endoftext|>


<commit_before>use std::{collections::BTreeMap, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::distributions::{Distribution, Gamma};
use rand::{rngs::StdRng, Rng, SeedableRng};

use sled::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Key(vec!{:?})", self.0)
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        }).collect();

    println!("working on ops {:?}", ops);
    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(ops, 0, 100, false)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        let gs = g.size();
        let gamma = Gamma::new(0.3, gs as f64);
        let v = gamma.sample(&mut rand::thread_rng());
        let len = if v > 30000.0 {
            30000
        } else if v < 1. && v > 0.0001 {
            1
        } else {
            v as usize
        };

        let space = g.gen_range(0, gs) + 1;

        let inner =
            (0..len).map(|_| g.gen_range(0, space) as u8).collect();

        Key(inner)
    }

    fn shrink(&self) -> Box<Iterator<Item = Key>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| {
                    Key(underlying[..len].to_vec())
                }),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, usize),
    Restart,
}

use self::Op::*;

impl Op {
    pub fn is_restart(&self) -> bool {
        if let Restart = self {
            true
        } else {
            false
        }
    }
}

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 6);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => Del(Key::arbitrary(g)),
            4 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            5 => Scan(Key::arbitrary(g), g.gen_range(0, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Set(ref k, v) => {
                Box::new(k.shrink().map(move |sk| Set(sk, v.clone())))
            }
            Merge(ref k, v) => {
                Box::new(k.shrink().map(move |k| Merge(k, v.clone())))
            }
            Get(ref k) => Box::new(k.shrink().map(move |k| Get(k))),
            Cas(ref k, old, new) => Box::new(Box::new(
                k.shrink()
                    .map(move |k| Cas(k, old.clone(), new.clone())),
            )),
            Scan(ref k, len) => {
                Box::new(k.shrink().map(move |k| Scan(k, len)))
            }
            Del(ref k) => Box::new(k.shrink().map(|k| Del(k))),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    ((v[0] as u16) << 8) + v[1] as u16
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    let ret = vec![(u >> 8) as u8, u as u8];
    ret
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + to_merge[0] as u16;
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    blink_node_exponent: u8,
    snapshot_after: u8,
    flusher: bool,
) -> bool {
    use self::*;
    let config = ConfigBuilder::new()
        .temporary(true)
        .snapshot_after_ops(snapshot_after as usize + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .io_buf_size(10000)
        .blink_node_split_size(
            1 << std::cmp::min(blink_node_exponent, 20),
        ).cache_capacity(40)
        .cache_bits(0)
        .merge_operator(test_merge_operator)
        .build();

    let mut tree = sled::Tree::start(config.clone()).unwrap();
    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops.into_iter() {
        match op {
            Set(k, v) => {
                tree.set(&k.0, vec![0, v]).unwrap();
                reference.insert(k.clone(), v as u16);
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let mut entry = reference.entry(k).or_insert(0u16);
                *entry += v as u16;
            }
            Get(k) => {
                let res1 = tree
                    .get(&*k.0)
                    .unwrap()
                    .map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            Del(k) => {
                tree.del(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == &*vec![0, old] {
                        tree.set(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(old as u16) {
                    reference.insert(k, new as u16);
                }
            }
            Scan(k, len) => {
                let mut tree_iter = tree
                    .scan(&*k.0)
                    .take(len)
                    .map(|res| res.unwrap());
                let ref_iter = reference
                    .iter()
                    .filter(|&(ref rk, _rv)| **rk >= k)
                    .take(len)
                    .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                for r in ref_iter {
                    let tree_next = tree_iter.next().unwrap();
                    let lhs = (tree_next.0, &*tree_next.1);
                    let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                    assert_eq!(
                        lhs, rhs,
                        "expected iteration over the Tree \
                         to match our BTreeMap model"
                    );
                }
            }
            Restart => {
                drop(tree);
                tree = sled::Tree::start(config.clone()).unwrap();
            }
        }
    }

    true
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<commit_msg>Add get_gt and get_lt testing to Tree quickcheck<commit_after>use std::{collections::BTreeMap, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::distributions::{Distribution, Gamma};
use rand::{rngs::StdRng, Rng, SeedableRng};

use sled::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Key(vec!{:?})", self.0)
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        }).collect();

    println!("working on ops {:?}", ops);
    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(ops, 0, 100, false)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        let gs = g.size();
        let gamma = Gamma::new(0.3, gs as f64);
        let v = gamma.sample(&mut rand::thread_rng());
        let len = if v > 30000.0 {
            30000
        } else if v < 1. && v > 0.0001 {
            1
        } else {
            v as usize
        };

        let space = g.gen_range(0, gs) + 1;

        let inner =
            (0..len).map(|_| g.gen_range(0, space) as u8).collect();

        Key(inner)
    }

    fn shrink(&self) -> Box<Iterator<Item = Key>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| {
                    Key(underlying[..len].to_vec())
                }),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, usize),
    Restart,
}

use self::Op::*;

impl Op {
    pub fn is_restart(&self) -> bool {
        if let Restart = self {
            true
        } else {
            false
        }
    }
}

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(0, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Set(ref k, v) => {
                Box::new(k.shrink().map(move |sk| Set(sk, v.clone())))
            }
            Merge(ref k, v) => {
                Box::new(k.shrink().map(move |k| Merge(k, v.clone())))
            }
            Get(ref k) => Box::new(k.shrink().map(move |k| Get(k))),
            GetLt(ref k) => {
                Box::new(k.shrink().map(move |k| GetLt(k)))
            }
            GetGt(ref k) => {
                Box::new(k.shrink().map(move |k| GetGt(k)))
            }
            Cas(ref k, old, new) => Box::new(Box::new(
                k.shrink()
                    .map(move |k| Cas(k, old.clone(), new.clone())),
            )),
            Scan(ref k, len) => {
                Box::new(k.shrink().map(move |k| Scan(k, len)))
            }
            Del(ref k) => Box::new(k.shrink().map(|k| Del(k))),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    ((v[0] as u16) << 8) + v[1] as u16
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    let ret = vec![(u >> 8) as u8, u as u8];
    ret
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + to_merge[0] as u16;
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    blink_node_exponent: u8,
    snapshot_after: u8,
    flusher: bool,
) -> bool {
    use self::*;
    let config = ConfigBuilder::new()
        .temporary(true)
        .snapshot_after_ops(snapshot_after as usize + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .io_buf_size(10000)
        .blink_node_split_size(
            1 << std::cmp::min(blink_node_exponent, 20),
        ).cache_capacity(40)
        .cache_bits(0)
        .merge_operator(test_merge_operator)
        .build();

    let mut tree = sled::Tree::start(config.clone()).unwrap();
    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops.into_iter() {
        match op {
            Set(k, v) => {
                tree.set(&k.0, vec![0, v]).unwrap();
                reference.insert(k.clone(), v as u16);
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let mut entry = reference.entry(k).or_insert(0u16);
                *entry += v as u16;
            }
            Get(k) => {
                let res1 = tree
                    .get(&*k.0)
                    .unwrap()
                    .map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree
                    .get_lt(&*k.0)
                    .unwrap()
                    .map(|v| bytes_to_u16(&*v));
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| *key < &k)
                    .nth(0)
                    .map(|(_, v)| *v);
                assert_eq!(res1, res2);
            }
            GetGt(k) => {
                let res1 = tree
                    .get_gt(&*k.0)
                    .unwrap()
                    .map(|v| bytes_to_u16(&*v));
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| *key > &k)
                    .nth(0)
                    .map(|(_, v)| *v);
                println!("tree: {:?}", tree);
                assert_eq!(res1, res2);
            }
            Del(k) => {
                tree.del(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == &*vec![0, old] {
                        tree.set(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(old as u16) {
                    reference.insert(k, new as u16);
                }
            }
            Scan(k, len) => {
                let mut tree_iter = tree
                    .scan(&*k.0)
                    .take(len)
                    .map(|res| res.unwrap());
                let ref_iter = reference
                    .iter()
                    .filter(|&(ref rk, _rv)| **rk >= k)
                    .take(len)
                    .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                for r in ref_iter {
                    let tree_next = tree_iter.next().unwrap();
                    let lhs = (tree_next.0, &*tree_next.1);
                    let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                    assert_eq!(
                        lhs, rhs,
                        "expected iteration over the Tree \
                         to match our BTreeMap model"
                    );
                }
            }
            Restart => {
                drop(tree);
                tree = sled::Tree::start(config.clone()).unwrap();
            }
        }
    }

    true
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<|endoftext|>


<commit_before>#![deny(rust_2018_idioms)]

use std::fs;
use std::io::{Read, Seek, SeekFrom, Write};
use std::sync::mpsc::{sync_channel, TryRecvError};
use std::thread;

#[test]
fn test_basic() {
    let mut tmpfile = tempfile::tempfile().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_cleanup() {
    let tmpdir = tempfile::tempdir().unwrap();
    {
        let mut tmpfile = tempfile::tempfile_in(&tmpdir).unwrap();
        write!(tmpfile, "abcde").unwrap();
    }
    let num_files = fs::read_dir(&tmpdir).unwrap().count();
    assert!(num_files == 0);
}

#[test]
fn test_pathological_cleaner() {
    let tmpdir = tempfile::tempdir().unwrap();
    let (tx, rx) = sync_channel(0);
    let cleaner_thread = thread::spawn(move || {
        let tmp_path = rx.recv().unwrap();
        while rx.try_recv() == Err(TryRecvError::Empty) {
            let files = fs::read_dir(&tmp_path).unwrap();
            for f in files {
                // skip errors
                if f.is_err() {
                    continue;
                }
                let f = f.unwrap();
                let _ = fs::remove_file(f.path());
            }
        }
    });

    // block until cleaner_thread makes progress
    tx.send(tmpdir.path().to_owned()).unwrap();
    // need 40-400 iterations to encounter race with cleaner on original system
    for _ in 0..10000 {
        let mut tmpfile = tempfile::tempfile_in(&tmpdir).unwrap();
        write!(tmpfile, "abcde").unwrap();
        tmpfile.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        tmpfile.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }

    // close the channel to make cleaner_thread exit
    drop(tx);
    cleaner_thread.join().expect("The cleaner thread failed");
}
<commit_msg>test: disable cleaner test on everything but linux<commit_after>#![deny(rust_2018_idioms)]

use std::fs;
use std::io::{Read, Seek, SeekFrom, Write};
use std::sync::mpsc::{sync_channel, TryRecvError};
use std::thread;

#[test]
fn test_basic() {
    let mut tmpfile = tempfile::tempfile().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_cleanup() {
    let tmpdir = tempfile::tempdir().unwrap();
    {
        let mut tmpfile = tempfile::tempfile_in(&tmpdir).unwrap();
        write!(tmpfile, "abcde").unwrap();
    }
    let num_files = fs::read_dir(&tmpdir).unwrap().count();
    assert!(num_files == 0);
}

// Only run this test on Linux. MacOS doesn't like us creating so many files, apparently.
#[cfg(target_os = "linux")]
#[test]
fn test_pathological_cleaner() {
    let tmpdir = tempfile::tempdir().unwrap();
    let (tx, rx) = sync_channel(0);
    let cleaner_thread = thread::spawn(move || {
        let tmp_path = rx.recv().unwrap();
        while rx.try_recv() == Err(TryRecvError::Empty) {
            let files = fs::read_dir(&tmp_path).unwrap();
            for f in files {
                // skip errors
                if f.is_err() {
                    continue;
                }
                let f = f.unwrap();
                let _ = fs::remove_file(f.path());
            }
        }
    });

    // block until cleaner_thread makes progress
    tx.send(tmpdir.path().to_owned()).unwrap();
    // need 40-400 iterations to encounter race with cleaner on original system
    for _ in 0..10000 {
        let mut tmpfile = tempfile::tempfile_in(&tmpdir).unwrap();
        write!(tmpfile, "abcde").unwrap();
        tmpfile.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        tmpfile.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }

    // close the channel to make cleaner_thread exit
    drop(tx);
    cleaner_thread.join().expect("The cleaner thread failed");
}
<|endoftext|>


<commit_before>use std::collections::{HashSet, HashMap};
use torrent::{Bitfield, Info, Peer};

pub struct Picker {
    /// Bitfield of which blocks have been picked
    blocks: Bitfield,
    /// Number of blocks per piece
    scale: u64,
    /// Set of pieces which have blocks waiting. These should be prioritized.
    picked: HashSet<u32>,
    /// Map of block indeces to peers waiting on them. Used for
    /// cancelling in endgame.
    waiting_peers: HashMap<u64, HashSet<usize>>,
    /// Number of blocks left to request. Once this becomes 0
    /// endgame mode is entered.
    endgame_cnt: u64,
    /// Current order of pieces
    pieces: Vec<u32>,
    /// Indices into pieces which indicate priority bounds
    priorities: Vec<usize>,
}

impl Picker {
    pub fn new(info: &Info) -> Picker {
        let scale = info.piece_len/16384;
        // The n - 1 piece length, since the last one is (usually) shorter.
        let compl_piece_len = scale * (info.pieces() as usize - 1);
        // the nth piece length
        let mut last_piece_len = info.total_len - info.piece_len as u64 * (info.pieces() as u64 - 1) as u64;
        if last_piece_len % 16384 == 0 {
            last_piece_len /= 16384;
        } else {
            last_piece_len /= 16384;
            last_piece_len += 1;
        }
        let len = compl_piece_len + last_piece_len as usize;
        let blocks = Bitfield::new(len as u64);
        Picker {
            blocks,
            scale: scale as u64,
            endgame_cnt: len as u64,
            waiting_peers: HashMap::new(),
            picked: HashSet::new(),
            pieces: (0..info.pieces() - 1).collect(),
            priorities: vec![0],
        }
    }

    pub fn add_peer(&mut self, peer: &Peer) {
        for idx in peer.pieces.iter() {
            self.piece_available(idx as u32);
        }
    }

    pub fn remove_peer(&mut self, peer: &Peer) {

    }

    pub fn piece_available(&mut self, idx: u32) {
    }

    pub fn pick(&mut self, peer: &Peer) -> Option<(u32, u32)> {
        unimplemented!();
    }

    pub fn completed(&mut self, mut idx: u32, mut offset: u32) -> (bool, HashSet<usize>) {
        unimplemented!();
    }
}
<commit_msg>Add initial pick and completion code for picker<commit_after>use std::collections::{HashSet, HashMap};
use torrent::{Bitfield, Info, Peer};

pub struct Picker {
    /// Bitfield of which blocks have been waiting
    blocks: Bitfield,
    /// Number of blocks per piece
    scale: u64,
    /// Set of pieces which have blocks waiting. These should be prioritized.
    waiting: HashSet<u64>,
    /// Map of block indeces to peers waiting on them. Used for
    /// cancelling in endgame.
    waiting_peers: HashMap<u64, HashSet<usize>>,
    /// Number of blocks left to request. Once this becomes 0
    /// endgame mode is entered.
    endgame_cnt: u64,
    /// Current order of pieces
    pieces: Vec<u32>,
    /// Indices into pieces which indicate priority bounds
    priorities: Vec<usize>,
}

impl Picker {
    pub fn new(info: &Info) -> Picker {
        let scale = info.piece_len/16384;
        // The n - 1 piece length, since the last one is (usually) shorter.
        let compl_piece_len = scale * (info.pieces() as usize - 1);
        // the nth piece length
        let mut last_piece_len = info.total_len - info.piece_len as u64 * (info.pieces() as u64 - 1) as u64;
        if last_piece_len % 16384 == 0 {
            last_piece_len /= 16384;
        } else {
            last_piece_len /= 16384;
            last_piece_len += 1;
        }
        let len = compl_piece_len + last_piece_len as usize;
        let blocks = Bitfield::new(len as u64);
        Picker {
            blocks,
            scale: scale as u64,
            endgame_cnt: len as u64,
            waiting_peers: HashMap::new(),
            waiting: HashSet::new(),
            pieces: (0..info.pieces() - 1).collect(),
            priorities: vec![0],
        }
    }

    pub fn add_peer(&mut self, peer: &Peer) {
        for idx in peer.pieces.iter() {
            self.piece_available(idx as u32);
        }
    }

    pub fn remove_peer(&mut self, peer: &Peer) {

    }

    pub fn piece_available(&mut self, idx: u32) {
    }

    pub fn pick(&mut self, peer: &Peer) -> Option<(u32, u32)> {
        // TODO: handle endgame
        for pidx in self.pieces.iter() {
            if peer.pieces.has_bit(*pidx as u64) {
                for bidx in 0..self.scale {
                    let block = *pidx as u64 * self.scale + bidx;
                    if !self.blocks.has_bit(block) {
                        self.blocks.set_bit(block);
                        let mut hs = HashSet::with_capacity(1);
                        hs.insert(peer.id);
                        self.waiting_peers.insert(block, hs);
                        self.waiting.insert(block);
                        return Some((*pidx as u32, bidx as u32 * 16384));
                    }
                }
            }
        }
        None
    }

    pub fn completed(&mut self, idx: u32, offset: u32) -> (bool, HashSet<usize>) {
        let idx: u64 = idx as u64 * self.scale;
        let offset: u64 = offset as u64/16384;
        let block = idx + offset;
        self.waiting.remove(&block);
        let peers = self.waiting_peers.remove(&block).unwrap_or(HashSet::with_capacity(0));
        for i in 0..self.scale {
            if (idx + i < self.blocks.len() && !self.blocks.has_bit(idx + i)) || self.waiting.contains(&(idx + i)) {
                return (false, peers);
            }
        }
        (true, peers)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rustc_serialize::json::{Json, ToJson, Object};
use std::collections::HashMap;
use {Ring, GeoJsonResult};

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
#[derive(RustcEncodable, Clone, Debug)]
pub struct MultiLineString {
    pub coordinates: Vec<Ring>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> Json {
        let mut d = HashMap::new();
        d.insert(format!("type"), "MultiLineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}

impl MultiLineString {
    pub fn from_json(json_geometry: &Object) -> GeoJsonResult<MultiLineString> {
        let mut coordinates = vec![];
        for json_ring in expect_array!(expect_property!(json_geometry, "coordinates", "missing 'coordinates' field")) {
            coordinates.push(try!(Ring::from_json(expect_array!(json_ring))));
        }
        return Ok(MultiLineString{coordinates: coordinates});
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::{ToJson, Json};
    use {MultiLineString, Pos, Ring};

    #[test]
    fn test_multi_line_string_to_json() {
        let multi_line_string = MultiLineString{coordinates: vec![
            Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
            Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
            ]};
        let json_string = format!("{}", multi_line_string.to_json());
        assert_eq!("{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"MultiLineString\"}", json_string);
    }

    #[test]
    fn test_multi_line_string_from_json() {
        let json_string = "{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"MultiLineString\"}";
        let json_doc = Json::from_str(json_string).unwrap();
        let multi_line_string = MultiLineString::from_json(json_doc.as_object().unwrap()).ok().unwrap();
        assert_eq!(json_string, format!("{}", multi_line_string.to_json()));
    }
}
<commit_msg>Replace MultiLineString Ring with Pos<commit_after>// Copyright 2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rustc_serialize::json::{Json, ToJson, Object};
use std::collections::HashMap;
use {Pos, GeoJsonResult};

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
#[derive(RustcEncodable, Clone, Debug)]
pub struct MultiLineString {
    pub coordinates: Vec<Vec<Pos>>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> Json {
        let mut d = HashMap::new();
        d.insert(format!("type"), "MultiLineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}

impl MultiLineString {
    pub fn from_json(json_geometry: &Object) -> GeoJsonResult<MultiLineString> {
        let mut coordinates = vec![];
        for json_array in expect_array!(expect_property!(json_geometry, "coordinates", "missing 'coordinates' field")) {
            let mut inner_coords = vec![];
            for coordinate in expect_array!(json_array) {
                inner_coords.push(try!(Pos::from_json(expect_array!(coordinate))))
            }
            coordinates.push(inner_coords);
        }
        return Ok(MultiLineString{coordinates: coordinates});
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::{ToJson, Json};
    use {MultiLineString, Pos};

    #[test]
    fn test_multi_line_string_to_json() {
        let multi_line_string = MultiLineString{coordinates: vec![
            vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])],
            vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])]
        ]};
        let json_string = format!("{}", multi_line_string.to_json());
        assert_eq!("{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"MultiLineString\"}", json_string);
    }

    #[test]
    fn test_multi_line_string_from_json() {
        let json_string = "{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"MultiLineString\"}";
        let json_doc = Json::from_str(json_string).unwrap();
        let multi_line_string = MultiLineString::from_json(json_doc.as_object().unwrap()).ok().unwrap();
        assert_eq!(json_string, format!("{}", multi_line_string.to_json()));
    }
}
<|endoftext|>


<commit_before>s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_amp: *mut ::c_void,
        pub shm_lkcnt: ::c_ushort,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_cnattch: ::c_ulong,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_pad4: [i64; 4],
    }

    pub struct fil_info {
        pub fi_flags: ::c_int,
        pub fi_pos: ::c_int,
        pub fi_name: [::c_char; ::FILNAME_MAX as usize],
    }
}

pub const AF_LOCAL: ::c_int = 1; // AF_UNIX
pub const AF_FILE: ::c_int = 1; // AF_UNIX

pub const EFD_SEMAPHORE: ::c_int = 0x1;
pub const EFD_NONBLOCK: ::c_int = 0x800;
pub const EFD_CLOEXEC: ::c_int = 0x80000;

pub const TCP_KEEPIDLE: ::c_int = 34;
pub const TCP_KEEPCNT: ::c_int = 35;
pub const TCP_KEEPINTVL: ::c_int = 36;
pub const TCP_CONGESTION: ::c_int = 37;

// These constants are correct for 64-bit programs or 32-bit programs that are
// not using large-file mode.  If Rust ever supports anything other than 64-bit
// compilation on illumos, this may require adjustment:
pub const F_OFD_GETLK: ::c_int = 47;
pub const F_OFD_SETLK: ::c_int = 48;
pub const F_OFD_SETLKW: ::c_int = 49;
pub const F_FLOCK: ::c_int = 53;
pub const F_FLOCKW: ::c_int = 54;

pub const F_DUPFD_CLOEXEC: ::c_int = 37;
pub const F_DUP2FD_CLOEXEC: ::c_int = 36;

pub const FIL_ATTACH: ::c_int = 0x1;
pub const FIL_DETACH: ::c_int = 0x2;
pub const FIL_LIST: ::c_int = 0x3;
pub const FILNAME_MAX: ::c_int = 32;
pub const FILF_PROG: ::c_int = 0x1;
pub const FILF_AUTO: ::c_int = 0x2;
pub const FILF_BYPASS: ::c_int = 0x4;
pub const SOL_FILTER: ::c_int = 0xfffc;

pub const MADV_PURGE: ::c_int = 9;

pub const MR_HDR_AOUT: ::c_uint = 0x3;

pub const B1000000: ::speed_t = 24;
pub const B1152000: ::speed_t = 25;
pub const B1500000: ::speed_t = 26;
pub const B2000000: ::speed_t = 27;
pub const B2500000: ::speed_t = 28;
pub const B3000000: ::speed_t = 29;
pub const B3500000: ::speed_t = 30;
pub const B4000000: ::speed_t = 31;

// sys/systeminfo.h
pub const SI_ADDRESS_WIDTH: ::c_int = 520;

extern "C" {
    pub fn eventfd(init: ::c_uint, flags: ::c_int) -> ::c_int;

    pub fn mincore(addr: ::caddr_t, len: ::size_t, vec: *mut ::c_char) -> ::c_int;

    pub fn pset_bind_lwp(
        pset: ::psetid_t,
        id: ::id_t,
        pid: ::pid_t,
        opset: *mut ::psetid_t,
    ) -> ::c_int;
    pub fn pset_getloadavg(pset: ::psetid_t, load: *mut ::c_double, num: ::c_int) -> ::c_int;

    pub fn preadv(fd: ::c_int, iov: *const ::iovec, iovcnt: ::c_int, offset: ::off_t) -> ::ssize_t;
    pub fn pwritev(fd: ::c_int, iov: *const ::iovec, iovcnt: ::c_int, offset: ::off_t)
        -> ::ssize_t;
    pub fn getpagesizes2(pagesize: *mut ::size_t, nelem: ::c_int) -> ::c_int;
}
<commit_msg>illumos: Remove obsolete (and private) a.out define<commit_after>s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_amp: *mut ::c_void,
        pub shm_lkcnt: ::c_ushort,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_cnattch: ::c_ulong,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_pad4: [i64; 4],
    }

    pub struct fil_info {
        pub fi_flags: ::c_int,
        pub fi_pos: ::c_int,
        pub fi_name: [::c_char; ::FILNAME_MAX as usize],
    }
}

pub const AF_LOCAL: ::c_int = 1; // AF_UNIX
pub const AF_FILE: ::c_int = 1; // AF_UNIX

pub const EFD_SEMAPHORE: ::c_int = 0x1;
pub const EFD_NONBLOCK: ::c_int = 0x800;
pub const EFD_CLOEXEC: ::c_int = 0x80000;

pub const TCP_KEEPIDLE: ::c_int = 34;
pub const TCP_KEEPCNT: ::c_int = 35;
pub const TCP_KEEPINTVL: ::c_int = 36;
pub const TCP_CONGESTION: ::c_int = 37;

// These constants are correct for 64-bit programs or 32-bit programs that are
// not using large-file mode.  If Rust ever supports anything other than 64-bit
// compilation on illumos, this may require adjustment:
pub const F_OFD_GETLK: ::c_int = 47;
pub const F_OFD_SETLK: ::c_int = 48;
pub const F_OFD_SETLKW: ::c_int = 49;
pub const F_FLOCK: ::c_int = 53;
pub const F_FLOCKW: ::c_int = 54;

pub const F_DUPFD_CLOEXEC: ::c_int = 37;
pub const F_DUP2FD_CLOEXEC: ::c_int = 36;

pub const FIL_ATTACH: ::c_int = 0x1;
pub const FIL_DETACH: ::c_int = 0x2;
pub const FIL_LIST: ::c_int = 0x3;
pub const FILNAME_MAX: ::c_int = 32;
pub const FILF_PROG: ::c_int = 0x1;
pub const FILF_AUTO: ::c_int = 0x2;
pub const FILF_BYPASS: ::c_int = 0x4;
pub const SOL_FILTER: ::c_int = 0xfffc;

pub const MADV_PURGE: ::c_int = 9;

pub const B1000000: ::speed_t = 24;
pub const B1152000: ::speed_t = 25;
pub const B1500000: ::speed_t = 26;
pub const B2000000: ::speed_t = 27;
pub const B2500000: ::speed_t = 28;
pub const B3000000: ::speed_t = 29;
pub const B3500000: ::speed_t = 30;
pub const B4000000: ::speed_t = 31;

// sys/systeminfo.h
pub const SI_ADDRESS_WIDTH: ::c_int = 520;

extern "C" {
    pub fn eventfd(init: ::c_uint, flags: ::c_int) -> ::c_int;

    pub fn mincore(addr: ::caddr_t, len: ::size_t, vec: *mut ::c_char) -> ::c_int;

    pub fn pset_bind_lwp(
        pset: ::psetid_t,
        id: ::id_t,
        pid: ::pid_t,
        opset: *mut ::psetid_t,
    ) -> ::c_int;
    pub fn pset_getloadavg(pset: ::psetid_t, load: *mut ::c_double, num: ::c_int) -> ::c_int;

    pub fn preadv(fd: ::c_int, iov: *const ::iovec, iovcnt: ::c_int, offset: ::off_t) -> ::ssize_t;
    pub fn pwritev(fd: ::c_int, iov: *const ::iovec, iovcnt: ::c_int, offset: ::off_t)
        -> ::ssize_t;
    pub fn getpagesizes2(pagesize: *mut ::size_t, nelem: ::c_int) -> ::c_int;
}
<|endoftext|>