<commit_before>/// modules for storing player and opponent model
use std::collections::HashMap;
use cards::{BasicCard, Suit, Rank, print_card_map, NUM_BASIC_CARDS};
use std::fmt;
use std::cmp;
use ndarray::prelude::*;
use ndarray::DataMut;

/// A `CardState` is an internal tracker for the likelihood of a
/// specific card.
#[derive(Debug, Clone, Copy, PartialEq)]
enum CardState {
    /// The card has been played, or the player otherwise definitely
    /// doesn't have the card.
    Played,

    /// The player was proven not to have this card right now.
    Void,

    /// The player has the card with the given likelihood.
    Prob(f32),

    /// The player definitely has this card.
    Owns
}

impl CardState {
    // Return the probability that the player owns a card in this
    // state.
    pub fn p(&self) -> f32 {
        match self {
            &CardState::Played => 0.0,
            &CardState::Void => 0.0,
            &CardState::Owns => 1.0,
            &CardState::Prob(ref p) => *p
        }
    }

    /// Return a zero-probability state if the current state is
    /// `Void`. Otherwise, return the same state.
    pub fn void_to_zero(&mut self) -> Self {
        if let CardState::Void = *self  {
            CardState::Prob(0.0)
        } else {
            *self
        }
    }

    /// Return true iff the state is the `Prob` enum
    pub fn is_prob(&self) -> bool {
        match self {
            &CardState::Prob(_) => true,
            _ => false
        }
    }
}

impl fmt::Display for CardState {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use self::CardState::*;
        let w = cmp::max(fmt.width().unwrap_or(5), 4);

        match *self {
            Played => write!(fmt, "{:1$}", "----", w),
            Void => write!(fmt, "{:1$}", "VOID", w),
            Owns => write!(fmt, "{:1$}", "MINE", w),
            Prob(p) => write!(fmt, "{:.1$}", p, w-2)
        }
    }
}

/// A `HandBelief` object represents the best estimate of the
/// probabilities of holding a specific card.
///
/// This struct assumes that all actions affecting the hand (picking
/// up, discarding, playing cards) are public, even if the precise
/// cards aren't. For instance, this module would be invalid if the
/// player could pick up a secret number of cards.
///
/// `HandBelief` is game-agnostic, and does not generally try to
/// model any game-specific knowledge. Estimates are generally
/// max-entropy in that sense.
pub struct HandBelief {
    probs: HashMap<BasicCard, CardState>,
}

impl HandBelief {
    pub fn new() -> HandBelief {
        let mut probs = HashMap::new();
        for card in BasicCard::all() {
            probs.insert(card.clone(), CardState::Void);
        }

        HandBelief { probs: probs }
    }

    /// Reset the entire hand to void.
    pub fn clear(&mut self) {
        for v in self.probs.values_mut() {
            *v = CardState::Void;
        }
    }

    /// print probabilities
    pub fn print_probabilities(&self) {
        print_card_map(&self.probs);
    }

    /// Return the probability that the player has the card.
    pub fn has_card(&mut self, card: &BasicCard) -> f32 {
        self.probs.get(card).expect("All basic cards should be in probability map.").p()
    }

    /// Return the total number of cards held by the player
    pub fn num_cards(&self) -> f32 {
        self.probs.values().map(|v| v.p()).sum()
    }

    /// Increase the probability of each card in probability status,
    /// such that the total probability increase is ec.
    fn distribute_uniformly(&mut self, ec: f32) {
        let nc = self.num_candidates();
        for  v in self.probs.values_mut() {
            if let &mut CardState::Prob(ref mut p) = v {
                *p += ec / nc;
            }
        }
    }

    /// Transfer the probability from cards satisfying the predicate
    /// to cards that don't.
    fn transfer_probability_to<F: Fn(BasicCard) -> bool>(&mut self, pred: F) {
        let (p_dist, count) = self.probs.iter()
            .filter_map(|(k, v)| if !pred(*k) && v.is_prob() { Some(v.p()) } else { None } )
            .fold((0.0, 0.0), |state, m| (state.0 + m, state.1 + 1.0));

        let nc = self.num_candidates();
        let p_inc = p_dist / (nc - count) ;

        for (card, p) in self.probs.iter_mut() {
            if let &mut CardState::Prob(ref mut pp) = p {
                if pred(*card) {
                    *pp += p_inc;
                } else {
                    *pp = 0.0;
                }
            }
        }
    }

    // Return the number of cards that are in a probability state.
    fn num_candidates(&self) -> f32 {
        self.probs.values().filter(|v| v.is_prob()).count() as f32
    }

    // mark all cards as non-void
    fn remove_voids(&mut self) {
        for p in self.probs.values_mut() {
            *p = p.void_to_zero();
        }
    }

    // Draw n random cards, after marking cards as non-void.
    pub fn random_cards_drawn(&mut self, n: usize) {
        self.remove_voids();
        self.distribute_uniformly(n as f32);
    }

    /// establish that the suit is empty
    pub fn empty_suit(&mut self, suit: Suit) {
        self.transfer_probability_to(|c| c.suit != suit);
        for (k, v) in self.probs.iter_mut() {
            if k.suit == suit {
                if let &mut CardState::Prob(_) = v {
                    *v = CardState::Void;
                }
            }
        }
    }

    /// Show that a particular card has been picked up.
    pub fn card_drawn(&mut self, card: &BasicCard) {
        // distribute the probability among the remaining cards
        self.transfer_probability_to(|c| c != *card);

        // Set the card to be owned
        self.probs.insert(*card, CardState::Owns);
    }

    /// Mark that the card has been played by this player.
    pub fn card_played(&mut self, card: &BasicCard) {
        self.transfer_probability_to(|c| c != *card);

        // mark that the card has been played
        self.probs.insert(*card, CardState::Played);

        // show that the total number of cards has been reduced
        self.distribute_uniformly(-1.0);
    }

    /// Mark that the card was played by another player.
    pub fn card_seen(&mut self, card: &BasicCard) {
        self.transfer_probability_to(|c| c != *card);
        self.probs.insert(*card, CardState::Played);
    }

    /// Write the probabilities onto a vector in the given suit order.
    pub fn onto_vector<T: DataMut<Elem=f32>>(&self, vec: &mut ArrayBase<T, Ix1>, suit_order: &[Suit]) {
        assert_eq!(vec.dim(), NUM_BASIC_CARDS);

        for ((suit, rank), v) in izip!(iproduct!(suit_order, Rank::iterator()), vec.iter_mut()) {
            let card = BasicCard{suit: *suit, rank: *rank};
            *v = self.probs.get(&card).map(|v| v.p()).unwrap_or(0.0);
        }
    }
}
<commit_msg>HandBelief: rename accessor has_card -> p<commit_after>/// modules for storing player and opponent model
use std::collections::HashMap;
use cards::{BasicCard, Suit, Rank, print_card_map, NUM_BASIC_CARDS};
use std::fmt;
use std::cmp;
use ndarray::prelude::*;
use ndarray::DataMut;

/// A `CardState` is an internal tracker for the likelihood of a
/// specific card.
#[derive(Debug, Clone, Copy, PartialEq)]
enum CardState {
    /// The card has been played, or the player otherwise definitely
    /// doesn't have the card.
    Played,

    /// The player was proven not to have this card right now.
    Void,

    /// The player has the card with the given likelihood.
    Prob(f32),

    /// The player definitely has this card.
    Owns
}

impl CardState {
    // Return the probability that the player owns a card in this
    // state.
    pub fn p(&self) -> f32 {
        match self {
            &CardState::Played => 0.0,
            &CardState::Void => 0.0,
            &CardState::Owns => 1.0,
            &CardState::Prob(ref p) => *p
        }
    }

    /// Return a zero-probability state if the current state is
    /// `Void`. Otherwise, return the same state.
    pub fn void_to_zero(&mut self) -> Self {
        if let CardState::Void = *self  {
            CardState::Prob(0.0)
        } else {
            *self
        }
    }

    /// Return true iff the state is the `Prob` enum
    pub fn is_prob(&self) -> bool {
        match self {
            &CardState::Prob(_) => true,
            _ => false
        }
    }
}

impl fmt::Display for CardState {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use self::CardState::*;
        let w = cmp::max(fmt.width().unwrap_or(5), 4);

        match *self {
            Played => write!(fmt, "{:1$}", "----", w),
            Void => write!(fmt, "{:1$}", "VOID", w),
            Owns => write!(fmt, "{:1$}", "MINE", w),
            Prob(p) => write!(fmt, "{:.1$}", p, w-2)
        }
    }
}

/// A `HandBelief` object represents the best estimate of the
/// probabilities of holding a specific card.
///
/// This struct assumes that all actions affecting the hand (picking
/// up, discarding, playing cards) are public, even if the precise
/// cards aren't. For instance, this module would be invalid if the
/// player could pick up a secret number of cards.
///
/// `HandBelief` is game-agnostic, and does not generally try to
/// model any game-specific knowledge. Estimates are generally
/// max-entropy in that sense.
pub struct HandBelief {
    probs: HashMap<BasicCard, CardState>,
}

impl HandBelief {
    pub fn new() -> HandBelief {
        let mut probs = HashMap::new();
        for card in BasicCard::all() {
            probs.insert(card.clone(), CardState::Void);
        }

        HandBelief { probs: probs }
    }

    /// Reset the entire hand to void.
    pub fn clear(&mut self) {
        for v in self.probs.values_mut() {
            *v = CardState::Void;
        }
    }

    /// print probabilities
    pub fn print_probabilities(&self) {
        print_card_map(&self.probs);
    }

    /// Return the probability that the player has the card.
    pub fn p(&self, card: &BasicCard) -> f32 {
        self.probs.get(card).expect("All basic cards should be in probability map.").p()
    }

    /// Return the total number of cards held by the player
    pub fn num_cards(&self) -> f32 {
        self.probs.values().map(|v| v.p()).sum()
    }

    /// Increase the probability of each card in probability status,
    /// such that the total probability increase is ec.
    fn distribute_uniformly(&mut self, ec: f32) {
        let nc = self.num_candidates();
        for  v in self.probs.values_mut() {
            if let &mut CardState::Prob(ref mut p) = v {
                *p += ec / nc;
            }
        }
    }

    /// Transfer the probability from cards satisfying the predicate
    /// to cards that don't.
    fn transfer_probability_to<F: Fn(BasicCard) -> bool>(&mut self, pred: F) {
        let (p_dist, count) = self.probs.iter()
            .filter_map(|(k, v)| if !pred(*k) && v.is_prob() { Some(v.p()) } else { None } )
            .fold((0.0, 0.0), |state, m| (state.0 + m, state.1 + 1.0));

        let nc = self.num_candidates();
        let p_inc = p_dist / (nc - count) ;

        for (card, p) in self.probs.iter_mut() {
            if let &mut CardState::Prob(ref mut pp) = p {
                if pred(*card) {
                    *pp += p_inc;
                } else {
                    *pp = 0.0;
                }
            }
        }
    }

    // Return the number of cards that are in a probability state.
    fn num_candidates(&self) -> f32 {
        self.probs.values().filter(|v| v.is_prob()).count() as f32
    }

    // mark all cards as non-void
    fn remove_voids(&mut self) {
        for p in self.probs.values_mut() {
            *p = p.void_to_zero();
        }
    }

    // Draw n random cards, after marking cards as non-void.
    pub fn random_cards_drawn(&mut self, n: usize) {
        self.remove_voids();
        self.distribute_uniformly(n as f32);
    }

    /// establish that the suit is empty
    pub fn empty_suit(&mut self, suit: Suit) {
        self.transfer_probability_to(|c| c.suit != suit);
        for (k, v) in self.probs.iter_mut() {
            if k.suit == suit {
                if let &mut CardState::Prob(_) = v {
                    *v = CardState::Void;
                }
            }
        }
    }

    /// Show that a particular card has been picked up.
    pub fn card_drawn(&mut self, card: &BasicCard) {
        // distribute the probability among the remaining cards
        self.transfer_probability_to(|c| c != *card);

        // Set the card to be owned
        self.probs.insert(*card, CardState::Owns);
    }

    /// Mark that the card has been played by this player.
    pub fn card_played(&mut self, card: &BasicCard) {
        self.transfer_probability_to(|c| c != *card);

        // mark that the card has been played
        self.probs.insert(*card, CardState::Played);

        // show that the total number of cards has been reduced
        self.distribute_uniformly(-1.0);
    }

    /// Mark that the card was played by another player.
    pub fn card_seen(&mut self, card: &BasicCard) {
        self.transfer_probability_to(|c| c != *card);
        self.probs.insert(*card, CardState::Played);
    }

    /// Write the probabilities onto a vector in the given suit order.
    pub fn onto_vector<T: DataMut<Elem=f32>>(&self, vec: &mut ArrayBase<T, Ix1>, suit_order: &[Suit]) {
        assert_eq!(vec.dim(), NUM_BASIC_CARDS);

        for ((suit, rank), v) in izip!(iproduct!(suit_order, Rank::iterator()), vec.iter_mut()) {
            let card = BasicCard{suit: *suit, rank: *rank};
            *v = self.probs.get(&card).map(|v| v.p()).unwrap_or(0.0);
        }
    }
}
<|endoftext|>


<commit_before>use hyper::header::ByteRangeSpec;
use hyper::header::ByteRangeSpec::FromTo;
use hyper::header::Range::Bytes;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec};
use hyper::StatusCode;

use reqwest;
use reqwest::{header, Client};

use buffer::Buffer;
use reader::Reader;

use std::cmp;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};
use std::time::Instant;

fn get_head(filename: &str) -> Result<reqwest::Response, reqwest::Error> {
    if filename.contains(".amazonaws.com") {
        let range = vec![FromTo(0, 0)];

        let mut headers = header::Headers::new();
        headers.set(Bytes(range));
        let client = reqwest::Client::builder()
            .default_headers(headers)
            .build()
            .unwrap();

        client.get(filename).send()
    } else {
        let client = Client::new();
        client.head(filename).send()
    }
}

#[derive(Debug)]
struct ResponseData {
    body_data: Vec<u8>,
    file_size: u64,
}

fn get_data(filename: &str, range: Vec<ByteRangeSpec>) -> Result<ResponseData, String> {
    let mut headers = header::Headers::new();
    headers.set(Bytes(range));
    let client = reqwest::Client::builder()
        .default_headers(headers)
        .build()
        .unwrap();

    let mut response = match client.get(filename).send() {
        Ok(content) => content,
        Err(_msg) => return Err("bad request".to_string()),
    };

    let status = response.status();

    if !(status == StatusCode::Ok || status == StatusCode::PartialContent) {
        error!("ERROR {:?}", response);
        return Err("bad response status".to_string());
    }

    let mut body: Vec<u8> = vec![];
    let _result = response.copy_to(&mut body);

    let file_size = match get_content_range(&response) {
        Ok(length) => length.unwrap_or(0),
        Err(_msg) => return Err("bad response header".to_string()),
    };

    Ok(ResponseData {
        body_data: body,
        file_size,
    })
}

fn get_content_length(response: &reqwest::Response) -> Option<u64> {
    match response.headers().get::<ContentRange>() {
        Some(&ContentRange(ContentRangeSpec::Bytes {
            range: _range,
            instance_length,
        })) => instance_length,
        _ => match response.headers().get::<ContentLength>() {
            Some(length) => Some(**length as u64),
            None => None,
        },
    }
}

fn get_content_range(response: &reqwest::Response) -> Result<Option<u64>, String> {
    match response.headers().get::<ContentRange>() {
        Some(content_range) => match content_range.clone() {
            ContentRange(ContentRangeSpec::Bytes {
                range: _range,
                instance_length: length,
            }) => Ok(length),
            ContentRange(ContentRangeSpec::Unregistered {
                unit: _unit,
                resp: _resp,
            }) => Err("Unregistered, actually unsupported".to_string()),
        },
        None => Err("Missing content_range".to_string()),
    }
}

#[derive(Debug)]
pub struct HttpReader {
    pub filename: String,
    pub file_size: Option<u64>,
    pub position: u64,
    pub buffer: Buffer,
}

pub fn exists(filename: &str) -> bool {
    match get_head(filename) {
        Ok(resp) => resp.status().is_success(),
        Err(_msg) => false,
    }
}

fn get_data_range(position: u64, size: usize, max_end_position: Option<u64>) -> Vec<ByteRangeSpec> {
    let start = position;
    let end = match (position, size) {
        (0, 0) => 0,
        (_, _) => match max_end_position {
            Some(max) => {
                let max_size = max - position;
                position + cmp::min((size - 1) as u64, max_size)
            }
            None => position + (size - 1) as u64,
        },
    };

    vec![FromTo(start, end)]
}

fn load_data(reader: &mut HttpReader, size: usize) -> Result<Option<Vec<u8>>, String> {
    let start = Instant::now();
    info!("make HTTP request with request {:?} bytes", size);

    let position = match reader.buffer.size {
        Some(_) => reader.buffer.position,
        None => reader.position,
    };

    if let Some(total_file_size) = reader.file_size {
        if position >= total_file_size {
            info!(
                "request range out of range: {} > {}",
                position, total_file_size
            );
            return Ok(None);
        }
    }

    let range = get_data_range(position, size, reader.buffer.max_end_position);
    let response = match get_data(&reader.filename, range) {
        Ok(data) => data,
        Err(msg) => return Err(msg),
    };

    let elapsed = start.elapsed();
    if elapsed.as_secs() > 0 {
        warn!("Request duration {} seconds", elapsed.as_secs());
    }

    let new_position = position + response.body_data.len() as u64;
    match reader.buffer.size {
        Some(_) => {
            reader.buffer.position = new_position;
        }
        None => {
            reader.position = new_position;
        }
    };
    Ok(Some(response.body_data))
}

impl Reader for HttpReader {
    fn new() -> HttpReader {
        HttpReader {
            filename: "".to_string(),
            file_size: None,
            position: 0,
            buffer: Buffer {
                size: None,
                position: 0,
                max_end_position: None,
                buffer: vec![],
            },
        }
    }

    fn open(&mut self, filename: &str) -> Result<(), String> {
        self.filename = filename.to_string();

        match get_head(filename) {
            Err(msg) => Err(msg.to_string()),
            Ok(response) => {
                let content_length = match get_content_range(&response) {
                    Ok(length) => length,
                    _ => get_content_length(&response),
                };

                self.file_size = content_length;
                Ok(())
            }
        }
    }

    fn get_position(&mut self) -> Result<u64, String> {
        Ok(self.position)
    }

    fn get_cache_size(&self) -> Option<usize> {
        self.buffer.size
    }

    fn set_cache_size(&mut self, cache_size: Option<usize>) {
        self.buffer.size = cache_size;
    }

    fn get_max_end_position(&self) -> Option<u64> {
        self.buffer.max_end_position
    }

    fn set_max_end_position(&mut self, max_end_position: Option<u64>) {
        self.buffer.max_end_position = max_end_position;
    }

    fn get_size(&mut self) -> Result<u64, String> {
        match self.file_size {
            Some(length) => Ok(length),
            None => Err("No length detected".to_string()),
        }
    }
}

impl Read for HttpReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        if self.buffer.get_cached_size() >= buf.len() {
            self.position += buf.len() as u64;
            if self.buffer.get_data(buf) {
                Ok(buf.len())
            } else {
                Err(Error::new(
                    ErrorKind::Other,
                    "unable to read data from HTTP cache",
                ))
            }
        } else if let Some(buffer_size) = self.buffer.size {
            let some_data = load_data(self, buffer_size)
                .map_err(|msg| Error::new(ErrorKind::Other, msg))?;

            if let Some(data) = some_data {
                self.buffer.append_data(&data.to_vec());
                self.position += buf.len() as u64;
                if self.buffer.get_data(buf) {
                    return Ok(buf.len());
                } else {
                    return Err(Error::new(
                        ErrorKind::Other,
                        "unable to read data from HTTP cache",
                    ));
                }
            } else {
                Ok(0)
            }
        } else {
            let some_data =
                load_data(self, buf.len()).map_err(|msg| Error::new(ErrorKind::Other, msg))?;

            if let Some(data) = some_data {
                if data.len() >= buf.len() {
                    buf.clone_from_slice(&data);
                    Ok(data.len())
                } else {
                    Ok(0)
                }
            } else {
                Ok(0)
            }
        }
    }
}

impl Seek for HttpReader {
    fn seek(&mut self, seek_from: SeekFrom) -> Result<u64, Error> {
        match seek_from {
            SeekFrom::Current(offset) => {
                self.position += offset as u64;
                if self.buffer.size.is_some() {
                    if offset > 0 && self.buffer.get_cached_size() > offset as usize {
                        let mut skipped_data = vec![];
                        skipped_data.resize(offset as usize, 0);
                        let _skiped_data = self.buffer.get_data(&mut skipped_data);
                    } else {
                        self.buffer.reset();
                    }
                }
            }
            SeekFrom::Start(offset) => {
                self.buffer.reset();
                self.position = offset;
                if self.buffer.size.is_some() {
                    self.buffer.position = self.position;
                }
            }
            SeekFrom::End(offset) => {
                self.buffer.reset();
                match self.file_size {
                    Some(size) => {
                        self.position = size - offset as u64;
                        if self.buffer.size.is_some() {
                            self.buffer.position = self.position;
                        }
                    }
                    None => return Err(Error::new(ErrorKind::Other, "Missing file size")),
                }
            }
        }
        Ok(self.position)
    }
}
<commit_msg>format code<commit_after>use hyper::header::ByteRangeSpec;
use hyper::header::ByteRangeSpec::FromTo;
use hyper::header::Range::Bytes;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec};
use hyper::StatusCode;

use reqwest;
use reqwest::{header, Client};

use buffer::Buffer;
use reader::Reader;

use std::cmp;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};
use std::time::Instant;

fn get_head(filename: &str) -> Result<reqwest::Response, reqwest::Error> {
    if filename.contains(".amazonaws.com") {
        let range = vec![FromTo(0, 0)];

        let mut headers = header::Headers::new();
        headers.set(Bytes(range));
        let client = reqwest::Client::builder()
            .default_headers(headers)
            .build()
            .unwrap();

        client.get(filename).send()
    } else {
        let client = Client::new();
        client.head(filename).send()
    }
}

#[derive(Debug)]
struct ResponseData {
    body_data: Vec<u8>,
    file_size: u64,
}

fn get_data(filename: &str, range: Vec<ByteRangeSpec>) -> Result<ResponseData, String> {
    let mut headers = header::Headers::new();
    headers.set(Bytes(range));
    let client = reqwest::Client::builder()
        .default_headers(headers)
        .build()
        .unwrap();

    let mut response = match client.get(filename).send() {
        Ok(content) => content,
        Err(_msg) => return Err("bad request".to_string()),
    };

    let status = response.status();

    if !(status == StatusCode::Ok || status == StatusCode::PartialContent) {
        error!("ERROR {:?}", response);
        return Err("bad response status".to_string());
    }

    let mut body: Vec<u8> = vec![];
    let _result = response.copy_to(&mut body);

    let file_size = match get_content_range(&response) {
        Ok(length) => length.unwrap_or(0),
        Err(_msg) => return Err("bad response header".to_string()),
    };

    Ok(ResponseData {
        body_data: body,
        file_size,
    })
}

fn get_content_length(response: &reqwest::Response) -> Option<u64> {
    match response.headers().get::<ContentRange>() {
        Some(&ContentRange(ContentRangeSpec::Bytes {
            range: _range,
            instance_length,
        })) => instance_length,
        _ => match response.headers().get::<ContentLength>() {
            Some(length) => Some(**length as u64),
            None => None,
        },
    }
}

fn get_content_range(response: &reqwest::Response) -> Result<Option<u64>, String> {
    match response.headers().get::<ContentRange>() {
        Some(content_range) => match content_range.clone() {
            ContentRange(ContentRangeSpec::Bytes {
                range: _range,
                instance_length: length,
            }) => Ok(length),
            ContentRange(ContentRangeSpec::Unregistered {
                unit: _unit,
                resp: _resp,
            }) => Err("Unregistered, actually unsupported".to_string()),
        },
        None => Err("Missing content_range".to_string()),
    }
}

#[derive(Debug)]
pub struct HttpReader {
    pub filename: String,
    pub file_size: Option<u64>,
    pub position: u64,
    pub buffer: Buffer,
}

pub fn exists(filename: &str) -> bool {
    match get_head(filename) {
        Ok(resp) => resp.status().is_success(),
        Err(_msg) => false,
    }
}

fn get_data_range(position: u64, size: usize, max_end_position: Option<u64>) -> Vec<ByteRangeSpec> {
    let start = position;
    let end = match (position, size) {
        (0, 0) => 0,
        (_, _) => match max_end_position {
            Some(max) => {
                let max_size = max - position;
                position + cmp::min((size - 1) as u64, max_size)
            }
            None => position + (size - 1) as u64,
        },
    };

    vec![FromTo(start, end)]
}

fn load_data(reader: &mut HttpReader, size: usize) -> Result<Option<Vec<u8>>, String> {
    let start = Instant::now();
    info!("make HTTP request with request {:?} bytes", size);

    let position = match reader.buffer.size {
        Some(_) => reader.buffer.position,
        None => reader.position,
    };

    if let Some(total_file_size) = reader.file_size {
        if position >= total_file_size {
            info!(
                "request range out of range: {} > {}",
                position, total_file_size
            );
            return Ok(None);
        }
    }

    let range = get_data_range(position, size, reader.buffer.max_end_position);
    let response = match get_data(&reader.filename, range) {
        Ok(data) => data,
        Err(msg) => return Err(msg),
    };

    let elapsed = start.elapsed();
    if elapsed.as_secs() > 0 {
        warn!("Request duration {} seconds", elapsed.as_secs());
    }

    let new_position = position + response.body_data.len() as u64;
    match reader.buffer.size {
        Some(_) => {
            reader.buffer.position = new_position;
        }
        None => {
            reader.position = new_position;
        }
    };
    Ok(Some(response.body_data))
}

impl Reader for HttpReader {
    fn new() -> HttpReader {
        HttpReader {
            filename: "".to_string(),
            file_size: None,
            position: 0,
            buffer: Buffer {
                size: None,
                position: 0,
                max_end_position: None,
                buffer: vec![],
            },
        }
    }

    fn open(&mut self, filename: &str) -> Result<(), String> {
        self.filename = filename.to_string();

        match get_head(filename) {
            Err(msg) => Err(msg.to_string()),
            Ok(response) => {
                let content_length = match get_content_range(&response) {
                    Ok(length) => length,
                    _ => get_content_length(&response),
                };

                self.file_size = content_length;
                Ok(())
            }
        }
    }

    fn get_position(&mut self) -> Result<u64, String> {
        Ok(self.position)
    }

    fn get_cache_size(&self) -> Option<usize> {
        self.buffer.size
    }

    fn set_cache_size(&mut self, cache_size: Option<usize>) {
        self.buffer.size = cache_size;
    }

    fn get_max_end_position(&self) -> Option<u64> {
        self.buffer.max_end_position
    }

    fn set_max_end_position(&mut self, max_end_position: Option<u64>) {
        self.buffer.max_end_position = max_end_position;
    }

    fn get_size(&mut self) -> Result<u64, String> {
        match self.file_size {
            Some(length) => Ok(length),
            None => Err("No length detected".to_string()),
        }
    }
}

impl Read for HttpReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        if self.buffer.get_cached_size() >= buf.len() {
            self.position += buf.len() as u64;
            if self.buffer.get_data(buf) {
                Ok(buf.len())
            } else {
                Err(Error::new(
                    ErrorKind::Other,
                    "unable to read data from HTTP cache",
                ))
            }
        } else if let Some(buffer_size) = self.buffer.size {
            let some_data =
                load_data(self, buffer_size).map_err(|msg| Error::new(ErrorKind::Other, msg))?;

            if let Some(data) = some_data {
                self.buffer.append_data(&data.to_vec());
                self.position += buf.len() as u64;
                if self.buffer.get_data(buf) {
                    return Ok(buf.len());
                } else {
                    return Err(Error::new(
                        ErrorKind::Other,
                        "unable to read data from HTTP cache",
                    ));
                }
            } else {
                Ok(0)
            }
        } else {
            let some_data =
                load_data(self, buf.len()).map_err(|msg| Error::new(ErrorKind::Other, msg))?;

            if let Some(data) = some_data {
                if data.len() >= buf.len() {
                    buf.clone_from_slice(&data);
                    Ok(data.len())
                } else {
                    Ok(0)
                }
            } else {
                Ok(0)
            }
        }
    }
}

impl Seek for HttpReader {
    fn seek(&mut self, seek_from: SeekFrom) -> Result<u64, Error> {
        match seek_from {
            SeekFrom::Current(offset) => {
                self.position += offset as u64;
                if self.buffer.size.is_some() {
                    if offset > 0 && self.buffer.get_cached_size() > offset as usize {
                        let mut skipped_data = vec![];
                        skipped_data.resize(offset as usize, 0);
                        let _skiped_data = self.buffer.get_data(&mut skipped_data);
                    } else {
                        self.buffer.reset();
                    }
                }
            }
            SeekFrom::Start(offset) => {
                self.buffer.reset();
                self.position = offset;
                if self.buffer.size.is_some() {
                    self.buffer.position = self.position;
                }
            }
            SeekFrom::End(offset) => {
                self.buffer.reset();
                match self.file_size {
                    Some(size) => {
                        self.position = size - offset as u64;
                        if self.buffer.size.is_some() {
                            self.buffer.position = self.position;
                        }
                    }
                    None => return Err(Error::new(ErrorKind::Other, "Missing file size")),
                }
            }
        }
        Ok(self.position)
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;

use support::{project, execs};
use support::{COMPILING, RUNNING};
use hamcrest::assert_that;

fn setup() {
}

test!(plugin_to_the_max {
    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo_lib"

            [dependencies.bar]
            path = "../bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]
            extern crate foo_lib;

            fn main() { foo_lib::foo(); }
        "#)
        .file("src/foo_lib.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            pub fn foo() {}
        "#);
    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true

            [dependencies.baz]
            path = "../baz"
        "#)
        .file("src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate rustc;
            extern crate baz;

            use rustc::plugin::Registry;

            #[plugin_registrar]
            pub fn foo(_reg: &mut Registry) {
                println!("{}", baz::baz());
            }
        "#);
    let baz = project("baz")
        .file("Cargo.toml", r#"
            [package]
            name = "baz"
            version = "0.0.1"
            authors = []

            [lib]
            name = "baz"
            crate_type = ["dylib"]
        "#)
        .file("src/lib.rs", "pub fn baz() -> i32 { 1 }");
    bar.build();
    baz.build();

    assert_that(foo.cargo_process("build"),
                execs().with_status(0));
    assert_that(foo.cargo("doc"),
                execs().with_status(0));
});

test!(plugin_with_dynamic_native_dependency {
    let build = project("builder")
        .file("Cargo.toml", r#"
            [package]
            name = "builder"
            version = "0.0.1"
            authors = []

            [lib]
            name = "builder"
            crate-type = ["dylib"]
        "#)
        .file("src/lib.rs", r#"
            #[no_mangle]
            pub extern fn foo() {}
        "#);
    assert_that(build.cargo_process("build"),
                execs().with_status(0).with_stderr(""));
    let src = build.root().join("target/debug");
    let lib = fs::read_dir(&src).unwrap().map(|s| s.unwrap().path()).find(|lib| {
        let lib = lib.file_name().unwrap().to_str().unwrap();
        lib.starts_with(env::consts::DLL_PREFIX) &&
            lib.ends_with(env::consts::DLL_SUFFIX)
    }).unwrap();
    let libname = lib.file_name().unwrap().to_str().unwrap();
    let libname = &libname[env::consts::DLL_PREFIX.len()..
                           libname.len() - env::consts::DLL_SUFFIX.len()];

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = "bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            fn main() {}
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
            build = 'build.rs'

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/build.rs", r#"
            #![feature(convert)]
            use std::path::PathBuf;
            use std::env;

            fn main() {
                let src = PathBuf::from(env::var("SRC").unwrap());
                println!("cargo:rustc-flags=-L {}", src.parent().unwrap()
                                                       .display());
            }
        "#)
        .file("bar/src/lib.rs", &format!(r#"
            #![feature(plugin_registrar, rustc_private)]
            extern crate rustc;

            use rustc::plugin::Registry;

            #[link(name = "{}")]
            extern {{ fn foo(); }}

            #[plugin_registrar]
            pub fn bar(_reg: &mut Registry) {{
                unsafe {{ foo() }}
            }}
        "#, libname));

    assert_that(foo.cargo_process("build").env("SRC", &lib),
                execs().with_status(0));
});

test!(plugin_integration {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"

            [lib]
            name = "foo"
            plugin = true
            doctest = false
        "#)
        .file("build.rs", "fn main() {}")
        .file("src/lib.rs", "")
        .file("tests/it_works.rs", "");

    assert_that(p.cargo_process("test"),
                execs().with_status(0));
});

test!(doctest_a_plugin {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = { path = "bar" }
        "#)
        .file("src/lib.rs", r#"
            #[macro_use]
            extern crate bar;
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/src/lib.rs", "");

    assert_that(p.cargo_process("test").arg("-v"),
                execs().with_status(0));
});

// See #1515
test!(native_plugin_dependency_with_custom_ar_linker {
    let (_, target) = ::cargo::ops::rustc_version().unwrap();

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo"
            plugin = true
        "#)
        .file("src/lib.rs", "");

    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"

            [dependencies.foo]
            path = "../foo"
        "#)
        .file("src/lib", "")
        .file(".cargo/config", &format!(r#"
            [target.{}]
            ar = "ar"
            linker = "cc"
        "#, target));

    foo.build();
    assert_that(bar.cargo_process("build").arg("--verbose"),
    execs().with_stdout(&format!("\
{compiling} foo v0.0.1 ({url})
{running} `rustc [..] -C ar=ar -C linker=cc [..]`
{compiling} bar v0.0.1 ({url})
{running} `rustc [..] -C ar=ar -C linker=cc [..]`
", compiling = COMPILING, running = RUNNING, url = bar.url())))
});
<commit_msg>Relax the test for ar/linker with plugins<commit_after>use std::fs;
use std::env;

use support::{project, execs};
use support::{COMPILING, RUNNING};
use hamcrest::assert_that;

fn setup() {
}

test!(plugin_to_the_max {
    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo_lib"

            [dependencies.bar]
            path = "../bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]
            extern crate foo_lib;

            fn main() { foo_lib::foo(); }
        "#)
        .file("src/foo_lib.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            pub fn foo() {}
        "#);
    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true

            [dependencies.baz]
            path = "../baz"
        "#)
        .file("src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate rustc;
            extern crate baz;

            use rustc::plugin::Registry;

            #[plugin_registrar]
            pub fn foo(_reg: &mut Registry) {
                println!("{}", baz::baz());
            }
        "#);
    let baz = project("baz")
        .file("Cargo.toml", r#"
            [package]
            name = "baz"
            version = "0.0.1"
            authors = []

            [lib]
            name = "baz"
            crate_type = ["dylib"]
        "#)
        .file("src/lib.rs", "pub fn baz() -> i32 { 1 }");
    bar.build();
    baz.build();

    assert_that(foo.cargo_process("build"),
                execs().with_status(0));
    assert_that(foo.cargo("doc"),
                execs().with_status(0));
});

test!(plugin_with_dynamic_native_dependency {
    let build = project("builder")
        .file("Cargo.toml", r#"
            [package]
            name = "builder"
            version = "0.0.1"
            authors = []

            [lib]
            name = "builder"
            crate-type = ["dylib"]
        "#)
        .file("src/lib.rs", r#"
            #[no_mangle]
            pub extern fn foo() {}
        "#);
    assert_that(build.cargo_process("build"),
                execs().with_status(0).with_stderr(""));
    let src = build.root().join("target/debug");
    let lib = fs::read_dir(&src).unwrap().map(|s| s.unwrap().path()).find(|lib| {
        let lib = lib.file_name().unwrap().to_str().unwrap();
        lib.starts_with(env::consts::DLL_PREFIX) &&
            lib.ends_with(env::consts::DLL_SUFFIX)
    }).unwrap();
    let libname = lib.file_name().unwrap().to_str().unwrap();
    let libname = &libname[env::consts::DLL_PREFIX.len()..
                           libname.len() - env::consts::DLL_SUFFIX.len()];

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = "bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            fn main() {}
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
            build = 'build.rs'

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/build.rs", r#"
            #![feature(convert)]
            use std::path::PathBuf;
            use std::env;

            fn main() {
                let src = PathBuf::from(env::var("SRC").unwrap());
                println!("cargo:rustc-flags=-L {}", src.parent().unwrap()
                                                       .display());
            }
        "#)
        .file("bar/src/lib.rs", &format!(r#"
            #![feature(plugin_registrar, rustc_private)]
            extern crate rustc;

            use rustc::plugin::Registry;

            #[link(name = "{}")]
            extern {{ fn foo(); }}

            #[plugin_registrar]
            pub fn bar(_reg: &mut Registry) {{
                unsafe {{ foo() }}
            }}
        "#, libname));

    assert_that(foo.cargo_process("build").env("SRC", &lib),
                execs().with_status(0));
});

test!(plugin_integration {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"

            [lib]
            name = "foo"
            plugin = true
            doctest = false
        "#)
        .file("build.rs", "fn main() {}")
        .file("src/lib.rs", "")
        .file("tests/it_works.rs", "");

    assert_that(p.cargo_process("test"),
                execs().with_status(0));
});

test!(doctest_a_plugin {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = { path = "bar" }
        "#)
        .file("src/lib.rs", r#"
            #[macro_use]
            extern crate bar;
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/src/lib.rs", "");

    assert_that(p.cargo_process("test").arg("-v"),
                execs().with_status(0));
});

// See #1515
test!(native_plugin_dependency_with_custom_ar_linker {
    let (_, target) = ::cargo::ops::rustc_version().unwrap();

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo"
            plugin = true
        "#)
        .file("src/lib.rs", "");

    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"

            [dependencies.foo]
            path = "../foo"
        "#)
        .file("src/lib", "")
        .file(".cargo/config", &format!(r#"
            [target.{}]
            ar = "nonexistent-ar"
            linker = "nonexistent-linker"
        "#, target));

    foo.build();
    assert_that(bar.cargo_process("build").arg("--verbose"),
                execs().with_stdout(&format!("\
{compiling} foo v0.0.1 ({url})
{running} `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
", compiling = COMPILING, running = RUNNING, url = bar.url())))
});
<|endoftext|>


<commit_before>use structopt::StructOpt;

use codespan::Files;
use codespan_reporting::termcolor::StandardStream;
use codespan_reporting::{emit, ColorArg, Diagnostic, Label};

#[derive(Debug, StructOpt)]
#[structopt(name = "emit")]
pub struct Opts {
    /// Configure coloring of output
    #[structopt(
        long = "color",
        parse(try_from_str),
        default_value = "auto",
        raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
    )]
    pub color: ColorArg,
}

fn main() {
    let opts = Opts::from_args();
    let mut files = Files::new();

    let nat_file_id = files.add(
        "Data/Nat.fun",
        unindent::unindent(
            "
                module Data.Nat where

                data Nat : Type where
                    zero : Nat
                    succ : Nat → Nat

                {-# BUILTIN NATRAL Nat #-}

                infixl 6 _+_ _-_

                _+_ : Nat → Nat → Nat
                zero    + n₂ = n₂
                succ n₁ + n₂ = succ (n₁ + n₂)

                _-_ : Nat → Nat → Nat
                n₁      - zero    = n₁
                zero    - succ n₂ = zero
                succ n₁ - succ n₂ = n₁ - n₂
            ",
        ),
    );

    let test_file_id = files.add(
        "Test.fun",
        unindent::unindent(
            r#"
                module Test where

                _ : Nat
                _ = 123 + "hello"
            "#,
        ),
    );

    let fizz_buzz_file_id = files.add(
        "FizzBuzz.fun",
        unindent::unindent(
            r#"
                module FizzBuzz where

                fizz₁ : Nat → String
                fizz₁ num = case (mod num 5) (mod num 3) of
                    0 0 => "FizzBuzz"
                    0 _ => "Fizz"
                    _ 0 => "Buzz"
                    _ _ => num

                fizz₂ num =
                    case (mod num 5) (mod num 3) of
                        0 0 => "FizzBuzz"
                        0 _ => "Fizz"
                        _ 0 => "Buzz"
                        _ _ => num
            "#,
        ),
    );

    let diagnostics = [
        // Unknown builtin error
        Diagnostic::new_error(
            "unknown builtin: `NATRAL`",
            Label::new(nat_file_id, 96..102, "unknown builtin"),
        )
        .with_notes(vec![
            "there is a builtin with a similar name: `NATURAL`".to_owned()
        ]),
        // Unused parameter warning
        Diagnostic::new_warning(
            "unused parameter pattern: `n₂`",
            Label::new(nat_file_id, 285..289, "unused parameter"),
        )
        .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]),
        // Unexpected type error
        Diagnostic::new_error(
            "unexpected type in application of `_+_`",
            Label::new(test_file_id, 37..44, "expected `Nat`, found `String`"),
        )
        .with_code("E0001")
        .with_secondary_labels(vec![Label::new(
            nat_file_id,
            130..155,
            "based on the definition of `_+_`",
        )]),
        // Incompatible match clause error
        Diagnostic::new_error(
            "`case` clauses have incompatible types",
            Label::new(
                fizz_buzz_file_id,
                163..166,
                "expected `String`, found `Nat`",
            ),
        )
        .with_code("E0308")
        .with_notes(vec![unindent::unindent(
            "
                expected type `String`
                   found type `Nat`
            ",
        )])
        .with_secondary_labels(vec![
            Label::new(
                fizz_buzz_file_id,
                62..166,
                "`case` clauses have incompatible types",
            ),
            Label::new(
                fizz_buzz_file_id,
                41..47,
                "expected type `String` found here",
            ),
        ]),
        // Incompatible match clause error
        Diagnostic::new_error(
            "`case` clauses have incompatible types",
            Label::new(
                fizz_buzz_file_id,
                303..306,
                "expected `String`, found `Nat`",
            ),
        )
        .with_code("E0308")
        .with_notes(vec![unindent::unindent(
            "
                expected type `String`
                   found type `Nat`
            ",
        )])
        .with_secondary_labels(vec![
            Label::new(
                fizz_buzz_file_id,
                186..306,
                "`case` clauses have incompatible types",
            ),
            Label::new(
                fizz_buzz_file_id,
                233..243,
                "this is found to be of type `String`",
            ),
            Label::new(
                fizz_buzz_file_id,
                259..265,
                "this is found to be of type `String`",
            ),
            Label::new(
                fizz_buzz_file_id,
                281..287,
                "this is found to be of type `String`",
            ),
        ]),
    ];

    let writer = StandardStream::stderr(opts.color.into());
    let config = codespan_reporting::Config::default();
    for diagnostic in &diagnostics {
        emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
    }
}
<commit_msg>Make example more succinct<commit_after>use structopt::StructOpt;

use codespan::Files;
use codespan_reporting::termcolor::StandardStream;
use codespan_reporting::{emit, ColorArg, Diagnostic, Label};

#[derive(Debug, StructOpt)]
#[structopt(name = "emit")]
pub struct Opts {
    /// Configure coloring of output
    #[structopt(
        long = "color",
        parse(try_from_str),
        default_value = "auto",
        raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
    )]
    pub color: ColorArg,
}

fn main() {
    let opts = Opts::from_args();
    let mut files = Files::new();

    let file_id1 = files.add(
        "Data/Nat.fun",
        unindent::unindent(
            "
                module Data.Nat where

                data Nat : Type where
                    zero : Nat
                    succ : Nat → Nat

                {-# BUILTIN NATRAL Nat #-}

                infixl 6 _+_ _-_

                _+_ : Nat → Nat → Nat
                zero    + n₂ = n₂
                succ n₁ + n₂ = succ (n₁ + n₂)

                _-_ : Nat → Nat → Nat
                n₁      - zero    = n₁
                zero    - succ n₂ = zero
                succ n₁ - succ n₂ = n₁ - n₂
            ",
        ),
    );

    let file_id2 = files.add(
        "Test.fun",
        unindent::unindent(
            r#"
                module Test where

                _ : Nat
                _ = 123 + "hello"
            "#,
        ),
    );

    let file_id3 = files.add(
        "FizzBuzz.fun",
        unindent::unindent(
            r#"
                module FizzBuzz where

                fizz₁ : Nat → String
                fizz₁ num = case (mod num 5) (mod num 3) of
                    0 0 => "FizzBuzz"
                    0 _ => "Fizz"
                    _ 0 => "Buzz"
                    _ _ => num

                fizz₂ num =
                    case (mod num 5) (mod num 3) of
                        0 0 => "FizzBuzz"
                        0 _ => "Fizz"
                        _ 0 => "Buzz"
                        _ _ => num
            "#,
        ),
    );

    let diagnostics = [
        // Unknown builtin error
        Diagnostic::new_error(
            "unknown builtin: `NATRAL`",
            Label::new(file_id1, 96..102, "unknown builtin"),
        )
        .with_notes(vec![
            "there is a builtin with a similar name: `NATURAL`".to_owned()
        ]),
        // Unused parameter warning
        Diagnostic::new_warning(
            "unused parameter pattern: `n₂`",
            Label::new(file_id1, 285..289, "unused parameter"),
        )
        .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]),
        // Unexpected type error
        Diagnostic::new_error(
            "unexpected type in application of `_+_`",
            Label::new(file_id2, 37..44, "expected `Nat`, found `String`"),
        )
        .with_code("E0001")
        .with_secondary_labels(vec![Label::new(
            file_id1,
            130..155,
            "based on the definition of `_+_`",
        )]),
        // Incompatible match clause error
        Diagnostic::new_error(
            "`case` clauses have incompatible types",
            Label::new(file_id3, 163..166, "expected `String`, found `Nat`"),
        )
        .with_code("E0308")
        .with_notes(vec![unindent::unindent(
            "
                expected type `String`
                   found type `Nat`
            ",
        )])
        .with_secondary_labels(vec![
            Label::new(file_id3, 62..166, "`case` clauses have incompatible types"),
            Label::new(file_id3, 41..47, "expected type `String` found here"),
        ]),
        // Incompatible match clause error
        Diagnostic::new_error(
            "`case` clauses have incompatible types",
            Label::new(file_id3, 303..306, "expected `String`, found `Nat`"),
        )
        .with_code("E0308")
        .with_notes(vec![unindent::unindent(
            "
                expected type `String`
                   found type `Nat`
            ",
        )])
        .with_secondary_labels(vec![
            Label::new(file_id3, 186..306, "`case` clauses have incompatible types"),
            Label::new(file_id3, 233..243, "this is found to be of type `String`"),
            Label::new(file_id3, 259..265, "this is found to be of type `String`"),
            Label::new(file_id3, 281..287, "this is found to be of type `String`"),
        ]),
    ];

    let writer = StandardStream::stderr(opts.color.into());
    let config = codespan_reporting::Config::default();
    for diagnostic in &diagnostics {
        emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
    }
}
<|endoftext|>


<commit_before>use parser::ParseError;
use std::collections::HashSet;
use text_range::TextRange;

pub struct InputError {
    /// The error message
    pub msg: String,
    /// The columns in which the error occurred
    pub pos: TextRange,
}

impl InputError {
    pub fn from_parser_error(err: ParseError) -> InputError {
        InputError {
            msg: generate_expected_string(err.expected),
            pos: TextRange {
                start: err.offset,
                end: err.column,
            },
        }
    }
}

fn generate_expected_string(expected: HashSet<&'static str>) -> String {
    let expected = expected
        .iter()
        .map(|s| s.to_string())
        .collect::<Vec<String>>();

    format!("expected {}", or_list(expected))
}

fn or_list(items: Vec<String>) -> String {
    let len = items.len();
    match len {
        0 => String::new(),
        1 => format!("{}", items[0]),
        _ => {
            let last = len - 1;
            format!("{} or {}", items[0..last].join(", "), items[last])
        }
    }
}

#[test]
fn test_or_list() {
    assert_eq!(or_list(vec![String::from("foo")]), String::from("foo"));

    assert_eq!(
        or_list(vec![String::from("foo"), String::from("bar")]),
        String::from("foo or bar")
    );

    assert_eq!(
        or_list(
            vec![
                String::from("foo"),
                String::from("bar"),
                String::from("baz"),
            ]
        ),
        String::from("foo, bar or baz")
    );

    assert_eq!(
        or_list(
            vec![
                String::from("a"),
                String::from("b"),
                String::from("c"),
                String::from("d"),
                String::from("e"),
            ]
        ),
        String::from("a, b, c, d or e")
    );
}
<commit_msg>Pass values by reference<commit_after>use parser::ParseError;
use std::collections::HashSet;
use text_range::TextRange;

pub struct InputError {
    /// The error message
    pub msg: String,
    /// The columns in which the error occurred
    pub pos: TextRange,
}

impl InputError {
    pub fn from_parser_error(err: ParseError) -> InputError {
        InputError {
            msg: generate_expected_string(&err.expected),
            pos: TextRange {
                start: err.offset,
                end: err.column,
            },
        }
    }
}

fn generate_expected_string(expected: &HashSet<&'static str>) -> String {
    let expected = expected
        .iter()
        .map(|s| s.to_string())
        .collect::<Vec<String>>();

    format!("expected {}", or_list(&expected))
}

fn or_list(items: &[String]) -> String {
    let len = items.len();
    match len {
        0 => String::new(),
        1 => items[0].clone(),
        _ => {
            let last = len - 1;
            format!("{} or {}", items[0..last].join(", "), items[last])
        }
    }
}

#[test]
fn test_or_list() {
    assert_eq!(or_list(&vec![String::from("foo")]), String::from("foo"));

    assert_eq!(
        or_list(&vec![String::from("foo"), String::from("bar")]),
        String::from("foo or bar")
    );

    assert_eq!(
        or_list(
            &vec![
                String::from("foo"),
                String::from("bar"),
                String::from("baz"),
            ]
        ),
        String::from("foo, bar or baz")
    );

    assert_eq!(
        or_list(
            &vec![
                String::from("a"),
                String::from("b"),
                String::from("c"),
                String::from("d"),
                String::from("e"),
            ]
        ),
        String::from("a, b, c, d or e")
    );
}
<|endoftext|>


<commit_before>use constants::*;
use std::ffi::OsString;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};

pub fn initialize() {
    println!("Initialize ...");

    let dir_name    = ".kic";
    let path_to_dir = Path::new(dir_name);
    if path_to_dir.exists() && path_to_dir.is_dir() {
        println!("  OK: \"{}\" directory has already exist.", dir_name);
    } else {
        match fs::create_dir(path_to_dir) {
            Ok(_)    => println!("  OK: Created \"{}\" directory.", dir_name),
            Err(why) => panic!("{:?}", why),
        }
    }

    let config_file    = "config";
    let path_to_config = path_to_dir.clone().join(config_file);
    create_setting_file(path_to_config, DEFAULT_CONFIG);

    let ignore_file    = "ignore";
    let path_to_ignore = path_to_dir.clone().join(ignore_file);
    let ignore_contents = walk_dir(".").iter()
        .map(|f| f.clone().into_string())
        .filter(|f| f.is_ok())
        .fold("".to_string(), |c, f| c + &(f.unwrap()) + "\n");
    create_setting_file(path_to_ignore, ignore_contents);
}

fn create_setting_file<S: AsRef<str>>(path_to_file: PathBuf, contents: S) {
    if path_to_file.exists() && path_to_file.is_file() {
        println!("  OK: \"{:?}\" file has already exist.", path_to_file);
    } else {
        match File::create(&path_to_file) {
            Ok(mut fp) => {
                println!("  OK: Created {:?} file.", path_to_file);
                match fp.write(contents.as_ref().as_bytes()) {
                    Ok(_)    => {},
                    Err(why) => panic!("{:?}", why),
                }
            },
            Err(why) => panic!("{:?}", why),
        }
    }
}

// You will be enable to use std::fs::walk_dir instead of this function in rust 1.6.0 or later
fn walk_dir<P: AsRef<Path>>(p: P) -> Vec<OsString> {
    let dirs = match fs::read_dir(p) {
        Ok(ds)   => ds,
        Err(why) => panic!("{:?}", why),
    };
    let dirs = dirs.filter(|d| d.is_ok())
        .flat_map(|d| {
            let p = d.unwrap().path();
            if IGNORED_NAMES.iter().any(|name| p.ends_with(name)) {
                Vec::new()
            } else if p.is_file() {
                vec![p.into_os_string()]
            } else {
                walk_dir(&p)
            }
        })
        .collect::<Vec<OsString>>();
    dirs
}

pub fn set_params() {
    println!("set parameters");
}

pub fn sweep() {
    println!("sweep");
}

pub fn burn() {
    println!("burn");
}

pub fn register_with_cron() {
    println!("register");
}

pub fn unregister_cron() {
    println!("unregister");
}

pub fn destroy() {
    println!("destroy");
}
<commit_msg>Fix output messages<commit_after>use constants::*;
use std::ffi::OsString;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};

pub fn initialize() {
    println!("Initialize ...");

    let dir_name    = ".kic";
    let path_to_dir = Path::new(dir_name);
    if path_to_dir.exists() && path_to_dir.is_dir() {
        println!("  OK: \"{}\" directory has already exist.", dir_name);
    } else {
        match fs::create_dir(path_to_dir) {
            Ok(_)    => println!("  OK: Created \"{}\" directory.", dir_name),
            Err(why) => panic!("{:?}", why),
        }
    }

    let config_file    = "config";
    let path_to_config = path_to_dir.clone().join(config_file);
    create_setting_file(path_to_config, DEFAULT_CONFIG);

    let ignore_file    = "ignore";
    let path_to_ignore = path_to_dir.clone().join(ignore_file);
    let ignore_contents = walk_dir(".").iter()
        .map(|f| f.clone().into_string())
        .filter(|f| f.is_ok())
        .fold("".to_string(), |c, f| c + &(f.unwrap()) + "\n");
    create_setting_file(path_to_ignore, ignore_contents);
}

fn create_setting_file<S: AsRef<str>>(path_to_file: PathBuf, contents: S) {
    let file_name = path_to_file.file_name().and_then(|f| f.to_str()).unwrap();
    if path_to_file.exists() && path_to_file.is_file() {
        println!("  OK: \"{}\" file has already exist.", file_name);
    } else {
        match File::create(&path_to_file) {
            Ok(mut fp) => {
                println!("  OK: Created \"{}\" file.", file_name);
                match fp.write(contents.as_ref().as_bytes()) {
                    Ok(_)    => {},
                    Err(why) => panic!("{:?}", why),
                }
            },
            Err(why) => panic!("{:?}", why),
        }
    }
}

// You will be enable to use std::fs::walk_dir instead of this function in rust 1.6.0 or later
fn walk_dir<P: AsRef<Path>>(p: P) -> Vec<OsString> {
    let dirs = match fs::read_dir(p) {
        Ok(ds)   => ds,
        Err(why) => panic!("{:?}", why),
    };
    let dirs = dirs.filter(|d| d.is_ok())
        .flat_map(|d| {
            let p = d.unwrap().path();
            if IGNORED_NAMES.iter().any(|name| p.ends_with(name)) {
                Vec::new()
            } else if p.is_file() {
                vec![p.into_os_string()]
            } else {
                walk_dir(&p)
            }
        })
        .collect::<Vec<OsString>>();
    dirs
}

pub fn set_params() {
    println!("set parameters");
}

pub fn sweep() {
    println!("sweep");
}

pub fn burn() {
    println!("burn");
}

pub fn register_with_cron() {
    println!("register");
}

pub fn unregister_cron() {
    println!("unregister");
}

pub fn destroy() {
    println!("destroy");
}
<|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/.

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::DM;
use devicemapper::types::{DataBlocks, Sectors};
use time;
use uuid::Uuid;
use serde_json;

use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;
use engine::Filesystem;
use engine::Pool;
use engine::RenameAction;
use engine::engine::Redundancy;
use engine::strat_engine::blockdev::wipe_sectors;
use engine::strat_engine::lineardev::LinearDev;
use engine::strat_engine::thinpooldev::ThinPoolDev;

use super::super::engine::{FilesystemUuid, HasName, HasUuid};
use super::super::structures::Table;

use super::serde_structs::StratSave;
use super::blockdev::{BlockDev, initialize, resolve_devices};
use super::filesystem::StratFilesystem;
use super::metadata::MIN_MDA_SECTORS;

pub const DATA_BLOCK_SIZE: Sectors = Sectors(2048);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: Uuid,
    pub block_devs: HashMap<PathBuf, BlockDev>,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
}

impl StratPool {
    pub fn new(name: &str,
               dm: &DM,
               paths: &[&Path],
               redundancy: Redundancy,
               force: bool)
               -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(&pool_uuid, devices, MIN_MDA_SECTORS, force));

        // TODO: We've got some temporary code in BlockDev::initialize that
        // makes sure we've got at least 2 blockdevs supplied - one for a meta
        // and one for data.  In the future, we will be able to deal with a
        // single blockdev.  When that code is added to use a single blockdev,
        // the check for 2 devs in BlockDev::initialize should be removed.
        assert!(bds.len() >= 2);

        let meta_dev = try!(LinearDev::new(&format!("stratis_{}_meta", name), dm, &vec![&bds[0]]));
        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.path()), Sectors(0), DATA_BLOCK_SIZE));
        let data_dev = try!(LinearDev::new(&format!("stratis_{}_data", name),
                                           dm,
                                           &Vec::from_iter(bds[1..].iter())));
        try!(wipe_sectors(&try!(data_dev.path()), Sectors(0), DATA_BLOCK_SIZE));
        let length = try!(data_dev.size()).sectors();

        // TODO Fix hard coded data blocksize and low water mark.
        let thinpool_dev = try!(ThinPoolDev::new(&format!("stratis_{}_thinpool", name),
                                                 dm,
                                                 length,
                                                 DATA_BLOCK_SIZE,
                                                 DataBlocks(256000),
                                                 meta_dev,
                                                 data_dev));

        let mut blockdevs = HashMap::new();
        for bd in bds {
            blockdevs.insert(bd.devnode.clone(), bd);
        }
        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: blockdevs,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Return the metadata from the first blockdev with up-to-date, readable
    /// metadata.
    /// Precondition: All Blockdevs in blockdevs must belong to the same pool.
    pub fn read_metadata(blockdevs: &[&BlockDev]) -> Option<Vec<u8>> {
        if blockdevs.is_empty() {
            return None;
        }

        let most_recent_blockdev = blockdevs.iter()
            .max_by_key(|bd| bd.last_update_time())
            .expect("must be a maximum since bds is non-empty");

        let most_recent_time = most_recent_blockdev.last_update_time();

        if most_recent_time.is_none() {
            return None;
        }

        for bd in blockdevs.iter().filter(|b| b.last_update_time() == most_recent_time) {
            match bd.load_state() {
                Ok(Some(data)) => return Some(data),
                _ => continue,
            }
        }

        None
    }

    /// Write the given data to all blockdevs
    pub fn write_metadata(&mut self) -> EngineResult<()> {

        let data = try!(serde_json::to_string(&self.to_save()));

        // TODO: Cap # of blockdevs written to, as described in SWDD
        // TODO: Check current time against global last updated, and use
        // alternate time value if earlier, as described in SWDD

        let time = time::now().to_timespec();

        // TODO: Do something better than panic when saving to blockdev fails.
        for (_, bd) in &mut self.block_devs {
            bd.save_state(&time, data.as_bytes()).unwrap();
        }

        Ok(())
    }

    pub fn to_save(&self) -> StratSave {
        StratSave {
            name: self.name.clone(),
            id: self.pool_uuid.simple().to_string(),
            block_devs: self.block_devs
                .iter()
                .map(|(_, bd)| (bd.uuid().simple().to_string(), bd.to_save()))
                .collect(),
        }
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let dm = try!(DM::new());
            let new_filesystem = try!(StratFilesystem::new(uuid, name, &dm, &mut self.thin_pool));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(&self.pool_uuid, devices, MIN_MDA_SECTORS, force));
        let bdev_paths = bds.iter().map(|p| p.devnode.clone()).collect();
        for bd in bds {
            self.block_devs.insert(bd.devnode.clone(), bd);
        }
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(mut self) -> EngineResult<()> {

        // TODO Do we want to create a new File each time we interact with DM?
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));

        for (_, bd) in self.block_devs.drain() {
            try!(bd.wipe_metadata());
        }

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &FilesystemUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}
<commit_msg>Give pool a save_state() and a load_state() method<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/.

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::DM;
use devicemapper::types::{DataBlocks, Sectors};
use time::{now, Timespec};
use uuid::Uuid;
use serde_json;

use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;
use engine::Filesystem;
use engine::Pool;
use engine::RenameAction;
use engine::engine::Redundancy;
use engine::strat_engine::blockdev::wipe_sectors;
use engine::strat_engine::lineardev::LinearDev;
use engine::strat_engine::thinpooldev::ThinPoolDev;

use super::super::engine::{FilesystemUuid, HasName, HasUuid};
use super::super::structures::Table;

use super::serde_structs::StratSave;
use super::blockdev::{BlockDev, initialize, resolve_devices};
use super::filesystem::StratFilesystem;
use super::metadata::MIN_MDA_SECTORS;

pub const DATA_BLOCK_SIZE: Sectors = Sectors(2048);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: Uuid,
    pub block_devs: HashMap<PathBuf, BlockDev>,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
}

impl StratPool {
    pub fn new(name: &str,
               dm: &DM,
               paths: &[&Path],
               redundancy: Redundancy,
               force: bool)
               -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(&pool_uuid, devices, MIN_MDA_SECTORS, force));

        // TODO: We've got some temporary code in BlockDev::initialize that
        // makes sure we've got at least 2 blockdevs supplied - one for a meta
        // and one for data.  In the future, we will be able to deal with a
        // single blockdev.  When that code is added to use a single blockdev,
        // the check for 2 devs in BlockDev::initialize should be removed.
        assert!(bds.len() >= 2);

        let meta_dev = try!(LinearDev::new(&format!("stratis_{}_meta", name), dm, &vec![&bds[0]]));
        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.path()), Sectors(0), DATA_BLOCK_SIZE));
        let data_dev = try!(LinearDev::new(&format!("stratis_{}_data", name),
                                           dm,
                                           &Vec::from_iter(bds[1..].iter())));
        try!(wipe_sectors(&try!(data_dev.path()), Sectors(0), DATA_BLOCK_SIZE));
        let length = try!(data_dev.size()).sectors();

        // TODO Fix hard coded data blocksize and low water mark.
        let thinpool_dev = try!(ThinPoolDev::new(&format!("stratis_{}_thinpool", name),
                                                 dm,
                                                 length,
                                                 DATA_BLOCK_SIZE,
                                                 DataBlocks(256000),
                                                 meta_dev,
                                                 data_dev));

        let mut blockdevs = HashMap::new();
        for bd in bds {
            blockdevs.insert(bd.devnode.clone(), bd);
        }
        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: blockdevs,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Return the metadata from the first blockdev with up-to-date, readable
    /// metadata.
    /// Precondition: All Blockdevs in blockdevs must belong to the same pool.
    pub fn load_state(blockdevs: &[&BlockDev]) -> Option<Vec<u8>> {
        if blockdevs.is_empty() {
            return None;
        }

        let most_recent_blockdev = blockdevs.iter()
            .max_by_key(|bd| bd.last_update_time())
            .expect("must be a maximum since bds is non-empty");

        let most_recent_time = most_recent_blockdev.last_update_time();

        if most_recent_time.is_none() {
            return None;
        }

        for bd in blockdevs.iter().filter(|b| b.last_update_time() == most_recent_time) {
            match bd.load_state() {
                Ok(Some(data)) => return Some(data),
                _ => continue,
            }
        }

        None
    }

    /// Write the given data to all blockdevs marking with specified time.
    pub fn save_state(devs: &mut [&mut BlockDev],
                      time: &Timespec,
                      metadata: &[u8])
                      -> EngineResult<()> {
        // TODO: Do something better than panic when saving to blockdev fails.
        for bd in devs {
            bd.save_state(time, metadata).unwrap();
        }
        Ok(())
    }

    /// Write pool metadata to all its blockdevs marking with current time.

    // TODO: Cap # of blockdevs written to, as described in SWDD

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    pub fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&self.to_save()));
        let mut blockdevs: Vec<&mut BlockDev> = self.block_devs.values_mut().collect();
        StratPool::save_state(&mut blockdevs, &now().to_timespec(), data.as_bytes())
    }

    pub fn to_save(&self) -> StratSave {
        StratSave {
            name: self.name.clone(),
            id: self.pool_uuid.simple().to_string(),
            block_devs: self.block_devs
                .iter()
                .map(|(_, bd)| (bd.uuid().simple().to_string(), bd.to_save()))
                .collect(),
        }
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let dm = try!(DM::new());
            let new_filesystem = try!(StratFilesystem::new(uuid, name, &dm, &mut self.thin_pool));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(&self.pool_uuid, devices, MIN_MDA_SECTORS, force));
        let bdev_paths = bds.iter().map(|p| p.devnode.clone()).collect();
        for bd in bds {
            self.block_devs.insert(bd.devnode.clone(), bd);
        }
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(mut self) -> EngineResult<()> {

        // TODO Do we want to create a new File each time we interact with DM?
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));

        for (_, bd) in self.block_devs.drain() {
            try!(bd.wipe_metadata());
        }

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &FilesystemUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}
<|endoftext|>


<commit_before>//! Template declaration and instantiation related things.
//!
//! The nomenclature surrounding templates is often confusing, so here are a few
//! brief definitions:
//!
//! * "Template definition": a class/struct/alias/function definition that takes
//! generic template parameters. For example:
//!
//! ```c++
//! template<typename T>
//! class List<T> {
//!     // ...
//! };
//! ```
//!
//! * "Template instantiation": an instantiation is a use of a template with
//! concrete template arguments. For example, `List<int>`.
//!
//! * "Template specialization": an alternative template definition providing a
//! custom definition for instantiations with the matching template
//! arguments. This C++ feature is unsupported by bindgen. For example:
//!
//! ```c++
//! template<>
//! class List<int> {
//!     // Special layout for int lists...
//! };
//! ```

use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;

/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
    /// Any extra information the implementor might need to make this decision.
    type Extra;

    /// Convert this thing to the item id of a named template type parameter.
    fn as_named(&self,
                ctx: &BindgenContext,
                extra: &Self::Extra)
                -> Option<ItemId>;

    /// Is this a named template type parameter?
    fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
        self.as_named(ctx, extra).is_some()
    }
}

/// A concrete instantiation of a generic template.
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
    /// The template definition which this is instantiating.
    definition: ItemId,
    /// The concrete template arguments, which will be substituted in the
    /// definition for the generic template parameters.
    args: Vec<ItemId>,
}

impl TemplateInstantiation {
    /// Construct a new template instantiation from the given parts.
    pub fn new<I>(template_definition: ItemId,
                  template_args: I)
                  -> TemplateInstantiation
        where I: IntoIterator<Item = ItemId>,
    {
        TemplateInstantiation {
            definition: template_definition,
            args: template_args.into_iter().collect(),
        }
    }

    /// Get the template definition for this instantiation.
    pub fn template_definition(&self) -> ItemId {
        self.definition
    }

    /// Get the concrete template arguments used in this instantiation.
    pub fn template_arguments(&self) -> &[ItemId] {
        &self.args[..]
    }

    /// Parse a `TemplateInstantiation` from a clang `Type`.
    pub fn from_ty(ty: &clang::Type,
                   ctx: &mut BindgenContext)
                   -> Option<TemplateInstantiation> {
        use clang_sys::*;

        let template_args = ty.template_args()
            .map_or(vec![], |args| {
                args.filter(|t| t.kind() != CXType_Invalid)
                    .map(|t| {
                        Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                    })
                    .collect()
            });

        if ty.declaration().is_builtin() {
            return None;
        }

        let definition = ty.declaration()
            .specialized()
            .or_else(|| {
                let mut template_ref = None;
                ty.declaration().visit(|child| {
                    if child.kind() == CXCursor_TemplateRef {
                        template_ref = Some(child);
                        return CXVisit_Break;
                    }

                    // Instantiations of template aliases might have the
                    // TemplateRef to the template alias definition arbitrarily
                    // deep, so we need to recurse here and not only visit
                    // direct children.
                    CXChildVisit_Recurse
                });

                template_ref.and_then(|cur| cur.referenced())
            })
            .expect("Should have found the template definition one way or another");

        let template_definition =
            Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);

        Some(TemplateInstantiation::new(template_definition, template_args))
    }

    /// Does this instantiation have a vtable?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_vtable(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_vtable(ctx))
    }

    /// Does this instantiation have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_destructor(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
    }
}

impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy_in_array(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
    }
}

impl CanDeriveDebug for TemplateInstantiation {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
        ctx.resolve_type(self.definition)
            .as_comp()
            .and_then(|c| {
                // For non-type template parameters, we generate an opaque
                // blob, and in this case the instantiation has a better
                // idea of the layout than the definition does.
                if c.has_non_type_template_params() {
                    let opaque = layout.unwrap_or(Layout::zero()).opaque();
                    Some(opaque.can_derive_debug(ctx, ()))
                } else {
                    None
                }
            })
            .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
    }
}

impl Trace for TemplateInstantiation {
    type Extra = ();

    fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
        for &item in self.template_arguments() {
            tracer.visit_kind(item, EdgeKind::TemplateArgument);
        }
    }
}
<commit_msg>Generalize fallibility template instantiation fallibility<commit_after>//! Template declaration and instantiation related things.
//!
//! The nomenclature surrounding templates is often confusing, so here are a few
//! brief definitions:
//!
//! * "Template definition": a class/struct/alias/function definition that takes
//! generic template parameters. For example:
//!
//! ```c++
//! template<typename T>
//! class List<T> {
//!     // ...
//! };
//! ```
//!
//! * "Template instantiation": an instantiation is a use of a template with
//! concrete template arguments. For example, `List<int>`.
//!
//! * "Template specialization": an alternative template definition providing a
//! custom definition for instantiations with the matching template
//! arguments. This C++ feature is unsupported by bindgen. For example:
//!
//! ```c++
//! template<>
//! class List<int> {
//!     // Special layout for int lists...
//! };
//! ```

use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;

/// A trait for things which may or may not be a named template type parameter.
pub trait AsNamed {
    /// Any extra information the implementor might need to make this decision.
    type Extra;

    /// Convert this thing to the item id of a named template type parameter.
    fn as_named(&self,
                ctx: &BindgenContext,
                extra: &Self::Extra)
                -> Option<ItemId>;

    /// Is this a named template type parameter?
    fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
        self.as_named(ctx, extra).is_some()
    }
}

/// A concrete instantiation of a generic template.
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
    /// The template definition which this is instantiating.
    definition: ItemId,
    /// The concrete template arguments, which will be substituted in the
    /// definition for the generic template parameters.
    args: Vec<ItemId>,
}

impl TemplateInstantiation {
    /// Construct a new template instantiation from the given parts.
    pub fn new<I>(template_definition: ItemId,
                  template_args: I)
                  -> TemplateInstantiation
        where I: IntoIterator<Item = ItemId>,
    {
        TemplateInstantiation {
            definition: template_definition,
            args: template_args.into_iter().collect(),
        }
    }

    /// Get the template definition for this instantiation.
    pub fn template_definition(&self) -> ItemId {
        self.definition
    }

    /// Get the concrete template arguments used in this instantiation.
    pub fn template_arguments(&self) -> &[ItemId] {
        &self.args[..]
    }

    /// Parse a `TemplateInstantiation` from a clang `Type`.
    pub fn from_ty(ty: &clang::Type,
                   ctx: &mut BindgenContext)
                   -> Option<TemplateInstantiation> {
        use clang_sys::*;

        let template_args = ty.template_args()
            .map_or(vec![], |args| {
                args.filter(|t| t.kind() != CXType_Invalid)
                    .map(|t| {
                        Item::from_ty_or_ref(t, t.declaration(), None, ctx)
                    })
                    .collect()
            });

        let definition = ty.declaration()
            .specialized()
            .or_else(|| {
                let mut template_ref = None;
                ty.declaration().visit(|child| {
                    if child.kind() == CXCursor_TemplateRef {
                        template_ref = Some(child);
                        return CXVisit_Break;
                    }

                    // Instantiations of template aliases might have the
                    // TemplateRef to the template alias definition arbitrarily
                    // deep, so we need to recurse here and not only visit
                    // direct children.
                    CXChildVisit_Recurse
                });

                template_ref.and_then(|cur| cur.referenced())
            });

        let definition = match definition {
            None => return None,
            Some(def) => def,
        };

        let template_definition =
            Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);

        Some(TemplateInstantiation::new(template_definition, template_args))
    }

    /// Does this instantiation have a vtable?
    pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_vtable(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_vtable(ctx))
    }

    /// Does this instantiation have a destructor?
    pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
        ctx.resolve_type(self.definition).has_destructor(ctx) ||
        self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
    }
}

impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
    type Extra = ();

    fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
    }

    fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
        self.definition.can_derive_copy_in_array(ctx, ()) &&
        self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
    }
}

impl CanDeriveDebug for TemplateInstantiation {
    type Extra = Option<Layout>;

    fn can_derive_debug(&self,
                        ctx: &BindgenContext,
                        layout: Option<Layout>)
                        -> bool {
        self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
        ctx.resolve_type(self.definition)
            .as_comp()
            .and_then(|c| {
                // For non-type template parameters, we generate an opaque
                // blob, and in this case the instantiation has a better
                // idea of the layout than the definition does.
                if c.has_non_type_template_params() {
                    let opaque = layout.unwrap_or(Layout::zero()).opaque();
                    Some(opaque.can_derive_debug(ctx, ()))
                } else {
                    None
                }
            })
            .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
    }
}

impl Trace for TemplateInstantiation {
    type Extra = ();

    fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
        for &item in self.template_arguments() {
            tracer.visit_kind(item, EdgeKind::TemplateArgument);
        }
    }
}
<|endoftext|>