<commit_before>use std::collections::HashMap;
use std::{mem, time};
use std::sync::Arc;
use torrent::{Bitfield, Info, Peer};
use control::cio;

mod rarest;
mod sequential;

#[cfg(test)]
mod tests;

#[derive(Clone, Debug)]
pub struct Picker {
    /// Number of blocks per piece
    scale: u32,
    last_piece_scale: u32,
    last_piece: u32,
    /// Number of detected seeders
    seeders: u16,
    /// Set of pieces which have blocks waiting. These should be prioritized.
    downloading: HashMap<u32, Vec<Downloading>>,
    /// Bitfield of unpicked pieces, not in progress or
    /// completed yet. A set bit is picked, unset is unpicked.
    unpicked: Bitfield,
    /// The current picker in use
    picker: PickerKind,
    /// Piece priorities
    priorities: Vec<u8>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Block {
    pub index: u32,
    pub offset: u32,
}

/// Pickers act solely as piece picking algorithm.
/// They will select the optimal next piece for a peer,
/// and can be told when a piece is complete(or invalid).
#[derive(Clone, Debug)]
enum PickerKind {
    Rarest(rarest::Picker),
    Sequential(sequential::Picker),
}

/// A downloading block and the peers it has been
/// requested from.
#[derive(Clone, Debug)]
struct Downloading {
    offset: u32,
    completed: bool,
    requested: Vec<Request>,
}

/// A request to a peer and the time it was initiated.
#[derive(Clone, Debug)]
struct Request {
    peer: usize,
    requested_at: time::Instant,
}

const MAX_DUP_REQS: usize = 5;
const MAX_DL_Q: usize = 50;
const REQ_TIMEOUT: u64 = 15;

impl Picker {
    /// Creates a new picker, which will select over
    /// the given pieces. The algorithm used for selection
    /// will vary based on the current swarm state, but
    /// will default to rarest first.
    pub fn new(info: &Arc<Info>, pieces: &Bitfield, priorities: &[u8]) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = rarest::Picker::new(pieces);
        let last_piece = info.pieces().saturating_sub(1);
        let lpl = info.piece_len(last_piece);
        let last_piece_scale = if lpl % 16_384 == 0 {
            lpl / 16_384
        } else {
            lpl / 16_384 + 1
        };
        let mut picker = Picker {
            picker: PickerKind::Rarest(picker),
            scale,
            last_piece,
            last_piece_scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
            priorities: vec![3; info.pieces() as usize],
        };
        picker.set_priorities(priorities, info);
        picker
    }

    /// Returns true if the current picker algorithm is sequential
    pub fn is_sequential(&self) -> bool {
        match self.picker {
            PickerKind::Sequential(_) => true,
            _ => false,
        }
    }

    pub fn tick(&mut self) {
        let mut expired = 0;
        self.downloading.values_mut().for_each(|chunks| {
            for chunk in chunks.iter_mut() {
                if !chunk.completed {
                    chunk.requested.retain(|req| {
                        let unexp = req.requested_at.elapsed().as_secs() < REQ_TIMEOUT;
                        if !unexp {
                            expired += 1;
                        }
                        unexp
                    })
                }
            }
        });
        if expired != 0 {
            debug!("Expired {} chunks!", expired);
        }
    }

    /// Attempts to select a block for a peer.
    pub fn pick<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        if let Some(b) = self.pick_expired(peer) {
            return Some(b);
        }
        if self.downloading.len() > MAX_DL_Q {
            if let Some(b) = self.pick_pri(peer) {
                return Some(b);
            }
        }

        let piece = match self.picker {
            PickerKind::Sequential(ref mut p) => p.pick(peer),
            PickerKind::Rarest(ref mut p) => p.pick(peer),
        };
        piece
            .and_then(|p| self.pick_piece(p, peer.id()))
            .or_else(|| self.pick_downloading(peer))
    }

    /// Attempts to pick an expired block
    fn pick_expired<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        // TODO: Use some form of heuristic here to say "we expect to have
        // downloaded some pieces by X, hit the picker with a tick which checks
        // that, flags shit as invalid, and then does a double request
        None
    }

    /// Picks a block from a given piece for a peer
    fn pick_piece(&mut self, piece: u32, id: usize) -> Option<Block> {
        self.downloading.entry(piece).or_insert_with(|| vec![]);
        let dl = self.downloading.get_mut(&piece).unwrap();
        let offset = dl.len() as u32 * 16_384;
        dl.push(Downloading {
            offset,
            completed: false,
            requested: vec![Request::new(id)],
        });

        if dl.len() == self.scale as usize
            || (piece == self.last_piece && dl.len() == self.last_piece_scale as usize)
        {
            match self.picker {
                PickerKind::Sequential(ref mut p) => p.completed(piece),
                PickerKind::Rarest(ref mut p) => p.completed(piece),
            }
            self.unpicked.set_bit(u64::from(piece));
        }
        Some(Block {
            index: piece,
            offset,
        })
    }

    /// Attempts to pick the highest priority piece in the dl q
    fn pick_pri<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        let pri = &mut self.priorities;
        self.downloading
            .iter_mut()
            .max_by_key(|&(idx, _)| pri[*idx as usize])
            .and_then(|(idx, dl)| {
                dl.iter_mut()
                    .find(|r| {
                        !r.completed && r.requested.len() < MAX_DUP_REQS
                            && r.requested.iter().all(|req| req.peer != peer.id())
                    })
                    .map(|r| {
                        r.requested.push(Request::new(peer.id()));
                        Block::new(*idx, r.offset)
                    })
            })
    }

    /// Attempts to pick an already requested block
    fn pick_downloading<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        for (idx, dl) in &mut self.downloading {
            if peer.pieces().has_bit(u64::from(*idx)) {
                let r = dl.iter_mut()
                    .find(|r| {
                        !r.completed && r.requested.len() < MAX_DUP_REQS
                            && r.requested.iter().all(|req| req.peer != peer.id())
                    })
                    .map(|r| {
                        r.requested.push(Request::new(peer.id()));
                        Block::new(*idx, r.offset)
                    });
                if r.is_some() {
                    return r;
                }
            }
        }
        None
    }

    /// Marks a block as completed. Returns a result indicating if the block
    /// was actually requested, the success value containing a bool indicating
    /// if the block is complete, and a vector of peers from which the block
    /// was requested(for cancellation).
    pub fn completed(&mut self, b: Block) -> Result<(bool, Vec<usize>), ()> {
        // Find the block in our downloading blocks, mark as true,
        // and extract the current peer list for return.
        let res = self.downloading
            .get_mut(&b.index)
            .and_then(|dl| {
                dl.iter_mut()
                    .find(|r| r.offset == b.offset)
                    .map(|r| r.complete())
            })
            .map(|r| r.into_iter().map(|e| e.peer).collect());

        // If we've requested every single block for this piece and they're all complete, remove it
        // and report completion
        let scale = self.scale;
        let lp = self.last_piece;
        let lps = self.last_piece_scale;
        let complete = self.downloading
            .get_mut(&b.index)
            .map(|r| {
                (r.len() as u32 == scale || (b.index == lp && r.len() as u32 == lps))
                    && r.iter().all(|d| d.completed)
            })
            .unwrap_or(false);

        if complete {
            self.downloading.remove(&b.index);
        }

        res.map(|r| (complete, r)).ok_or(())
    }

    pub fn have_block(&mut self, b: Block) -> bool {
        self.downloading
            .get_mut(&b.index)
            .and_then(|dl| {
                dl.iter()
                    .find(|r| r.offset == b.offset)
                    .map(|r| r.completed)
            })
            .unwrap_or(false)
    }

    /// Invalidates a piece
    pub fn invalidate_piece(&mut self, idx: u32) {
        match self.picker {
            PickerKind::Sequential(ref mut p) => p.incomplete(idx),
            PickerKind::Rarest(ref mut p) => p.incomplete(idx),
        }
        self.unpicked.unset_bit(u64::from(idx));
    }

    pub fn piece_available(&mut self, idx: u32) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.piece_available(idx);
        }
    }

    pub fn add_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if peer.pieces().complete() {
            self.seeders += 1;
        }
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.add_peer(peer);
        }
    }

    pub fn remove_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.remove_peer(peer);
        }

        for piece in self.downloading.values_mut() {
            for block in piece {
                block.requested.retain(|req| req.peer != peer.id())
            }
        }
    }

    /// Alters the picker to sequential/non sequential. If changing
    /// from sequential to non sequential, peer state will need to be loaded
    /// after this.
    pub fn change_picker(&mut self, sequential: bool) {
        self.picker = if sequential {
            PickerKind::Sequential(sequential::Picker::new(&self.unpicked))
        } else {
            PickerKind::Rarest(rarest::Picker::new(&self.unpicked))
        };
        self.apply_priorities();
        for i in self.downloading.keys() {
            if let PickerKind::Rarest(ref mut p) = self.picker {
                p.inc_pri(*i);
            }
        }
    }

    pub fn set_priorities(&mut self, pri: &[u8], info: &Arc<Info>) {
        self.unapply_priorities();
        self.priorities = generate_piece_pri(pri, info);
        self.apply_priorities();
    }

    pub fn apply_priorities(&mut self) {
        if self.is_sequential() {
            let mut pieces = [vec![], vec![], vec![], vec![], vec![], vec![]];
            for (piece, pri) in self.priorities.iter().enumerate() {
                pieces[*pri as usize].push(piece as u32);
            }
            self.picker = PickerKind::Sequential(sequential::Picker::new_pri(pieces));
        } else {
            for (piece, pri) in self.priorities.iter().enumerate() {
                for _ in 0..*pri {
                    if let PickerKind::Rarest(ref mut p) = self.picker {
                        p.piece_unavailable(piece as u32);
                    }
                }

                if *pri == 0 {
                    match self.picker {
                        PickerKind::Rarest(ref mut p) => p.completed(piece as u32),
                        _ => unreachable!(),
                    }
                }
            }
        }
    }

    pub fn unapply_priorities(&mut self) {
        if !self.is_sequential() {
            for (piece, pri) in self.priorities.iter().enumerate() {
                for _ in 0..*pri {
                    if let PickerKind::Rarest(ref mut p) = self.picker {
                        p.piece_available(piece as u32);
                    }
                }

                if *pri == 0 {
                    match self.picker {
                        PickerKind::Rarest(ref mut p) => p.incomplete(piece as u32),
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}

fn generate_piece_pri(pri: &[u8], info: &Arc<Info>) -> Vec<u8> {
    // Map piece -> priority
    let mut priorities = Vec::with_capacity(info.pieces() as usize);
    // If a piece is completely in a file, just assign that pri.
    // Otherwise mark it as the higher pri piece
    for p in 0..info.pieces() {
        let max = Info::piece_disk_locs(&info, p)
            .map(|loc| pri[loc.file])
            .max()
            .expect("Piece must have locations!");
        priorities.push(max);
    }
    priorities
}

#[cfg(test)]
impl Picker {
    pub fn new_rarest(info: &Info, pieces: &Bitfield) -> Picker {
        Picker::new(
            &Arc::new(info.clone()),
            pieces,
            &vec![3u8; info.files.len()],
        )
    }

    pub fn new_sequential(info: &Info, pieces: &Bitfield) -> Picker {
        let mut p = Picker::new(
            &Arc::new(info.clone()),
            pieces,
            &vec![3u8; info.files.len()],
        );
        p.change_picker(true);
        p
    }
}

impl Block {
    pub fn new(index: u32, offset: u32) -> Block {
        Block { index, offset }
    }
}

impl Request {
    fn new(peer: usize) -> Request {
        Request {
            peer,
            requested_at: time::Instant::now(),
        }
    }
}

impl Downloading {
    fn complete(&mut self) -> Vec<Request> {
        self.completed = true;
        mem::replace(&mut self.requested, Vec::with_capacity(0))
    }
}
<commit_msg>Use loop over iterator<commit_after>use std::collections::HashMap;
use std::{mem, time};
use std::sync::Arc;
use torrent::{Bitfield, Info, Peer};
use control::cio;

mod rarest;
mod sequential;

#[cfg(test)]
mod tests;

#[derive(Clone, Debug)]
pub struct Picker {
    /// Number of blocks per piece
    scale: u32,
    last_piece_scale: u32,
    last_piece: u32,
    /// Number of detected seeders
    seeders: u16,
    /// Set of pieces which have blocks waiting. These should be prioritized.
    downloading: HashMap<u32, Vec<Downloading>>,
    /// Bitfield of unpicked pieces, not in progress or
    /// completed yet. A set bit is picked, unset is unpicked.
    unpicked: Bitfield,
    /// The current picker in use
    picker: PickerKind,
    /// Piece priorities
    priorities: Vec<u8>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Block {
    pub index: u32,
    pub offset: u32,
}

/// Pickers act solely as piece picking algorithm.
/// They will select the optimal next piece for a peer,
/// and can be told when a piece is complete(or invalid).
#[derive(Clone, Debug)]
enum PickerKind {
    Rarest(rarest::Picker),
    Sequential(sequential::Picker),
}

/// A downloading block and the peers it has been
/// requested from.
#[derive(Clone, Debug)]
struct Downloading {
    offset: u32,
    completed: bool,
    requested: Vec<Request>,
}

/// A request to a peer and the time it was initiated.
#[derive(Clone, Debug)]
struct Request {
    peer: usize,
    requested_at: time::Instant,
}

const MAX_DUP_REQS: usize = 5;
const MAX_DL_Q: usize = 50;
const REQ_TIMEOUT: u64 = 15;

impl Picker {
    /// Creates a new picker, which will select over
    /// the given pieces. The algorithm used for selection
    /// will vary based on the current swarm state, but
    /// will default to rarest first.
    pub fn new(info: &Arc<Info>, pieces: &Bitfield, priorities: &[u8]) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = rarest::Picker::new(pieces);
        let last_piece = info.pieces().saturating_sub(1);
        let lpl = info.piece_len(last_piece);
        let last_piece_scale = if lpl % 16_384 == 0 {
            lpl / 16_384
        } else {
            lpl / 16_384 + 1
        };
        let mut picker = Picker {
            picker: PickerKind::Rarest(picker),
            scale,
            last_piece,
            last_piece_scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
            priorities: vec![3; info.pieces() as usize],
        };
        picker.set_priorities(priorities, info);
        picker
    }

    /// Returns true if the current picker algorithm is sequential
    pub fn is_sequential(&self) -> bool {
        match self.picker {
            PickerKind::Sequential(_) => true,
            _ => false,
        }
    }

    pub fn tick(&mut self) {
        let mut expired = 0;
        for chunks in self.downloading.values_mut() {
            for chunk in chunks.iter_mut() {
                if !chunk.completed {
                    chunk.requested.retain(|req| {
                        let unexp = req.requested_at.elapsed().as_secs() < REQ_TIMEOUT;
                        if !unexp {
                            expired += 1;
                        }
                        unexp
                    })
                }
            }
        }
        if expired != 0 {
            debug!("Expired {} chunks!", expired);
        }
    }

    /// Attempts to select a block for a peer.
    pub fn pick<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        if let Some(b) = self.pick_expired(peer) {
            return Some(b);
        }
        if self.downloading.len() > MAX_DL_Q {
            if let Some(b) = self.pick_pri(peer) {
                return Some(b);
            }
        }

        let piece = match self.picker {
            PickerKind::Sequential(ref mut p) => p.pick(peer),
            PickerKind::Rarest(ref mut p) => p.pick(peer),
        };
        piece
            .and_then(|p| self.pick_piece(p, peer.id()))
            .or_else(|| self.pick_downloading(peer))
    }

    /// Attempts to pick an expired block
    fn pick_expired<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        // TODO: Use some form of heuristic here to say "we expect to have
        // downloaded some pieces by X, hit the picker with a tick which checks
        // that, flags shit as invalid, and then does a double request
        None
    }

    /// Picks a block from a given piece for a peer
    fn pick_piece(&mut self, piece: u32, id: usize) -> Option<Block> {
        self.downloading.entry(piece).or_insert_with(|| vec![]);
        let dl = self.downloading.get_mut(&piece).unwrap();
        let offset = dl.len() as u32 * 16_384;
        dl.push(Downloading {
            offset,
            completed: false,
            requested: vec![Request::new(id)],
        });

        if dl.len() == self.scale as usize
            || (piece == self.last_piece && dl.len() == self.last_piece_scale as usize)
        {
            match self.picker {
                PickerKind::Sequential(ref mut p) => p.completed(piece),
                PickerKind::Rarest(ref mut p) => p.completed(piece),
            }
            self.unpicked.set_bit(u64::from(piece));
        }
        Some(Block {
            index: piece,
            offset,
        })
    }

    /// Attempts to pick the highest priority piece in the dl q
    fn pick_pri<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        let pri = &mut self.priorities;
        self.downloading
            .iter_mut()
            .max_by_key(|&(idx, _)| pri[*idx as usize])
            .and_then(|(idx, dl)| {
                dl.iter_mut()
                    .find(|r| {
                        !r.completed && r.requested.len() < MAX_DUP_REQS
                            && r.requested.iter().all(|req| req.peer != peer.id())
                    })
                    .map(|r| {
                        r.requested.push(Request::new(peer.id()));
                        Block::new(*idx, r.offset)
                    })
            })
    }

    /// Attempts to pick an already requested block
    fn pick_downloading<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        for (idx, dl) in &mut self.downloading {
            if peer.pieces().has_bit(u64::from(*idx)) {
                let r = dl.iter_mut()
                    .find(|r| {
                        !r.completed && r.requested.len() < MAX_DUP_REQS
                            && r.requested.iter().all(|req| req.peer != peer.id())
                    })
                    .map(|r| {
                        r.requested.push(Request::new(peer.id()));
                        Block::new(*idx, r.offset)
                    });
                if r.is_some() {
                    return r;
                }
            }
        }
        None
    }

    /// Marks a block as completed. Returns a result indicating if the block
    /// was actually requested, the success value containing a bool indicating
    /// if the block is complete, and a vector of peers from which the block
    /// was requested(for cancellation).
    pub fn completed(&mut self, b: Block) -> Result<(bool, Vec<usize>), ()> {
        // Find the block in our downloading blocks, mark as true,
        // and extract the current peer list for return.
        let res = self.downloading
            .get_mut(&b.index)
            .and_then(|dl| {
                dl.iter_mut()
                    .find(|r| r.offset == b.offset)
                    .map(|r| r.complete())
            })
            .map(|r| r.into_iter().map(|e| e.peer).collect());

        // If we've requested every single block for this piece and they're all complete, remove it
        // and report completion
        let scale = self.scale;
        let lp = self.last_piece;
        let lps = self.last_piece_scale;
        let complete = self.downloading
            .get_mut(&b.index)
            .map(|r| {
                (r.len() as u32 == scale || (b.index == lp && r.len() as u32 == lps))
                    && r.iter().all(|d| d.completed)
            })
            .unwrap_or(false);

        if complete {
            self.downloading.remove(&b.index);
        }

        res.map(|r| (complete, r)).ok_or(())
    }

    pub fn have_block(&mut self, b: Block) -> bool {
        self.downloading
            .get_mut(&b.index)
            .and_then(|dl| {
                dl.iter()
                    .find(|r| r.offset == b.offset)
                    .map(|r| r.completed)
            })
            .unwrap_or(false)
    }

    /// Invalidates a piece
    pub fn invalidate_piece(&mut self, idx: u32) {
        match self.picker {
            PickerKind::Sequential(ref mut p) => p.incomplete(idx),
            PickerKind::Rarest(ref mut p) => p.incomplete(idx),
        }
        self.unpicked.unset_bit(u64::from(idx));
    }

    pub fn piece_available(&mut self, idx: u32) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.piece_available(idx);
        }
    }

    pub fn add_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if peer.pieces().complete() {
            self.seeders += 1;
        }
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.add_peer(peer);
        }
    }

    pub fn remove_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.remove_peer(peer);
        }

        for piece in self.downloading.values_mut() {
            for block in piece {
                block.requested.retain(|req| req.peer != peer.id())
            }
        }
    }

    /// Alters the picker to sequential/non sequential. If changing
    /// from sequential to non sequential, peer state will need to be loaded
    /// after this.
    pub fn change_picker(&mut self, sequential: bool) {
        self.picker = if sequential {
            PickerKind::Sequential(sequential::Picker::new(&self.unpicked))
        } else {
            PickerKind::Rarest(rarest::Picker::new(&self.unpicked))
        };
        self.apply_priorities();
        for i in self.downloading.keys() {
            if let PickerKind::Rarest(ref mut p) = self.picker {
                p.inc_pri(*i);
            }
        }
    }

    pub fn set_priorities(&mut self, pri: &[u8], info: &Arc<Info>) {
        self.unapply_priorities();
        self.priorities = generate_piece_pri(pri, info);
        self.apply_priorities();
    }

    pub fn apply_priorities(&mut self) {
        if self.is_sequential() {
            let mut pieces = [vec![], vec![], vec![], vec![], vec![], vec![]];
            for (piece, pri) in self.priorities.iter().enumerate() {
                pieces[*pri as usize].push(piece as u32);
            }
            self.picker = PickerKind::Sequential(sequential::Picker::new_pri(pieces));
        } else {
            for (piece, pri) in self.priorities.iter().enumerate() {
                for _ in 0..*pri {
                    if let PickerKind::Rarest(ref mut p) = self.picker {
                        p.piece_unavailable(piece as u32);
                    }
                }

                if *pri == 0 {
                    match self.picker {
                        PickerKind::Rarest(ref mut p) => p.completed(piece as u32),
                        _ => unreachable!(),
                    }
                }
            }
        }
    }

    pub fn unapply_priorities(&mut self) {
        if !self.is_sequential() {
            for (piece, pri) in self.priorities.iter().enumerate() {
                for _ in 0..*pri {
                    if let PickerKind::Rarest(ref mut p) = self.picker {
                        p.piece_available(piece as u32);
                    }
                }

                if *pri == 0 {
                    match self.picker {
                        PickerKind::Rarest(ref mut p) => p.incomplete(piece as u32),
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}

fn generate_piece_pri(pri: &[u8], info: &Arc<Info>) -> Vec<u8> {
    // Map piece -> priority
    let mut priorities = Vec::with_capacity(info.pieces() as usize);
    // If a piece is completely in a file, just assign that pri.
    // Otherwise mark it as the higher pri piece
    for p in 0..info.pieces() {
        let max = Info::piece_disk_locs(&info, p)
            .map(|loc| pri[loc.file])
            .max()
            .expect("Piece must have locations!");
        priorities.push(max);
    }
    priorities
}

#[cfg(test)]
impl Picker {
    pub fn new_rarest(info: &Info, pieces: &Bitfield) -> Picker {
        Picker::new(
            &Arc::new(info.clone()),
            pieces,
            &vec![3u8; info.files.len()],
        )
    }

    pub fn new_sequential(info: &Info, pieces: &Bitfield) -> Picker {
        let mut p = Picker::new(
            &Arc::new(info.clone()),
            pieces,
            &vec![3u8; info.files.len()],
        );
        p.change_picker(true);
        p
    }
}

impl Block {
    pub fn new(index: u32, offset: u32) -> Block {
        Block { index, offset }
    }
}

impl Request {
    fn new(peer: usize) -> Request {
        Request {
            peer,
            requested_at: time::Instant::now(),
        }
    }
}

impl Downloading {
    fn complete(&mut self) -> Vec<Request> {
        self.completed = true;
        mem::replace(&mut self.requested, Vec::with_capacity(0))
    }
}
<|endoftext|>


<commit_before>extern crate handlebars;
extern crate rustc_serialize;

use std::path::{PathBuf, Path};
use std::collections::BTreeMap;

use self::rustc_serialize::json::{self, ToJson};
use self::handlebars::{Handlebars, RenderError, RenderContext, Helper, Context, Renderable};

// Handlebars helper for navigation

pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    debug!("[fn]: previous (handlebars helper)");

    debug!("[*]: Get data from context");
    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let chapters = c.navigate(rc.get_path(), "chapters");

    let current = c.navigate(rc.get_path(), "path")
        .to_string()
        .replace("\"", "");

    let path_to_root = PathBuf::from(
        c.navigate(rc.get_path(), "path_to_root")
            .to_string()
            .replace("\"", "")
    );

    debug!("[*]: Decode chapters from JSON");
    // Decode json format
    let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
        Ok(data) => data,
        Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
    };
    let mut previous: Option<BTreeMap<String, String>> = None;

    debug!("[*]: Search for current Chapter");
    // Search for current chapter and return previous entry
    for item in decoded {

        match item.get("path") {
            Some(path) if path.len() > 0 => {
                if path == &current {

                    debug!("[*]: Found current chapter");
                    if let Some(previous) = previous{

                        debug!("[*]: Creating BTreeMap to inject in context");
                        // Create new BTreeMap to extend the context: 'title' and 'link'
                        let mut previous_chapter = BTreeMap::new();

                        // Chapter title
                        match previous.get("name") {
                            Some(n) => {
                                debug!("[*]: Inserting title: {}", n);
                                previous_chapter.insert("title".to_string(), n.to_json())
                            },
                            None => {
                                debug!("[*]: No title found for chapter");
                                return Err(RenderError{ desc: "No title found for chapter in JSON data" })
                            }
                        };

                        // Chapter link

                        match previous.get("path") {
                            Some(p) => {
                                let path = path_to_root.join(Path::new(p).with_extension("html"));
                                debug!("[*]: Inserting link: {:?}", path);

                                match path.to_str() {
                                    Some(p) => { previous_chapter.insert("link".to_string(), p.to_json()); },
                                    None => return Err(RenderError{ desc: "Link could not be converted to str" })
                                }
                            },
                            None => return Err(RenderError{ desc: "No path found for chapter in JSON data" })
                        }

                        debug!("[*]: Inject in context");
                        // Inject in current context
                        let updated_context = c.extend(&previous_chapter);

                        debug!("[*]: Render template");
                        // Render template
                        match _h.template() {
                            Some(t) => {
                                try!(t.render(&updated_context, r, rc));
                            },
                            None => return Err(RenderError{ desc: "Error with the handlebars template" })
                        }

                    }

                    break;
                }
                else {
                    previous = Some(item.clone());
                }
            },
            _ => continue,

        }

    }

    Ok(())
}

pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    debug!("[fn]: next (handlebars helper)");

    debug!("[*]: Get data from context");
    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let chapters = c.navigate(rc.get_path(), "chapters");

    let current = c.navigate(rc.get_path(), "path")
        .to_string()
        .replace("\"", "");

    let path_to_root = PathBuf::from(
        c.navigate(rc.get_path(), "path_to_root")
            .to_string()
            .replace("\"", "")
    );

    debug!("[*]: Decode chapters from JSON");
    // Decode json format
    let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
        Ok(data) => data,
        Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
    };
    let mut previous: Option<BTreeMap<String, String>> = None;

    debug!("[*]: Search for current Chapter");
    // Search for current chapter and return previous entry
    for item in decoded {

        match item.get("path") {

            Some(path) if path.len() > 0 => {

                if let Some(previous) = previous {

                    let path = match previous.get("path") {
                        Some(p) => p,
                        None => return Err(RenderError{ desc: "No path found for chapter in JSON data"})
                    };

                    if path == &current {

                        debug!("[*]: Found current chapter");
                        debug!("[*]: Creating BTreeMap to inject in context");
                        // Create new BTreeMap to extend the context: 'title' and 'link'
                        let mut next_chapter = BTreeMap::new();

                        match item.get("name") {
                            Some(n) => {
                                debug!("[*]: Inserting title: {}", n);
                                next_chapter.insert("title".to_string(), n.to_json());
                            }
                            None => return Err(RenderError{ desc: "No title found for chapter in JSON data"})
                        }

                        let link = path_to_root.join(Path::new(path).with_extension("html"));
                        debug!("[*]: Inserting link: {:?}", link);

                        match link.to_str() {
                            Some(l) => { next_chapter.insert("link".to_string(), l.to_json()); },
                            None => return Err(RenderError{ desc: "Link could not converted to str"})
                        }

                        debug!("[*]: Inject in context");
                        // Inject in current context
                        let updated_context = c.extend(&next_chapter);

                        debug!("[*]: Render template");

                        // Render template
                        match _h.template() {
                            Some(t) => {
                                try!(t.render(&updated_context, r, rc));
                            },
                            None => return Err(RenderError{ desc: "Error with the handlebars template" })
                        }

                        break
                    }
                }

                previous = Some(item.clone());
            },

            _ => continue,
        }
    }
    Ok(())
}
<commit_msg>Fix #40 where next helper returned a link to the current chapter instead of the next<commit_after>extern crate handlebars;
extern crate rustc_serialize;

use std::path::{PathBuf, Path};
use std::collections::BTreeMap;

use self::rustc_serialize::json::{self, ToJson};
use self::handlebars::{Handlebars, RenderError, RenderContext, Helper, Context, Renderable};

// Handlebars helper for navigation

pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    debug!("[fn]: previous (handlebars helper)");

    debug!("[*]: Get data from context");
    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let chapters = c.navigate(rc.get_path(), "chapters");

    let current = c.navigate(rc.get_path(), "path")
        .to_string()
        .replace("\"", "");

    let path_to_root = PathBuf::from(
        c.navigate(rc.get_path(), "path_to_root")
            .to_string()
            .replace("\"", "")
    );

    debug!("[*]: Decode chapters from JSON");
    // Decode json format
    let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
        Ok(data) => data,
        Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
    };
    let mut previous: Option<BTreeMap<String, String>> = None;

    debug!("[*]: Search for current Chapter");
    // Search for current chapter and return previous entry
    for item in decoded {

        match item.get("path") {
            Some(path) if path.len() > 0 => {
                if path == &current {

                    debug!("[*]: Found current chapter");
                    if let Some(previous) = previous{

                        debug!("[*]: Creating BTreeMap to inject in context");
                        // Create new BTreeMap to extend the context: 'title' and 'link'
                        let mut previous_chapter = BTreeMap::new();

                        // Chapter title
                        match previous.get("name") {
                            Some(n) => {
                                debug!("[*]: Inserting title: {}", n);
                                previous_chapter.insert("title".to_string(), n.to_json())
                            },
                            None => {
                                debug!("[*]: No title found for chapter");
                                return Err(RenderError{ desc: "No title found for chapter in JSON data" })
                            }
                        };

                        // Chapter link

                        match previous.get("path") {
                            Some(p) => {
                                let path = path_to_root.join(Path::new(p).with_extension("html"));
                                debug!("[*]: Inserting link: {:?}", path);

                                match path.to_str() {
                                    Some(p) => { previous_chapter.insert("link".to_string(), p.to_json()); },
                                    None => return Err(RenderError{ desc: "Link could not be converted to str" })
                                }
                            },
                            None => return Err(RenderError{ desc: "No path found for chapter in JSON data" })
                        }

                        debug!("[*]: Inject in context");
                        // Inject in current context
                        let updated_context = c.extend(&previous_chapter);

                        debug!("[*]: Render template");
                        // Render template
                        match _h.template() {
                            Some(t) => {
                                try!(t.render(&updated_context, r, rc));
                            },
                            None => return Err(RenderError{ desc: "Error with the handlebars template" })
                        }

                    }

                    break;
                }
                else {
                    previous = Some(item.clone());
                }
            },
            _ => continue,

        }

    }

    Ok(())
}

pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    debug!("[fn]: next (handlebars helper)");

    debug!("[*]: Get data from context");
    // get value from context data
    // rc.get_path() is current json parent path, you should always use it like this
    // param is the key of value you want to display
    let chapters = c.navigate(rc.get_path(), "chapters");

    let current = c.navigate(rc.get_path(), "path")
        .to_string()
        .replace("\"", "");

    let path_to_root = PathBuf::from(
        c.navigate(rc.get_path(), "path_to_root")
            .to_string()
            .replace("\"", "")
    );

    debug!("[*]: Decode chapters from JSON");
    // Decode json format
    let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
        Ok(data) => data,
        Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
    };
    let mut previous: Option<BTreeMap<String, String>> = None;

    debug!("[*]: Search for current Chapter");
    // Search for current chapter and return previous entry
    for item in decoded {

        match item.get("path") {

            Some(path) if path.len() > 0 => {

                if let Some(previous) = previous {

                    let previous_path = match previous.get("path") {
                        Some(p) => p,
                        None => return Err(RenderError{ desc: "No path found for chapter in JSON data"})
                    };

                    if previous_path == &current {

                        debug!("[*]: Found current chapter");
                        debug!("[*]: Creating BTreeMap to inject in context");
                        // Create new BTreeMap to extend the context: 'title' and 'link'
                        let mut next_chapter = BTreeMap::new();

                        match item.get("name") {
                            Some(n) => {
                                debug!("[*]: Inserting title: {}", n);
                                next_chapter.insert("title".to_string(), n.to_json());
                            }
                            None => return Err(RenderError{ desc: "No title found for chapter in JSON data"})
                        }

                        let link = path_to_root.join(Path::new(path).with_extension("html"));
                        debug!("[*]: Inserting link: {:?}", link);

                        match link.to_str() {
                            Some(l) => { next_chapter.insert("link".to_string(), l.to_json()); },
                            None => return Err(RenderError{ desc: "Link could not converted to str"})
                        }

                        debug!("[*]: Inject in context");
                        // Inject in current context
                        let updated_context = c.extend(&next_chapter);

                        debug!("[*]: Render template");

                        // Render template
                        match _h.template() {
                            Some(t) => {
                                try!(t.render(&updated_context, r, rc));
                            },
                            None => return Err(RenderError{ desc: "Error with the handlebars template" })
                        }

                        break
                    }
                }

                previous = Some(item.clone());
            },

            _ => continue,
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

struct A { a: int, b: Box<int> }
struct B { a: Box<int>, b: Box<int> }

fn borrow<T>(_: &T) { }

fn move_after_copy() {
    let x = A { a: 1, b: box 2 };
    drop(x.a);
    drop(x.b);
}

fn move_after_fu_copy() {
    let x = A { a: 1, b: box 2 };
    let _y = A { b: box 3, .. x };
    drop(x.b);
}

fn fu_move_after_copy() {
    let x = A { a: 1, b: box 2 };
    drop(x.a);
    let y = A { a: 3, .. x };
    drop(y.b);
}

fn fu_move_after_fu_copy() {
    let x = A { a: 1, b: box 2 };
    let _y = A { b: box 3, .. x };
    let z = A { a: 4, .. x };
    drop(z.b);
}

fn copy_after_move() {
    let x = A { a: 1, b: box 2 };
    drop(x.b);
    drop(x.a);
}

fn copy_after_fu_move() {
    let x = A { a: 1, b: box 2 };
    let y = A { a: 3, .. x };
    drop(x.a);
    drop(y.b);
}

fn fu_copy_after_move() {
    let x = A { a: 1, b: box 2 };
    drop(x.b);
    let _y = A { b: box 3, .. x };
}

fn fu_copy_after_fu_move() {
    let x = A { a: 1, b: box 2 };
    let y = A { a: 3, .. x };
    let _z = A { b: box 3, .. x };
    drop(y.b);
}

fn borrow_after_move() {
    let x = A { a: 1, b: box 2 };
    drop(x.b);
    borrow(&x.a);
}

fn borrow_after_fu_move() {
    let x = A { a: 1, b: box 2 };
    let y = A { a: 3, .. x };
    borrow(&x.a);
    drop(y.b);
}

fn move_after_borrow() {
    let x = A { a: 1, b: box 2 };
    borrow(&x.a);
    drop(x.b);
}

fn fu_move_after_borrow() {
    let x = A { a: 1, b: box 2 };
    borrow(&x.a);
    let y = A { a: 3, .. x };
    drop(y.b);
}

fn mut_borrow_after_mut_borrow() {
    let mut x = A { a: 1, b: box 2 };
    let y = &mut x.a;
    let z = &mut x.b;
    drop(*y);
    drop(**z);
}

fn move_after_move() {
    let x = B { a: box 1, b: box 2 };
    drop(x.a);
    drop(x.b);
}

fn move_after_fu_move() {
    let x = B { a: box 1, b: box 2 };
    let y = B { a: box 3, .. x };
    drop(x.a);
    drop(y.b);
}

fn fu_move_after_move() {
    let x = B { a: box 1, b: box 2 };
    drop(x.a);
    let z = B { a: box 3, .. x };
    drop(z.b);
}

fn fu_move_after_fu_move() {
    let x = B { a: box 1, b: box 2 };
    let y = B { b: box 3, .. x };
    let z = B { a: box 4, .. x };
    drop(y.a);
    drop(z.b);
}

fn copy_after_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x = A { a: 3, b: box 4 };
    drop(*x.b);
}

fn copy_after_field_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x.b = box 3;
    drop(*x.b);
}

fn borrow_after_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x = A { a: 3, b: box 4 };
    borrow(&x.b);
}

fn borrow_after_field_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x.b = box 3;
    borrow(&x.b);
}

fn move_after_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    let y = x.b;
    x = A { a: 3, b: box 4 };
    drop(x.b);
    drop(y);
}

fn move_after_field_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x.b = box 3;
    drop(x.b);
}

fn copy_after_assign_after_uninit() {
    let mut x: A;
    x = A { a: 1, b: box 2 };
    drop(x.a);
}

fn borrow_after_assign_after_uninit() {
    let mut x: A;
    x = A { a: 1, b: box 2 };
    borrow(&x.a);
}

fn move_after_assign_after_uninit() {
    let mut x: A;
    x = A { a: 1, b: box 2 };
    drop(x.b);
}

fn main() {
    move_after_copy();
    move_after_fu_copy();
    fu_move_after_copy();
    fu_move_after_fu_copy();
    copy_after_move();
    copy_after_fu_move();
    fu_copy_after_move();
    fu_copy_after_fu_move();

    borrow_after_move();
    borrow_after_fu_move();
    move_after_borrow();
    fu_move_after_borrow();
    mut_borrow_after_mut_borrow();

    move_after_move();
    move_after_fu_move();
    fu_move_after_move();
    fu_move_after_fu_move();

    copy_after_assign_after_move();
    copy_after_field_assign_after_move();
    borrow_after_assign_after_move();
    borrow_after_field_assign_after_move();
    move_after_assign_after_move();
    move_after_field_assign_after_move();

    copy_after_assign_after_uninit();
    borrow_after_assign_after_uninit();
    move_after_assign_after_uninit();
}

<commit_msg>Make borrowck test functions better match their names<commit_after>// Copyright 2014 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.

struct A { a: int, b: Box<int> }
struct B { a: Box<int>, b: Box<int> }

fn borrow<T>(_: &T) { }

fn move_after_copy() {
    let x = A { a: 1, b: box 2 };
    drop(x.a);
    drop(x.b);
}

fn move_after_fu_copy() {
    let x = A { a: 1, b: box 2 };
    let _y = A { b: box 3, .. x };
    drop(x.b);
}

fn fu_move_after_copy() {
    let x = A { a: 1, b: box 2 };
    drop(x.a);
    let _y = A { a: 3, .. x };
}

fn fu_move_after_fu_copy() {
    let x = A { a: 1, b: box 2 };
    let _y = A { b: box 3, .. x };
    let _z = A { a: 4, .. x };
}

fn copy_after_move() {
    let x = A { a: 1, b: box 2 };
    drop(x.b);
    drop(x.a);
}

fn copy_after_fu_move() {
    let x = A { a: 1, b: box 2 };
    let y = A { a: 3, .. x };
    drop(x.a);
}

fn fu_copy_after_move() {
    let x = A { a: 1, b: box 2 };
    drop(x.b);
    let _y = A { b: box 3, .. x };
}

fn fu_copy_after_fu_move() {
    let x = A { a: 1, b: box 2 };
    let _y = A { a: 3, .. x };
    let _z = A { b: box 3, .. x };
}

fn borrow_after_move() {
    let x = A { a: 1, b: box 2 };
    drop(x.b);
    borrow(&x.a);
}

fn borrow_after_fu_move() {
    let x = A { a: 1, b: box 2 };
    let _y = A { a: 3, .. x };
    borrow(&x.a);
}

fn move_after_borrow() {
    let x = A { a: 1, b: box 2 };
    borrow(&x.a);
    drop(x.b);
}

fn fu_move_after_borrow() {
    let x = A { a: 1, b: box 2 };
    borrow(&x.a);
    let _y = A { a: 3, .. x };
}

fn mut_borrow_after_mut_borrow() {
    let mut x = A { a: 1, b: box 2 };
    let y = &mut x.a;
    let z = &mut x.b;
    drop(*y);
    drop(**z);
}

fn move_after_move() {
    let x = B { a: box 1, b: box 2 };
    drop(x.a);
    drop(x.b);
}

fn move_after_fu_move() {
    let x = B { a: box 1, b: box 2 };
    let y = B { a: box 3, .. x };
    drop(x.a);
}

fn fu_move_after_move() {
    let x = B { a: box 1, b: box 2 };
    drop(x.a);
    let z = B { a: box 3, .. x };
    drop(z.b);
}

fn fu_move_after_fu_move() {
    let x = B { a: box 1, b: box 2 };
    let _y = B { b: box 3, .. x };
    let _z = B { a: box 4, .. x };
}

fn copy_after_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x = A { a: 3, b: box 4 };
    drop(*x.b);
}

fn copy_after_field_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x.b = box 3;
    drop(*x.b);
}

fn borrow_after_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x = A { a: 3, b: box 4 };
    borrow(&x.b);
}

fn borrow_after_field_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x.b = box 3;
    borrow(&x.b);
}

fn move_after_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    let _y = x.b;
    x = A { a: 3, b: box 4 };
    drop(x.b);
}

fn move_after_field_assign_after_move() {
    let mut x = A { a: 1, b: box 2 };
    drop(x.b);
    x.b = box 3;
    drop(x.b);
}

fn copy_after_assign_after_uninit() {
    let mut x: A;
    x = A { a: 1, b: box 2 };
    drop(x.a);
}

fn borrow_after_assign_after_uninit() {
    let mut x: A;
    x = A { a: 1, b: box 2 };
    borrow(&x.a);
}

fn move_after_assign_after_uninit() {
    let mut x: A;
    x = A { a: 1, b: box 2 };
    drop(x.b);
}

fn main() {
    move_after_copy();
    move_after_fu_copy();
    fu_move_after_copy();
    fu_move_after_fu_copy();
    copy_after_move();
    copy_after_fu_move();
    fu_copy_after_move();
    fu_copy_after_fu_move();

    borrow_after_move();
    borrow_after_fu_move();
    move_after_borrow();
    fu_move_after_borrow();
    mut_borrow_after_mut_borrow();

    move_after_move();
    move_after_fu_move();
    fu_move_after_move();
    fu_move_after_fu_move();

    copy_after_assign_after_move();
    copy_after_field_assign_after_move();
    borrow_after_assign_after_move();
    borrow_after_field_assign_after_move();
    move_after_assign_after_move();
    move_after_field_assign_after_move();

    copy_after_assign_after_uninit();
    borrow_after_assign_after_uninit();
    move_after_assign_after_uninit();
}

<|endoftext|>


<commit_before>// Copyright 2014 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 std::rc::Rc;
use std::ops::Deref;

#[derive(Copy, Clone)]
struct DerefWrapper<X, Y> {
    x: X,
    y: Y
}

impl<X, Y> DerefWrapper<X, Y> {
    fn get_x(self) -> X {
        self.x
    }
}

impl<X, Y> Deref for DerefWrapper<X, Y> {
    type Target = Y;

    fn deref(&self) -> &Y {
        &self.y
    }
}

mod priv_test {
    use std::ops::Deref;

    #[derive(Copy, Clone)]
    pub struct DerefWrapperHideX<X, Y> {
        x: X,
        pub y: Y
    }

    impl<X, Y> DerefWrapperHideX<X, Y> {
        pub fn new(x: X, y: Y) -> DerefWrapperHideX<X, Y> {
            DerefWrapperHideX {
                x: x,
                y: y
            }
        }
    }

    impl<X, Y> Deref for DerefWrapperHideX<X, Y> {
        type Target = Y;

        fn deref(&self) -> &Y {
            &self.y
        }
    }
}

pub fn main() {
    let nested = DerefWrapper {x: true, y: DerefWrapper {x: 0, y: 1}};

    // Use the first field that you can find.
    assert_eq!(nested.x, true);
    assert_eq!((*nested).x, 0);

    // Same for methods, even though there are multiple
    // candidates (at different nesting levels).
    assert_eq!(nested.get_x(), true);
    assert_eq!((*nested).get_x(), 0);

    // Also go through multiple levels of indirection.
    assert_eq!(Rc::new(nested).x, true);

    let nested_priv = priv_test::DerefWrapperHideX::new(true, DerefWrapper {x: 0, y: 1});
    // FIXME(eddyb) #12808 should skip private fields.
    // assert_eq!(nested_priv.x, 0);
    assert_eq!((*nested_priv).x, 0);
}
<commit_msg>Rollup merge of #44327 - Eh2406:FIXME#12808, r=aturon<commit_after>// Copyright 2014 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 std::rc::Rc;
use std::ops::Deref;

#[derive(Copy, Clone)]
struct DerefWrapper<X, Y> {
    x: X,
    y: Y
}

impl<X, Y> DerefWrapper<X, Y> {
    fn get_x(self) -> X {
        self.x
    }
}

impl<X, Y> Deref for DerefWrapper<X, Y> {
    type Target = Y;

    fn deref(&self) -> &Y {
        &self.y
    }
}

mod priv_test {
    use std::ops::Deref;

    #[derive(Copy, Clone)]
    pub struct DerefWrapperHideX<X, Y> {
        x: X,
        pub y: Y
    }

    impl<X, Y> DerefWrapperHideX<X, Y> {
        pub fn new(x: X, y: Y) -> DerefWrapperHideX<X, Y> {
            DerefWrapperHideX {
                x: x,
                y: y
            }
        }
    }

    impl<X, Y> Deref for DerefWrapperHideX<X, Y> {
        type Target = Y;

        fn deref(&self) -> &Y {
            &self.y
        }
    }
}

pub fn main() {
    let nested = DerefWrapper {x: true, y: DerefWrapper {x: 0, y: 1}};

    // Use the first field that you can find.
    assert_eq!(nested.x, true);
    assert_eq!((*nested).x, 0);

    // Same for methods, even though there are multiple
    // candidates (at different nesting levels).
    assert_eq!(nested.get_x(), true);
    assert_eq!((*nested).get_x(), 0);

    // Also go through multiple levels of indirection.
    assert_eq!(Rc::new(nested).x, true);

    let nested_priv = priv_test::DerefWrapperHideX::new(true, DerefWrapper {x: 0, y: 1});
    assert_eq!(nested_priv.x, 0);
    assert_eq!((*nested_priv).x, 0);
}
<|endoftext|>


<commit_before>///! x86 timing functions.

use raw_cpuid::CpuId;
use x86_64::instructions::port::Port;
use core::arch::x86_64::_rdtsc;

/// Frequency of the PIT
const PIT_FREQUENCY: u64 = 1193182;

/// PIT port definition
const PIT_PORT_MODE: u16 = 0x43;
const PIT_PORT_CHANNEL_0: u16 = 0x40;

/// PIT mode bit definitions
const PIT_MODE_CHANNEL_0: u8 = 0 << 6;
const PIT_MODE_RATE_GENERATOR: u8 = 2 << 1;
const PIT_MODE_ACCESS_LATCH: u8 = 0 << 4;
const PIT_MODE_ACCESS_BOTH: u8 = 3 << 4;

/// Type used to store a time value in milliseconds.
pub type msTime = u64;

/// This a manager for all time functions
pub struct TimeManager {
    /// TSC cycles per milliseconds
    tsc_cycles_per_msec: u64,

    /// Initial TSC start time
    tsc_start_time: u64,
}

impl TimeManager {
    /// Create a new time manger instance.
    pub fn new() -> Self {
        TimeManager {
            tsc_cycles_per_msec: 0,
            tsc_start_time: 0,
        }
    }

    /// Get the number of cycles per second
    pub fn get_cycles_per_msec(&self) -> u64 {
        self.tsc_cycles_per_msec
    }

    /// Get the current internal time.
    pub fn current_time(&self) -> msTime {
        let current = unsafe { _rdtsc() };
        (current - self.get_cycles_per_msec()) / self.tsc_cycles_per_msec
    }

    /// Initialize the TSC
    pub fn init(&mut self) {
        let cpuid = CpuId::new();

        // Check TSC support
        {
            let has_tsc = match cpuid.get_feature_info() {
                Some(finfo) => finfo.has_tsc(),
                None => false,
            };

            if !has_tsc {
                panic!("CPU does not support TSC");
            }
        }

        // Build all needed ports
        let mut pit_mode_port: Port<u8> = Port::new(PIT_PORT_MODE);
        let mut pit_channel_0_port: Port<u8> = Port::new(PIT_PORT_CHANNEL_0);

        // Calculate the TSC frequency.
        // First set the PIT to rate generator mode.
        unsafe {
            pit_mode_port.write(PIT_MODE_CHANNEL_0 | PIT_MODE_RATE_GENERATOR | PIT_MODE_ACCESS_BOTH);
            pit_channel_0_port.write(0xff);
            pit_channel_0_port.write(0xff);
        }

        // Wait for the cycle to being
        let mut start_low: u8;
        let mut start_high: u8;

        loop {
            unsafe {
                pit_mode_port.write(PIT_MODE_CHANNEL_0 | PIT_MODE_ACCESS_LATCH);
                start_low = pit_channel_0_port.read();
                start_high = pit_channel_0_port.read();
            }

            if start_high == 0xff {
                break;
            }
        }

        // get the start TSC value
        let mut tsc_start_time;
        unsafe {
            tsc_start_time = _rdtsc();
        }

        // Wait for the high byte to drop to 128
        let mut end_low: u8;
        let mut end_high: u8;
        loop {
            unsafe {
                pit_mode_port.write(PIT_MODE_CHANNEL_0 | PIT_MODE_ACCESS_LATCH);
                end_low = pit_channel_0_port.read();
                end_high = pit_channel_0_port.read();
            }

            if end_high <= 0x80 {
                break;
            }
        }

        // Get the end TSC value
        let mut tsc_end_time;
        unsafe {
            tsc_end_time = _rdtsc();
        }

        // Calculate the difference between the value
        let cycles = (tsc_end_time - tsc_start_time) as u64;
        let end_record = ((end_high as u16) << 8) | (end_low as u16);
        let start_record = ((start_high as u16) << 8) | (start_low as u16);
        let ticks = end_record.wrapping_sub(start_record);

        // Calculate frequency
        self.tsc_cycles_per_msec = (cycles * PIT_FREQUENCY) / (ticks as u64 * 1000);
    }
}
<commit_msg>chore: rename msTime to MsTime<commit_after>///! x86 timing functions.

use raw_cpuid::CpuId;
use x86_64::instructions::port::Port;
use core::arch::x86_64::_rdtsc;

/// Frequency of the PIT
const PIT_FREQUENCY: u64 = 1193182;

/// PIT port definition
const PIT_PORT_MODE: u16 = 0x43;
const PIT_PORT_CHANNEL_0: u16 = 0x40;

/// PIT mode bit definitions
const PIT_MODE_CHANNEL_0: u8 = 0 << 6;
const PIT_MODE_RATE_GENERATOR: u8 = 2 << 1;
const PIT_MODE_ACCESS_LATCH: u8 = 0 << 4;
const PIT_MODE_ACCESS_BOTH: u8 = 3 << 4;

/// Type used to store a time value in milliseconds.
pub type MsTime = u64;

/// This a manager for all time functions
pub struct TimeManager {
    /// TSC cycles per milliseconds
    tsc_cycles_per_msec: u64,

    /// Initial TSC start time
    tsc_start_time: u64,
}

impl TimeManager {
    /// Create a new time manger instance.
    pub fn new() -> Self {
        TimeManager {
            tsc_cycles_per_msec: 0,
            tsc_start_time: 0,
        }
    }

    /// Get the number of cycles per second
    pub fn get_cycles_per_msec(&self) -> u64 {
        self.tsc_cycles_per_msec
    }

    /// Get the current internal time.
    pub fn current_time(&self) -> MsTime {
        let current = unsafe { _rdtsc() };
        (current - self.get_cycles_per_msec()) / self.tsc_cycles_per_msec
    }

    /// Initialize the TSC
    pub fn init(&mut self) {
        let cpuid = CpuId::new();

        // Check TSC support
        {
            let has_tsc = match cpuid.get_feature_info(){
                Some(finfo) => finfo.has_tsc(),
                None => false,
            };

            if !has_tsc {
                panic!("CPU does not support TSC");
            }
        }

        // Build all needed ports
        let mut pit_mode_port: Port<u8> = Port::new(PIT_PORT_MODE);
        let mut pit_channel_0_port: Port<u8> = Port::new(PIT_PORT_CHANNEL_0);

        // Calculate the TSC frequency.
        // First set the PIT to rate generator mode.
        unsafe {
            pit_mode_port.write(PIT_MODE_CHANNEL_0 | PIT_MODE_RATE_GENERATOR | PIT_MODE_ACCESS_BOTH);
            pit_channel_0_port.write(0xff);
            pit_channel_0_port.write(0xff);
        }

        // Wait for the cycle to being
        let mut start_low: u8;
        let mut start_high: u8;

        loop {
            unsafe {
                pit_mode_port.write(PIT_MODE_CHANNEL_0 | PIT_MODE_ACCESS_LATCH);
                start_low = pit_channel_0_port.read();
                start_high = pit_channel_0_port.read();
            }

            if start_high == 0xff {
                break;
            }
        }

        // get the start TSC value
        let mut tsc_start_time;
        unsafe {
            tsc_start_time = _rdtsc();
        }

        // Wait for the high byte to drop to 128
        let mut end_low: u8;
        let mut end_high: u8;
        loop {
            unsafe {
                pit_mode_port.write(PIT_MODE_CHANNEL_0 | PIT_MODE_ACCESS_LATCH);
                end_low = pit_channel_0_port.read();
                end_high = pit_channel_0_port.read();
            }

            if end_high <= 0x80 {
                break;
            }
        }

        // Get the end TSC value
        let mut tsc_end_time;
        unsafe {
            tsc_end_time = _rdtsc();
        }

        // Calculate the difference between the value
        let cycles = (tsc_end_time - tsc_start_time) as u64;
        let end_record = ((end_high as u16) << 8) | (end_low as u16);
        let start_record = ((start_high as u16) << 8) | (start_low as u16);
        let ticks = end_record.wrapping_sub(start_record);

        // Calculate frequency
        self.tsc_cycles_per_msec = (cycles * PIT_FREQUENCY) / (ticks as u64 * 1000);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implementation of cookie creation and matching as specified by
//! http://tools.ietf.org/html/rfc6265

use cookie_rs;
use net_traits::CookieSource;
use net_traits::pub_domains::is_pub_domain;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::net::{Ipv4Addr, Ipv6Addr};
use time::{Tm, now, at, Duration};

/// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL,
/// which cookie-rs and hyper's header parsing do not support.
#[derive(Clone, Debug, RustcDecodable, RustcEncodable)]
pub struct Cookie {
    pub cookie: cookie_rs::Cookie,
    pub host_only: bool,
    pub persistent: bool,
    pub creation_time: Tm,
    pub last_access: Tm,
    pub expiry_time: Option<Tm>,
}

impl Cookie {
    /// http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &ServoUrl, source: CookieSource)
                       -> Option<Cookie> {
        // Step 3
        let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
            (&Some(max_age), _) => {
                (true, Some(at(now().to_timespec() + Duration::seconds(max_age as i64))))
            }
            (_, &Some(expires)) => (true, Some(expires)),
            _ => (false, None)
        };

        let url_host = request.host_str().unwrap_or("").to_owned();

        // Step 4
        let mut domain = cookie.domain.clone().unwrap_or("".to_owned());

        // Step 5
        if is_pub_domain(&domain) {
            if domain == url_host {
                domain = "".to_owned();
            } else {
                return None
            }
        }

        // Step 6
        let host_only = if !domain.is_empty() {
            if !Cookie::domain_match(&url_host, &domain) {
                return None;
            } else {
                cookie.domain = Some(domain);
                false
            }
        } else {
            cookie.domain = Some(url_host);
            true
        };

        // Step 7
        let mut path = cookie.path.unwrap_or("".to_owned());
        if path.chars().next() != Some('/') {
            path = Cookie::default_path(request.path()).to_owned();
        }
        cookie.path = Some(path);

        // Step 10
        if cookie.httponly && source == CookieSource::NonHTTP {
            return None;
        }

        Some(Cookie {
            cookie: cookie,
            host_only: host_only,
            persistent: persistent,
            creation_time: now(),
            last_access: now(),
            expiry_time: expiry_time,
        })
    }

    pub fn touch(&mut self) {
        self.last_access = now();
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn default_path(request_path: &str) -> &str {
        // Step 2
        if request_path.chars().next() != Some('/') {
            return "/";
        }

        // Step 3
        let rightmost_slash_idx = request_path.rfind("/").unwrap();
        if rightmost_slash_idx == 0 {
            // There's only one slash; it's the first character
            return "/";
        }

        // Step 4
        &request_path[..rightmost_slash_idx]
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
        // A request-path path-matches a given cookie-path if at least one of
        // the following conditions holds:

        // The cookie-path and the request-path are identical.
        request_path == cookie_path ||

        (request_path.starts_with(cookie_path) && (
            // The cookie-path is a prefix of the request-path, and the last
            // character of the cookie-path is %x2F ("/").
            cookie_path.ends_with("/") ||
            // The cookie-path is a prefix of the request-path, and the first
            // character of the request-path that is not included in the cookie-
            // path is a %x2F ("/") character.
            request_path[cookie_path.len()..].starts_with("/")
        ))
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.3
    pub fn domain_match(string: &str, domain_string: &str) -> bool {
        string == domain_string ||
        (string.ends_with(domain_string) &&
         string.as_bytes()[string.len()-domain_string.len()-1] == b'.' &&
         string.parse::<Ipv4Addr>().is_err() &&
         string.parse::<Ipv6Addr>().is_err())
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
    pub fn appropriate_for_url(&self, url: &ServoUrl, source: CookieSource) -> bool {
        let domain = url.host_str();
        if self.host_only {
            if self.cookie.domain.as_ref().map(String::as_str) != domain {
                return false;
            }
        } else {
            if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                if !Cookie::domain_match(domain, cookie_domain) {
                    return false;
                }
            }
        }

        if let Some(ref cookie_path) = self.cookie.path {
            if !Cookie::path_match(url.path(), cookie_path) {
                return false;
            }
        }

        if self.cookie.secure && url.scheme() != "https" {
            return false;
        }
        if self.cookie.httponly && source == CookieSource::NonHTTP {
            return false;
        }

        true
    }
}
<commit_msg>Check wss scheme in Cookie::appropriate_for_url<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implementation of cookie creation and matching as specified by
//! http://tools.ietf.org/html/rfc6265

use cookie_rs;
use net_traits::CookieSource;
use net_traits::pub_domains::is_pub_domain;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::net::{Ipv4Addr, Ipv6Addr};
use time::{Tm, now, at, Duration};

/// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL,
/// which cookie-rs and hyper's header parsing do not support.
#[derive(Clone, Debug, RustcDecodable, RustcEncodable)]
pub struct Cookie {
    pub cookie: cookie_rs::Cookie,
    pub host_only: bool,
    pub persistent: bool,
    pub creation_time: Tm,
    pub last_access: Tm,
    pub expiry_time: Option<Tm>,
}

impl Cookie {
    /// http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &ServoUrl, source: CookieSource)
                       -> Option<Cookie> {
        // Step 3
        let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
            (&Some(max_age), _) => {
                (true, Some(at(now().to_timespec() + Duration::seconds(max_age as i64))))
            }
            (_, &Some(expires)) => (true, Some(expires)),
            _ => (false, None)
        };

        let url_host = request.host_str().unwrap_or("").to_owned();

        // Step 4
        let mut domain = cookie.domain.clone().unwrap_or("".to_owned());

        // Step 5
        if is_pub_domain(&domain) {
            if domain == url_host {
                domain = "".to_owned();
            } else {
                return None
            }
        }

        // Step 6
        let host_only = if !domain.is_empty() {
            if !Cookie::domain_match(&url_host, &domain) {
                return None;
            } else {
                cookie.domain = Some(domain);
                false
            }
        } else {
            cookie.domain = Some(url_host);
            true
        };

        // Step 7
        let mut path = cookie.path.unwrap_or("".to_owned());
        if path.chars().next() != Some('/') {
            path = Cookie::default_path(request.path()).to_owned();
        }
        cookie.path = Some(path);

        // Step 10
        if cookie.httponly && source == CookieSource::NonHTTP {
            return None;
        }

        Some(Cookie {
            cookie: cookie,
            host_only: host_only,
            persistent: persistent,
            creation_time: now(),
            last_access: now(),
            expiry_time: expiry_time,
        })
    }

    pub fn touch(&mut self) {
        self.last_access = now();
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn default_path(request_path: &str) -> &str {
        // Step 2
        if request_path.chars().next() != Some('/') {
            return "/";
        }

        // Step 3
        let rightmost_slash_idx = request_path.rfind("/").unwrap();
        if rightmost_slash_idx == 0 {
            // There's only one slash; it's the first character
            return "/";
        }

        // Step 4
        &request_path[..rightmost_slash_idx]
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
        // A request-path path-matches a given cookie-path if at least one of
        // the following conditions holds:

        // The cookie-path and the request-path are identical.
        request_path == cookie_path ||

        (request_path.starts_with(cookie_path) && (
            // The cookie-path is a prefix of the request-path, and the last
            // character of the cookie-path is %x2F ("/").
            cookie_path.ends_with("/") ||
            // The cookie-path is a prefix of the request-path, and the first
            // character of the request-path that is not included in the cookie-
            // path is a %x2F ("/") character.
            request_path[cookie_path.len()..].starts_with("/")
        ))
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.3
    pub fn domain_match(string: &str, domain_string: &str) -> bool {
        string == domain_string ||
        (string.ends_with(domain_string) &&
         string.as_bytes()[string.len()-domain_string.len()-1] == b'.' &&
         string.parse::<Ipv4Addr>().is_err() &&
         string.parse::<Ipv6Addr>().is_err())
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
    pub fn appropriate_for_url(&self, url: &ServoUrl, source: CookieSource) -> bool {
        let domain = url.host_str();
        if self.host_only {
            if self.cookie.domain.as_ref().map(String::as_str) != domain {
                return false;
            }
        } else {
            if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                if !Cookie::domain_match(domain, cookie_domain) {
                    return false;
                }
            }
        }

        if let Some(ref cookie_path) = self.cookie.path {
            if !Cookie::path_match(url.path(), cookie_path) {
                return false;
            }
        }

        if self.cookie.secure && !url.is_secure_scheme() {
            return false;
        }
        if self.cookie.httponly && source == CookieSource::NonHTTP {
            return false;
        }

        true
    }
}
<|endoftext|>