<commit_before>//! Structs and methods for searching for tweets.

use std::collections::HashMap;
use std::fmt;

use rustc_serialize::json;

use auth;
use error;
use error::Error::{InvalidResponse, MissingValue};
use links;
use tweet::Tweet;
use common::*;

///Begin setting up a tweet search with the given query.
pub fn search<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder {
        query: query,
        lang: None,
        result_type: None,
        count: None,
        until: None,
        geocode: None,
    }
}

///Represents what kind of tweets should be included in search results.
#[derive(Debug, Copy, Clone)]
pub enum ResultType {
    ///Return only the most recent tweets in the response.
    Recent,
    ///Return only the most popular tweets in the response.
    Popular,
    ///Include both popular and real-time results in the response.
    Mixed,
}

///Display impl that turns the variants into strings that can be used as search parameters.
impl fmt::Display for ResultType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResultType::Recent => write!(f, "recent"),
            ResultType::Popular => write!(f, "popular"),
            ResultType::Mixed => write!(f, "mixed"),
        }
    }
}

///Represents a radius around a given location to return search results for.
pub enum Distance {
    ///A radius given in miles.
    Miles(u32),
    ///A radius given in kilometers.
    Kilometers(u32),
}

///Represents a tweet search query before being sent.
#[must_use = "SearchBuilder is lazy and won't do anything unless `call`ed"]
pub struct SearchBuilder<'a> {
    ///The text to search for.
    query: &'a str,
    lang: Option<&'a str>,
    result_type: Option<ResultType>,
    count: Option<u32>,
    until: Option<(u32, u32, u32)>,
    geocode: Option<(f32, f32, Distance)>
}

impl<'a> SearchBuilder<'a> {
    ///Restrict search results to those that have been machine-parsed as the given two-letter
    ///language code.
    pub fn lang(self, lang: &'a str) -> Self {
        SearchBuilder {
            query: self.query,
            lang: Some(lang),
            result_type: self.result_type,
            count: self.count,
            until: self.until,
            geocode: self.geocode,
        }
    }

    ///Specify the type of search results to include. The default is `Recent`.
    pub fn result_type(self, result_type: ResultType) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: Some(result_type),
            count: self.count,
            until: self.until,
            geocode: self.geocode,
        }
    }

    ///Set the number of tweets to return per-page, up to a maximum of 100. The default is 15.
    pub fn count(self, count: u32) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: self.result_type,
            count: Some(count),
            until: self.until,
            geocode: self.geocode,
        }
    }

    ///Returns tweets created before the given date. Keep in mind that search is limited to the
    ///last 7 days of results, so giving a date here that's older than a week will return no
    ///results.
    pub fn until(self, year: u32, month: u32, day: u32) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: self.result_type,
            count: self.count,
            until: Some((year, month, day)),
            geocode: self.geocode,
        }
    }

    ///Restricts results to users located within the given radius of the given coordinate. This is
    ///preferably populated from location-tagged tweets, but can be filled in from the user's
    ///profile as a fallback.
    pub fn geocode(self, latitude: f32, longitude: f32, radius: Distance) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: self.result_type,
            count: self.count,
            until: self.until,
            geocode: Some((latitude, longitude, radius)),
        }
    }

    ///Finalize the search terms and return the first page of responses.
    pub fn call(self, con_token: &auth::Token, access_token: &auth::Token) -> WebResponse<SearchResult<'a>> {
        let mut params = HashMap::new();

        add_param(&mut params, "q", self.query);

        if let Some(lang) = self.lang {
            add_param(&mut params, "lang", lang);
        }

        if let Some(result_type) = self.result_type {
            add_param(&mut params, "result_type", result_type.to_string());
        }

        if let Some(count) = self.count {
            add_param(&mut params, "count", count.to_string());
        }

        if let Some((year, month, day)) = self.until {
            add_param(&mut params, "until", format!("{}-{}-{}", year, month, day));
        }

        if let Some((lat, lon, radius)) = self.geocode {
            match radius {
                Distance::Miles(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}mi", lat, lon, r)),
                Distance::Kilometers(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}km", lat, lon, r)),
            };
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, con_token, access_token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.response.params = Some(params);
        Ok(ret)
    }
}

///Represents a page of search results, along with metadata to request the next or previous page.
#[derive(Debug)]
pub struct SearchResult<'a> {
    ///The list of statuses in this page of results.
    pub statuses: Vec<Tweet>,
    ///The query used to generate this page of results. Note that changing this will not affect the
    ///`next_page` method.
    pub query: String,
    max_id: i64,
    since_id: i64,
    params: Option<ParamList<'a>>,
}

impl<'a> FromJson for SearchResult<'a> {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("SearchResult received json that wasn't an object", Some(input.to_string())));
        }

        let metadata = try!(input.find("search_metadata").ok_or(MissingValue("search_metadata")));

        Ok(SearchResult {
            statuses: try!(field(input, "statuses")),
            query: try!(field(metadata, "query")),
            max_id: try!(field(metadata, "max_id")),
            since_id: try!(field(metadata, "since_id")),
            params: None,
        })
    }
}

impl<'a> SearchResult<'a> {
    ///Load the next page of search results for the same query.
    pub fn older(&self, con_token: &auth::Token, access_token: &auth::Token) -> WebResponse<SearchResult> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("since_id");

        if let Some(min_id) = self.statuses.iter().map(|t| t.id).min() {
            add_param(&mut params, "max_id", (min_id - 1).to_string());
        }
        else {
            params.remove("max_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, con_token, access_token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.response.params = Some(params);
        Ok(ret)
    }

    ///Load the previous page of search results for the same query.
    pub fn newer(&self, con_token: &auth::Token, access_token: &auth::Token) -> WebResponse<SearchResult> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("max_id");

        if let Some(max_id) = self.statuses.iter().map(|t| t.id).max() {
            add_param(&mut params, "since_id", max_id.to_string());
        }
        else {
            params.remove("since_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, con_token, access_token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.response.params = Some(params);
        Ok(ret)
    }
}
<commit_msg>add docs example for search<commit_after>//! Structs and methods for searching for tweets.
//!
//! Since there are several optional parameters for searches, egg-mode handles it with a builder
//! pattern. To begin, call `search` with your requested search term. Additional parameters can be
//! added onto the `SearchBuilder` struct that is returned. When you're ready to load the first
//! page of results, hand your tokens to `call`.
//!
//! ```rust,no_run
//! # let con_token = egg_mode::Token::new("", "");
//! # let access_token = egg_mode::Token::new("", "");
//! use egg_mode::search::{self, ResultType};
//!
//! let search = search::search("rustlang")
//!                     .result_type(ResultType::Recent)
//!                     .call(&con_token, &access_token)
//!                     .unwrap();
//!
//! for tweet in &search.response.statuses {
//!     println!("(@{}) {}", tweet.user.screen_name, tweet.text);
//! }
//! ```

use std::collections::HashMap;
use std::fmt;

use rustc_serialize::json;

use auth;
use error;
use error::Error::{InvalidResponse, MissingValue};
use links;
use tweet::Tweet;
use common::*;

///Begin setting up a tweet search with the given query.
pub fn search<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder {
        query: query,
        lang: None,
        result_type: None,
        count: None,
        until: None,
        geocode: None,
    }
}

///Represents what kind of tweets should be included in search results.
#[derive(Debug, Copy, Clone)]
pub enum ResultType {
    ///Return only the most recent tweets in the response.
    Recent,
    ///Return only the most popular tweets in the response.
    Popular,
    ///Include both popular and real-time results in the response.
    Mixed,
}

///Display impl that turns the variants into strings that can be used as search parameters.
impl fmt::Display for ResultType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResultType::Recent => write!(f, "recent"),
            ResultType::Popular => write!(f, "popular"),
            ResultType::Mixed => write!(f, "mixed"),
        }
    }
}

///Represents a radius around a given location to return search results for.
pub enum Distance {
    ///A radius given in miles.
    Miles(u32),
    ///A radius given in kilometers.
    Kilometers(u32),
}

///Represents a tweet search query before being sent.
#[must_use = "SearchBuilder is lazy and won't do anything unless `call`ed"]
pub struct SearchBuilder<'a> {
    ///The text to search for.
    query: &'a str,
    lang: Option<&'a str>,
    result_type: Option<ResultType>,
    count: Option<u32>,
    until: Option<(u32, u32, u32)>,
    geocode: Option<(f32, f32, Distance)>
}

impl<'a> SearchBuilder<'a> {
    ///Restrict search results to those that have been machine-parsed as the given two-letter
    ///language code.
    pub fn lang(self, lang: &'a str) -> Self {
        SearchBuilder {
            query: self.query,
            lang: Some(lang),
            result_type: self.result_type,
            count: self.count,
            until: self.until,
            geocode: self.geocode,
        }
    }

    ///Specify the type of search results to include. The default is `Recent`.
    pub fn result_type(self, result_type: ResultType) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: Some(result_type),
            count: self.count,
            until: self.until,
            geocode: self.geocode,
        }
    }

    ///Set the number of tweets to return per-page, up to a maximum of 100. The default is 15.
    pub fn count(self, count: u32) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: self.result_type,
            count: Some(count),
            until: self.until,
            geocode: self.geocode,
        }
    }

    ///Returns tweets created before the given date. Keep in mind that search is limited to the
    ///last 7 days of results, so giving a date here that's older than a week will return no
    ///results.
    pub fn until(self, year: u32, month: u32, day: u32) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: self.result_type,
            count: self.count,
            until: Some((year, month, day)),
            geocode: self.geocode,
        }
    }

    ///Restricts results to users located within the given radius of the given coordinate. This is
    ///preferably populated from location-tagged tweets, but can be filled in from the user's
    ///profile as a fallback.
    pub fn geocode(self, latitude: f32, longitude: f32, radius: Distance) -> Self {
        SearchBuilder {
            query: self.query,
            lang: self.lang,
            result_type: self.result_type,
            count: self.count,
            until: self.until,
            geocode: Some((latitude, longitude, radius)),
        }
    }

    ///Finalize the search terms and return the first page of responses.
    pub fn call(self, con_token: &auth::Token, access_token: &auth::Token) -> WebResponse<SearchResult<'a>> {
        let mut params = HashMap::new();

        add_param(&mut params, "q", self.query);

        if let Some(lang) = self.lang {
            add_param(&mut params, "lang", lang);
        }

        if let Some(result_type) = self.result_type {
            add_param(&mut params, "result_type", result_type.to_string());
        }

        if let Some(count) = self.count {
            add_param(&mut params, "count", count.to_string());
        }

        if let Some((year, month, day)) = self.until {
            add_param(&mut params, "until", format!("{}-{}-{}", year, month, day));
        }

        if let Some((lat, lon, radius)) = self.geocode {
            match radius {
                Distance::Miles(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}mi", lat, lon, r)),
                Distance::Kilometers(r) => add_param(&mut params, "geocode", format!("{:.6},{:.6},{}km", lat, lon, r)),
            };
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, con_token, access_token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.response.params = Some(params);
        Ok(ret)
    }
}

///Represents a page of search results, along with metadata to request the next or previous page.
#[derive(Debug)]
pub struct SearchResult<'a> {
    ///The list of statuses in this page of results.
    pub statuses: Vec<Tweet>,
    ///The query used to generate this page of results. Note that changing this will not affect the
    ///`next_page` method.
    pub query: String,
    max_id: i64,
    since_id: i64,
    params: Option<ParamList<'a>>,
}

impl<'a> FromJson for SearchResult<'a> {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse("SearchResult received json that wasn't an object", Some(input.to_string())));
        }

        let metadata = try!(input.find("search_metadata").ok_or(MissingValue("search_metadata")));

        Ok(SearchResult {
            statuses: try!(field(input, "statuses")),
            query: try!(field(metadata, "query")),
            max_id: try!(field(metadata, "max_id")),
            since_id: try!(field(metadata, "since_id")),
            params: None,
        })
    }
}

impl<'a> SearchResult<'a> {
    ///Load the next page of search results for the same query.
    pub fn older(&self, con_token: &auth::Token, access_token: &auth::Token) -> WebResponse<SearchResult> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("since_id");

        if let Some(min_id) = self.statuses.iter().map(|t| t.id).min() {
            add_param(&mut params, "max_id", (min_id - 1).to_string());
        }
        else {
            params.remove("max_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, con_token, access_token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.response.params = Some(params);
        Ok(ret)
    }

    ///Load the previous page of search results for the same query.
    pub fn newer(&self, con_token: &auth::Token, access_token: &auth::Token) -> WebResponse<SearchResult> {
        let mut params = self.params.as_ref().cloned().unwrap_or_default();
        params.remove("max_id");

        if let Some(max_id) = self.statuses.iter().map(|t| t.id).max() {
            add_param(&mut params, "since_id", max_id.to_string());
        }
        else {
            params.remove("since_id");
        }

        let mut resp = try!(auth::get(links::statuses::SEARCH, con_token, access_token, Some(&params)));

        let mut ret: Response<SearchResult> = try!(parse_response(&mut resp));
        ret.response.params = Some(params);
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use backend::{AnimeEntry, AnimeInfo, Status, SyncBackend};
use chrono::{Date, Local};
use error::SeriesError;
use input::{self, Answer};
use process;
use regex::Regex;
use std;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use toml;

#[derive(Debug)]
pub struct Series<B>
where
    B: SyncBackend,
{
    sync_backend: B,
    pub episode_data: EpisodeData,
    pub save_data: SaveData,
    pub save_path: PathBuf,
}

impl<B> Series<B>
where
    B: SyncBackend,
{
    pub const DATA_FILE_NAME: &'static str = ".anup";

    pub fn from_data(episode_data: EpisodeData, sync_backend: B) -> Result<Series<B>, SeriesError> {
        let save_path = PathBuf::from(&episode_data.path).join(Series::<B>::DATA_FILE_NAME);
        let save_data = SaveData::from_path_or_default(&save_path)?;

        let series = Series {
            sync_backend,
            episode_data,
            save_data,
            save_path,
        };

        Ok(series)
    }

    pub fn load_season(&mut self, season: u32) -> Result<Season<B>, SeriesError> {
        let season_info = self.get_season_info(season)?;
        let season_ep_offset = self.calculate_season_offset(season);

        let list_entry = self.get_list_entry(season_info.clone())?;

        let season = Season {
            sync_backend: &self.sync_backend,
            list_entry,
            ep_offset: season_ep_offset,
            local_episodes: &self.episode_data.episodes,
        };

        Ok(season)
    }

    pub fn save_data(&self) -> Result<(), SeriesError> {
        self.save_data.write_to(&self.save_path)
    }

    fn get_season_info(&mut self, season: u32) -> Result<AnimeInfo, SeriesError> {
        let num_seasons = self.save_data.seasons.len() as u32;

        if season >= num_seasons {
            let mut series = None;

            for cur_season in num_seasons..=season {
                println!(
                    "select the correct series for season {} of [{}]:",
                    1 + cur_season,
                    self.episode_data.series_name
                );

                let series_info = self.search_and_select_series(&self.episode_data.series_name)?;
                self.save_data.seasons.push(series_info.clone().into());

                series = Some(series_info);
            }

            self.save_data()?;

            // This unwrap should never fail, as the enclosing if statement ensures the for loop will set the
            // series variable at least once
            Ok(series.unwrap())
        } else {
            let season_info = &self.save_data.seasons[season as usize];

            let series = self
                .sync_backend
                .get_series_info_by_id(season_info.series_id)?;

            Ok(series)
        }
    }

    fn calculate_season_offset(&self, season: u32) -> u32 {
        let mut offset = 0;

        for cur_season in 0..(season as usize) {
            if let Some(season_eps) = self.save_data.seasons[cur_season].episodes {
                offset += season_eps;
            }
        }

        offset
    }

    fn search_and_select_series(&self, name: &str) -> Result<AnimeInfo, SeriesError> {
        let mut found = self.sync_backend.search_by_name(name)?;

        println!("{} results for [{}]:", B::name(), name);
        println!("enter the number next to the desired series:\n");

        println!("0 [custom search]");

        for (i, series) in found.iter().enumerate() {
            println!("{} [{}]", 1 + i, series.title);
        }

        let index = input::read_range(0, found.len())?;

        if index == 0 {
            println!("enter the name you want to search for:");

            let name = input::read_line()?;
            self.search_and_select_series(&name)
        } else {
            let info = found.swap_remove(index - 1);
            Ok(info)
        }
    }

    fn get_list_entry(&self, info: AnimeInfo) -> Result<AnimeEntry, SeriesError> {
        let found = self.sync_backend.get_list_entry(info.clone())?;

        match found {
            Some(mut entry) => {
                if entry.status == Status::Completed {
                    self.prompt_to_rewatch(&mut entry)?;
                }

                Ok(entry)
            }
            None => {
                let mut entry = AnimeEntry::new(info);
                entry.status = Status::Watching;
                entry.start_date = Some(Local::today());

                self.sync_backend.update_list_entry(&entry)?;
                Ok(entry)
            }
        }
    }

    fn prompt_to_rewatch(&self, entry: &mut AnimeEntry) -> Result<(), SeriesError> {
        println!("[{}] already completed", entry.info.title);
        println!("do you want to rewatch it? (Y/n)");

        if input::read_yn(Answer::Yes)? {
            entry.status = Status::Rewatching;
            entry.watched_episodes = 0;

            println!("do you want to reset the start and end date? (Y/n)");

            if input::read_yn(Answer::Yes)? {
                entry.start_date = Some(Local::today());
                entry.finish_date = None;
            }

            self.sync_backend.update_list_entry(entry)?;
        } else {
            // No point in continuing in this case
            std::process::exit(0);
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct Season<'a, B>
where
    B: 'a + SyncBackend,
{
    sync_backend: &'a B,
    pub list_entry: AnimeEntry,
    pub local_episodes: &'a HashMap<u32, PathBuf>,
    pub ep_offset: u32,
}

impl<'a, B> Season<'a, B>
where
    B: 'a + SyncBackend,
{
    pub fn play_episode(&mut self, relative_ep: u32) -> Result<(), SeriesError> {
        let ep_num = self.ep_offset + relative_ep;

        let path = self
            .local_episodes
            .get(&ep_num)
            .ok_or_else(|| SeriesError::EpisodeNotFound(ep_num))?;

        let status = process::open_with_default(path).map_err(SeriesError::FailedToOpenPlayer)?;
        self.list_entry.watched_episodes = relative_ep;

        if !status.success() {
            println!("video player not exited normally");
            println!("do you still want to count the episode as watched? (y/N)");

            if !input::read_yn(Answer::No)? {
                return Ok(());
            }
        }

        match self.list_entry.info.episodes {
            Some(total_eps) if relative_ep >= total_eps => self.series_completed()?,
            _ => self.episode_completed()?,
        }

        Ok(())
    }

    pub fn play_all_episodes(&mut self) -> Result<(), SeriesError> {
        loop {
            let next_ep = self.list_entry.watched_episodes + 1;

            self.play_episode(next_ep)?;
            self.next_episode_options()?;
        }
    }

    fn episode_completed(&mut self) -> Result<(), SeriesError> {
        let entry = &mut self.list_entry;

        println!(
            "[{}] episode {}/{} completed",
            entry.info.title,
            entry.watched_episodes,
            entry
                .info
                .episodes
                .map(|e| e.to_string())
                .unwrap_or_else(|| "?".to_string())
        );

        if entry.status != Status::Rewatching {
            entry.status = Status::Watching;

            if entry.watched_episodes <= 1 {
                entry.start_date = Some(Local::today());
            }
        }

        self.sync_backend.update_list_entry(entry)?;
        Ok(())
    }

    fn series_completed(&mut self) -> Result<(), SeriesError> {
        println!(
            "[{}] completed!\ndo you want to rate it? (Y/n)",
            self.list_entry.info.title
        );

        if input::read_yn(Answer::Yes)? {
            self.prompt_to_update_score();
        }

        self.list_entry.status = Status::Completed;
        self.add_series_finish_date(Local::today())?;

        self.sync_backend.update_list_entry(&self.list_entry)?;

        // Nothing to do now
        std::process::exit(0);
    }

    fn next_episode_options(&mut self) -> Result<(), SeriesError> {
        println!("options:");
        println!("\t[d] drop series\n\t[h] put series on hold\n\t[r] rate series\n\t[x] exit\n\t[n] watch next episode (default)");

        let input = input::read_line()?.to_lowercase();

        match input.as_str() {
            "d" => {
                self.list_entry.status = Status::Dropped;
                self.add_series_finish_date(Local::today())?;
                self.sync_backend.update_list_entry(&self.list_entry)?;

                std::process::exit(0);
            }
            "h" => {
                self.list_entry.status = Status::OnHold;
                self.sync_backend.update_list_entry(&self.list_entry)?;

                std::process::exit(0);
            }
            "r" => {
                self.prompt_to_update_score();
                self.sync_backend.update_list_entry(&self.list_entry)?;

                self.next_episode_options()?;
            }
            "x" => std::process::exit(0),
            _ => (),
        }

        Ok(())
    }

    fn prompt_to_update_score(&mut self) {
        let max_score = self.sync_backend.max_score();
        println!("enter your score between 1-{}", max_score);

        match input::read_range(1.0, f32::from(max_score)) {
            Ok(score) => self.list_entry.score = score,
            Err(err) => eprintln!("failed to get score: {}", err),
        }
    }

    fn add_series_finish_date(&mut self, date: Date<Local>) -> Result<(), SeriesError> {
        let entry = &mut self.list_entry;

        // Someone may want to keep the original start / finish date for an
        // anime they're rewatching
        if entry.status == Status::Rewatching && entry.finish_date.is_some() {
            println!("do you want to override the finish date? (Y/n)");

            if input::read_yn(Answer::Yes)? {
                entry.finish_date = Some(date);
            }
        } else {
            entry.finish_date = Some(date);
        }

        Ok(())
    }
}

type SeriesName = String;
type EpisodeNum = u32;

#[derive(Debug)]
pub struct EpisodeData {
    pub series_name: String,
    pub episodes: HashMap<u32, PathBuf>,
    pub path: PathBuf,
}

impl EpisodeData {
    pub const EP_FORMAT_REGEX: &'static str =
        r"(?:\[.+?\]\s*)?(?P<series>.+?)\s*-\s*(?P<episode>\d+).*?\..+?";

    pub fn parse_dir(dir: &Path) -> Result<EpisodeData, SeriesError> {
        if !dir.is_dir() {
            return Err(SeriesError::NotADirectory(
                dir.file_name()
                    .map(|n| n.to_string_lossy().into_owned())
                    .unwrap_or_else(|| "err".into()),
            ));
        }

        let mut series_name = None;
        let mut episodes = HashMap::new();

        for entry in std::fs::read_dir(dir).map_err(SeriesError::Io)? {
            let path = entry.map_err(SeriesError::Io)?.path();

            if !path.is_file() {
                continue;
            }

            match EpisodeData::parse_filename(&path) {
                Ok((ep_name, ep_num)) => {
                    match series_name {
                        Some(ref series_name) if &ep_name != series_name => {
                            return Err(SeriesError::MultipleSeriesFound);
                        }
                        Some(_) => (),
                        None => series_name = Some(ep_name),
                    }

                    episodes.insert(ep_num, path);
                }
                Err(SeriesError::EpisodeRegexCaptureFailed) => continue,
                Err(e) => return Err(e),
            }
        }

        let name = series_name.ok_or(SeriesError::NoEpisodesFound)?;

        Ok(EpisodeData {
            series_name: name,
            episodes,
            path: dir.into(),
        })
    }

    fn parse_filename(path: &Path) -> Result<(SeriesName, EpisodeNum), SeriesError> {
        lazy_static! {
            static ref EP_FORMAT: Regex = Regex::new(EpisodeData::EP_FORMAT_REGEX).unwrap();
        }

        // Replace certain special characters with spaces since they can either
        // affect parsing or prevent finding results on MAL
        let filename = path
            .file_name()
            .and_then(|path| path.to_str())
            .ok_or(SeriesError::UnableToGetFilename)?
            .replace('_', " ");

        let caps = EP_FORMAT
            .captures(&filename)
            .ok_or(SeriesError::EpisodeRegexCaptureFailed)?;

        let series_name = {
            let raw_name = &caps["series"];

            raw_name.replace('.', " ")
            .replace(" -", ":") // Dashes typically represent a colon in file names
            .trim()
            .to_string()
        };

        let episode = caps["episode"]
            .parse()
            .map_err(SeriesError::EpisodeNumParseFailed)?;

        Ok((series_name, episode))
    }
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct SaveData {
    pub seasons: Vec<SeasonInfo>,
}

impl SaveData {
    fn from_path(path: &Path) -> Result<SaveData, SeriesError> {
        let file_contents = fs::read_to_string(path)?;
        let data = toml::from_str(&file_contents)?;

        Ok(data)
    }

    fn from_path_or_default(path: &Path) -> Result<SaveData, SeriesError> {
        if path.exists() {
            SaveData::from_path(path)
        } else {
            Ok(SaveData::default())
        }
    }

    fn write_to(&self, path: &Path) -> Result<(), SeriesError> {
        let toml = toml::to_string_pretty(self)?;
        fs::write(path, toml)?;

        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SeasonInfo {
    pub series_id: u32,
    pub episodes: Option<u32>,
}

impl From<AnimeInfo> for SeasonInfo {
    fn from(info: AnimeInfo) -> SeasonInfo {
        SeasonInfo {
            series_id: info.id,
            episodes: info.episodes,
        }
    }
}
<commit_msg>Update comment<commit_after>use backend::{AnimeEntry, AnimeInfo, Status, SyncBackend};
use chrono::{Date, Local};
use error::SeriesError;
use input::{self, Answer};
use process;
use regex::Regex;
use std;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use toml;

#[derive(Debug)]
pub struct Series<B>
where
    B: SyncBackend,
{
    sync_backend: B,
    pub episode_data: EpisodeData,
    pub save_data: SaveData,
    pub save_path: PathBuf,
}

impl<B> Series<B>
where
    B: SyncBackend,
{
    pub const DATA_FILE_NAME: &'static str = ".anup";

    pub fn from_data(episode_data: EpisodeData, sync_backend: B) -> Result<Series<B>, SeriesError> {
        let save_path = PathBuf::from(&episode_data.path).join(Series::<B>::DATA_FILE_NAME);
        let save_data = SaveData::from_path_or_default(&save_path)?;

        let series = Series {
            sync_backend,
            episode_data,
            save_data,
            save_path,
        };

        Ok(series)
    }

    pub fn load_season(&mut self, season: u32) -> Result<Season<B>, SeriesError> {
        let season_info = self.get_season_info(season)?;
        let season_ep_offset = self.calculate_season_offset(season);

        let list_entry = self.get_list_entry(season_info.clone())?;

        let season = Season {
            sync_backend: &self.sync_backend,
            list_entry,
            ep_offset: season_ep_offset,
            local_episodes: &self.episode_data.episodes,
        };

        Ok(season)
    }

    pub fn save_data(&self) -> Result<(), SeriesError> {
        self.save_data.write_to(&self.save_path)
    }

    fn get_season_info(&mut self, season: u32) -> Result<AnimeInfo, SeriesError> {
        let num_seasons = self.save_data.seasons.len() as u32;

        if season >= num_seasons {
            let mut series = None;

            for cur_season in num_seasons..=season {
                println!(
                    "select the correct series for season {} of [{}]:",
                    1 + cur_season,
                    self.episode_data.series_name
                );

                let series_info = self.search_and_select_series(&self.episode_data.series_name)?;
                self.save_data.seasons.push(series_info.clone().into());

                series = Some(series_info);
            }

            self.save_data()?;

            // This unwrap should never fail, as the enclosing if statement ensures the for loop will set the
            // series variable at least once
            Ok(series.unwrap())
        } else {
            let season_info = &self.save_data.seasons[season as usize];

            let series = self
                .sync_backend
                .get_series_info_by_id(season_info.series_id)?;

            Ok(series)
        }
    }

    fn calculate_season_offset(&self, season: u32) -> u32 {
        let mut offset = 0;

        for cur_season in 0..(season as usize) {
            if let Some(season_eps) = self.save_data.seasons[cur_season].episodes {
                offset += season_eps;
            }
        }

        offset
    }

    fn search_and_select_series(&self, name: &str) -> Result<AnimeInfo, SeriesError> {
        let mut found = self.sync_backend.search_by_name(name)?;

        println!("{} results for [{}]:", B::name(), name);
        println!("enter the number next to the desired series:\n");

        println!("0 [custom search]");

        for (i, series) in found.iter().enumerate() {
            println!("{} [{}]", 1 + i, series.title);
        }

        let index = input::read_range(0, found.len())?;

        if index == 0 {
            println!("enter the name you want to search for:");

            let name = input::read_line()?;
            self.search_and_select_series(&name)
        } else {
            let info = found.swap_remove(index - 1);
            Ok(info)
        }
    }

    fn get_list_entry(&self, info: AnimeInfo) -> Result<AnimeEntry, SeriesError> {
        let found = self.sync_backend.get_list_entry(info.clone())?;

        match found {
            Some(mut entry) => {
                if entry.status == Status::Completed {
                    self.prompt_to_rewatch(&mut entry)?;
                }

                Ok(entry)
            }
            None => {
                let mut entry = AnimeEntry::new(info);
                entry.status = Status::Watching;
                entry.start_date = Some(Local::today());

                self.sync_backend.update_list_entry(&entry)?;
                Ok(entry)
            }
        }
    }

    fn prompt_to_rewatch(&self, entry: &mut AnimeEntry) -> Result<(), SeriesError> {
        println!("[{}] already completed", entry.info.title);
        println!("do you want to rewatch it? (Y/n)");

        if input::read_yn(Answer::Yes)? {
            entry.status = Status::Rewatching;
            entry.watched_episodes = 0;

            println!("do you want to reset the start and end date? (Y/n)");

            if input::read_yn(Answer::Yes)? {
                entry.start_date = Some(Local::today());
                entry.finish_date = None;
            }

            self.sync_backend.update_list_entry(entry)?;
        } else {
            // No point in continuing in this case
            std::process::exit(0);
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct Season<'a, B>
where
    B: 'a + SyncBackend,
{
    sync_backend: &'a B,
    pub list_entry: AnimeEntry,
    pub local_episodes: &'a HashMap<u32, PathBuf>,
    pub ep_offset: u32,
}

impl<'a, B> Season<'a, B>
where
    B: 'a + SyncBackend,
{
    pub fn play_episode(&mut self, relative_ep: u32) -> Result<(), SeriesError> {
        let ep_num = self.ep_offset + relative_ep;

        let path = self
            .local_episodes
            .get(&ep_num)
            .ok_or_else(|| SeriesError::EpisodeNotFound(ep_num))?;

        let status = process::open_with_default(path).map_err(SeriesError::FailedToOpenPlayer)?;
        self.list_entry.watched_episodes = relative_ep;

        if !status.success() {
            println!("video player not exited normally");
            println!("do you still want to count the episode as watched? (y/N)");

            if !input::read_yn(Answer::No)? {
                return Ok(());
            }
        }

        match self.list_entry.info.episodes {
            Some(total_eps) if relative_ep >= total_eps => self.series_completed()?,
            _ => self.episode_completed()?,
        }

        Ok(())
    }

    pub fn play_all_episodes(&mut self) -> Result<(), SeriesError> {
        loop {
            let next_ep = self.list_entry.watched_episodes + 1;

            self.play_episode(next_ep)?;
            self.next_episode_options()?;
        }
    }

    fn episode_completed(&mut self) -> Result<(), SeriesError> {
        let entry = &mut self.list_entry;

        println!(
            "[{}] episode {}/{} completed",
            entry.info.title,
            entry.watched_episodes,
            entry
                .info
                .episodes
                .map(|e| e.to_string())
                .unwrap_or_else(|| "?".to_string())
        );

        if entry.status != Status::Rewatching {
            entry.status = Status::Watching;

            if entry.watched_episodes <= 1 {
                entry.start_date = Some(Local::today());
            }
        }

        self.sync_backend.update_list_entry(entry)?;
        Ok(())
    }

    fn series_completed(&mut self) -> Result<(), SeriesError> {
        println!(
            "[{}] completed!\ndo you want to rate it? (Y/n)",
            self.list_entry.info.title
        );

        if input::read_yn(Answer::Yes)? {
            self.prompt_to_update_score();
        }

        self.list_entry.status = Status::Completed;
        self.add_series_finish_date(Local::today())?;

        self.sync_backend.update_list_entry(&self.list_entry)?;

        // Nothing to do now
        std::process::exit(0);
    }

    fn next_episode_options(&mut self) -> Result<(), SeriesError> {
        println!("options:");
        println!("\t[d] drop series\n\t[h] put series on hold\n\t[r] rate series\n\t[x] exit\n\t[n] watch next episode (default)");

        let input = input::read_line()?.to_lowercase();

        match input.as_str() {
            "d" => {
                self.list_entry.status = Status::Dropped;
                self.add_series_finish_date(Local::today())?;
                self.sync_backend.update_list_entry(&self.list_entry)?;

                std::process::exit(0);
            }
            "h" => {
                self.list_entry.status = Status::OnHold;
                self.sync_backend.update_list_entry(&self.list_entry)?;

                std::process::exit(0);
            }
            "r" => {
                self.prompt_to_update_score();
                self.sync_backend.update_list_entry(&self.list_entry)?;

                self.next_episode_options()?;
            }
            "x" => std::process::exit(0),
            _ => (),
        }

        Ok(())
    }

    fn prompt_to_update_score(&mut self) {
        let max_score = self.sync_backend.max_score();
        println!("enter your score between 1-{}", max_score);

        match input::read_range(1.0, f32::from(max_score)) {
            Ok(score) => self.list_entry.score = score,
            Err(err) => eprintln!("failed to get score: {}", err),
        }
    }

    fn add_series_finish_date(&mut self, date: Date<Local>) -> Result<(), SeriesError> {
        let entry = &mut self.list_entry;

        // Someone may want to keep the original start / finish date for an
        // anime they're rewatching
        if entry.status == Status::Rewatching && entry.finish_date.is_some() {
            println!("do you want to override the finish date? (Y/n)");

            if input::read_yn(Answer::Yes)? {
                entry.finish_date = Some(date);
            }
        } else {
            entry.finish_date = Some(date);
        }

        Ok(())
    }
}

type SeriesName = String;
type EpisodeNum = u32;

#[derive(Debug)]
pub struct EpisodeData {
    pub series_name: String,
    pub episodes: HashMap<u32, PathBuf>,
    pub path: PathBuf,
}

impl EpisodeData {
    pub const EP_FORMAT_REGEX: &'static str =
        r"(?:\[.+?\]\s*)?(?P<series>.+?)\s*-\s*(?P<episode>\d+).*?\..+?";

    pub fn parse_dir(dir: &Path) -> Result<EpisodeData, SeriesError> {
        if !dir.is_dir() {
            return Err(SeriesError::NotADirectory(
                dir.file_name()
                    .map(|n| n.to_string_lossy().into_owned())
                    .unwrap_or_else(|| "err".into()),
            ));
        }

        let mut series_name = None;
        let mut episodes = HashMap::new();

        for entry in std::fs::read_dir(dir).map_err(SeriesError::Io)? {
            let path = entry.map_err(SeriesError::Io)?.path();

            if !path.is_file() {
                continue;
            }

            match EpisodeData::parse_filename(&path) {
                Ok((ep_name, ep_num)) => {
                    match series_name {
                        Some(ref series_name) if &ep_name != series_name => {
                            return Err(SeriesError::MultipleSeriesFound);
                        }
                        Some(_) => (),
                        None => series_name = Some(ep_name),
                    }

                    episodes.insert(ep_num, path);
                }
                Err(SeriesError::EpisodeRegexCaptureFailed) => continue,
                Err(e) => return Err(e),
            }
        }

        let name = series_name.ok_or(SeriesError::NoEpisodesFound)?;

        Ok(EpisodeData {
            series_name: name,
            episodes,
            path: dir.into(),
        })
    }

    fn parse_filename(path: &Path) -> Result<(SeriesName, EpisodeNum), SeriesError> {
        lazy_static! {
            static ref EP_FORMAT: Regex = Regex::new(EpisodeData::EP_FORMAT_REGEX).unwrap();
        }

        // Replace certain characters with spaces since they can prevent proper series
        // identification or prevent it from being found on a sync backend
        let filename = path
            .file_name()
            .and_then(|path| path.to_str())
            .ok_or(SeriesError::UnableToGetFilename)?
            .replace('_', " ");

        let caps = EP_FORMAT
            .captures(&filename)
            .ok_or(SeriesError::EpisodeRegexCaptureFailed)?;

        let series_name = {
            let raw_name = &caps["series"];

            raw_name.replace('.', " ")
            .replace(" -", ":") // Dashes typically represent a colon in file names
            .trim()
            .to_string()
        };

        let episode = caps["episode"]
            .parse()
            .map_err(SeriesError::EpisodeNumParseFailed)?;

        Ok((series_name, episode))
    }
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct SaveData {
    pub seasons: Vec<SeasonInfo>,
}

impl SaveData {
    fn from_path(path: &Path) -> Result<SaveData, SeriesError> {
        let file_contents = fs::read_to_string(path)?;
        let data = toml::from_str(&file_contents)?;

        Ok(data)
    }

    fn from_path_or_default(path: &Path) -> Result<SaveData, SeriesError> {
        if path.exists() {
            SaveData::from_path(path)
        } else {
            Ok(SaveData::default())
        }
    }

    fn write_to(&self, path: &Path) -> Result<(), SeriesError> {
        let toml = toml::to_string_pretty(self)?;
        fs::write(path, toml)?;

        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SeasonInfo {
    pub series_id: u32,
    pub episodes: Option<u32>,
}

impl From<AnimeInfo> for SeasonInfo {
    fn from(info: AnimeInfo) -> SeasonInfo {
        SeasonInfo {
            series_id: info.id,
            episodes: info.episodes,
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::convert::From;

use std::io::Error as IOError;

#[derive(Clone)]
pub enum StoreErrorType {
    Unknown,
    IdNotFound,
    OutOfMemory,
    // maybe more
}

impl From<StoreErrorType> for String {

    fn from(e: StoreErrorType) -> String {
        String::from(&e)
    }

}

impl<'a> From<&'a StoreErrorType> for String {

    fn from(e: &'a StoreErrorType) -> String {
        match e {
            &StoreErrorType::Unknown     => String::from("<Unknown>"),
            &StoreErrorType::IdNotFound  => String::from("ID not found"),
            &StoreErrorType::OutOfMemory => String::from("Out of Memory"),
        }
    }

}

impl Debug for StoreErrorType {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        let s : String = self.into();
        try!(write!(fmt, "{:?}", s));
        Ok(())
    }

}

impl Display for StoreErrorType {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        let s : String = self.into();
        try!(write!(fmt, "{}", s));
        Ok(())
    }

}

pub struct StoreError {
    err_type: StoreErrorType,
    expl: &'static str,
    cause: Option<Box<Error>>,
}

impl StoreError {

    pub fn new(errtype: StoreErrorType, expl: &'static str, cause: Option<Box<Error>>)
        -> StoreError
    {
        StoreError {
            err_type: errtype,
            expl:  expl,
            cause: cause,
        }
    }

    pub fn err_type(&self) -> StoreErrorType {
        self.err_type.clone()
    }

}

impl Debug for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{:?}]: {:?}, caused: {:?}",
                    self.err_type, self.expl, self.cause));
        Ok(())
    }

}

impl Display for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        let e : String = self.err_type.clone().into();
        try!(write!(fmt, "[{}]: {}", e, self.expl));
        Ok(())
    }

}

impl Error for StoreError {

    fn description(&self) -> &str {
        self.expl
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<commit_msg>Remove "Unknown" error type<commit_after>use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::convert::From;

use std::io::Error as IOError;

#[derive(Clone)]
pub enum StoreErrorType {
    IdNotFound,
    OutOfMemory,
    // maybe more
}

impl From<StoreErrorType> for String {

    fn from(e: StoreErrorType) -> String {
        String::from(&e)
    }

}

impl<'a> From<&'a StoreErrorType> for String {

    fn from(e: &'a StoreErrorType) -> String {
        match e {
            &StoreErrorType::IdNotFound  => String::from("ID not found"),
            &StoreErrorType::OutOfMemory => String::from("Out of Memory"),
        }
    }

}

impl Debug for StoreErrorType {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        let s : String = self.into();
        try!(write!(fmt, "{:?}", s));
        Ok(())
    }

}

impl Display for StoreErrorType {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        let s : String = self.into();
        try!(write!(fmt, "{}", s));
        Ok(())
    }

}

pub struct StoreError {
    err_type: StoreErrorType,
    expl: &'static str,
    cause: Option<Box<Error>>,
}

impl StoreError {

    pub fn new(errtype: StoreErrorType, expl: &'static str, cause: Option<Box<Error>>)
        -> StoreError
    {
        StoreError {
            err_type: errtype,
            expl:  expl,
            cause: cause,
        }
    }

    pub fn err_type(&self) -> StoreErrorType {
        self.err_type.clone()
    }

}

impl Debug for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{:?}]: {:?}, caused: {:?}",
                    self.err_type, self.expl, self.cause));
        Ok(())
    }

}

impl Display for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        let e : String = self.err_type.clone().into();
        try!(write!(fmt, "[{}]: {}", e, self.expl));
        Ok(())
    }

}

impl Error for StoreError {

    fn description(&self) -> &str {
        self.expl
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<|endoftext|>


<commit_before>use std::comm::{Receiver, Sender};
use uuid::Uuid;
use std::io::timer::Timer;
use std::time::duration::Duration;

use addr::Addr;
use broadcast::Broadcast;
use result::{GossipResult, GossipError};

use node::Node;
use health::{Health};
use state::State;

/// Each shutdown command needs to have a reason. Sometimes, we may not know the reason
/// of a particular shutdown (the network may fail, but we don't know if it's them or us, etc...).
/// This also improves error handling and error reporting to where it allows one to report the type
/// of shutdown and when.
#[deriving(Show, PartialEq)]
pub enum ShutdownReason {
    UserInitiatedShutdown,
    NetworkFailure,
    Failure
}

/// Current status of a particular server.
#[deriving(Show, PartialEq, Clone)]
pub enum Status {
    Initializing,
    Running,
    ShuttingDown,
    Failing
}

/// All the possible types of messages we can send to most of the channels that communicate with
/// the server. The most common one is the `Message` variant, which initiates/receives a new
/// broadcast/gossip to the appropriate nodes.
#[deriving(Show, PartialEq)]
pub enum ServerMessage {
    /// A broadcast/gossip that can be sent and/or received!
    Message(Broadcast),
    /// A shutdown command to the local node. This is an internal variant and thus isn't used
    /// to kill another member within the cluster. If we have received one of those commands, then
    /// this is emitted internally.
    Shutdown(ShutdownReason),
}

/// Handle the communication and setup of the server. Each server is spawned on
/// a separate task for isolation and independence. Thus, the only communication mechanism
/// is through the use of channels. Instead of requiring the user of the crate to initialize
/// all the local channels and such, this handles it automatically resulting in a super
/// clean API.
pub struct Server {
    /// Part of a channel that the server sends messages to.
    receiver: Receiver<ServerMessage>,
    /// Part of a channel that communicates with the server.
    sender: Sender<ServerMessage>
}

impl Server {
    /// Create a new `Server` that will handle the initialization of
    /// a server in a separate task. This will also handle creating all the required
    /// channels and such.
    ///
    /// ```rust
    /// use gossip::{Server};
    ///
    /// let mut server = Server::create("127.0.0.1", 4555);
    ///
    /// // We need to shutdown the system so that we don't hang in the
    /// // tests.
    /// server.shutdown();
    /// ```
    pub fn create(ip: &str, port: u16) -> Server {
        // Create an intermediate channel to send and receive another Sender
        // that will be used in the `Server`. This channel is only used
        // once and then thrown away.
        let (tx, rx) = channel();

        // Create another channel that will act as the local receiver. The sender
        // will be sent to the server.
        let (sender, receiver) = channel();

        // A slice does not implement `Send` so we have to allocate it first.
        let addr = ip.to_string();

        spawn(proc() {
            // Create a new server sending our `Sender`. This allows the server to send the user
            // messages over the channel.
            let mut server = InternalServer::new(sender.clone());

            // Send back the server's sender portion of the channel. This is how
            // we can further communicate with the server.
            tx.send(server.sender.clone());

            // Start the server. This will run forever until it's killed.
            server.listen(addr.as_slice(), port).unwrap();
        });

        Server {
            receiver: receiver,
            sender: rx.recv()
        }
    }

    /// Call the shutdown method after a set duration. This uses a
    /// synchronous timer.
    pub fn shutdown_in(&mut self, time: Duration) {
        let mut timer = Timer::new().unwrap();
        timer.sleep(time);
        self.shutdown();
    }

    /// Shutdown the current server now. This may not happen right away,
    /// but as soon as the proper protocol has been followed.
    pub fn shutdown(&mut self) {
        self.sender.send(Shutdown(UserInitiatedShutdown));
    }

    /// A slightly nicer interface for sending messages to the Server. This
    /// allows us to keep the `receiver` and `sender` private.
    pub fn recv(&mut self) -> ServerMessage {
        self.receiver.recv()
    }
}

/// A server/node/peer is the most atomic unit within a cluster. Each node is equal with it's peers,
/// thus we don't have any leader or election processes. Each server is identified with a unique ID
/// that is randomly generated, along with the appropriate state.
///
/// A server requires a bit of metadata about the cluster, the cluster's state and things like
/// channels. Each server has it's own Receiver to handle incoming messages. A separate Receiver
/// is used for users of this library. We then have a Sender that sends to the server's receiver.
/// This is meant to be copied to the appropriate task.
///
/// Usage:
///
/// ```rust
/// use gossip::{InternalServer, Shutdown};
/// use std::time::duration::Duration;
///
/// let mut server = InternalServer::create("127.0.0.1", 5666);
///
/// // Shutdown in the specified time in seconds.
/// server.shutdown_in(Duration::seconds(1));
///
/// // Wait for new messages. This will block the main task until the
/// // server has been shutdown.
/// loop {
///     match server.recv() {
///         Shutdown(reason) => break,
///         _ => {}
///     }
/// }
/// ```
pub struct InternalServer {
    /// A unique id for the server. This allows servers to talk about each other in
    /// a consistent manner.
    id: Uuid,
    /// The server may have an address to bind to. We make it optional to have a cleaner API
    /// to initially create the server, as the address is only needed at the .listen method.
    addr: Option<Addr>,
    /// Keep track of the server's status so that operations can be applied or rejected depending
    /// on which status it's current set on. This allows us to track whether the server
    /// has already initiated a shutdown or whether it's still running.
    status: Status,
    /// The state handles the core Gossip protocol. It's basically a giant state machine
    /// that keeps track of which nodes to communicate with, which nodes are alive/dead/failing,
    /// etc...
    state: State,
    /// A collection of servers within the cluster. Note that these aren't allocated/running
    /// servers, so we use another record called `Node` to handle that understanding.
    servers: Vec<Node>,
    /// The internal receiver to handle incoming messages. These can be messages coming from a
    /// transport, or from a user.
    receiver: Receiver<ServerMessage>,
    /// The sender-half of the previous channel. This is copied to the user and transports to send
    /// incoming messages. These aren't always broadcasts! Broadcasts are simply one kind of server
    /// message.
    sender: Sender<ServerMessage>,
    /// This is the user sender so that we can communicate with the end user of this crate. Any
    /// broadcasts that we don't handle will be relayed to the user's sender and they can take
    /// care of it.
    tx: Sender<ServerMessage>
}

impl InternalServer {

    /// Create a standard, default server. This only initializes the server
    /// but does **not** start it! So it doesn't spawn a new thread.
    ///
    /// This function requires a Sender so that the server can relay messages
    /// externally (such as the user of the crate).
    pub fn new(sender: Sender<ServerMessage>) -> InternalServer {
        // Create an internal channel for the server. The sender is often
        // copied around to various components.
        let (tx, rx) = channel();

        InternalServer {
            id: Uuid::new_v4(),
            addr: None,
            status: Initializing,
            state: State::new(),
            servers: Vec::new(),
            receiver: rx,
            sender: tx,
            tx: sender
        }
    }

    /// Create a new `Server` that is responsible for fully initializing and starting
    /// the server component. A `Server` is what the user will interact with as the server
    /// is running within another task, so the communication protocol is through channels
    /// exclusively.
    pub fn create(ip: &str, port: u16) -> Server {
        Server::create(ip, port)
    }

    /// Bind the server to the specified address. If there's a transport,
    /// it has the possibility of failing.
    pub fn listen(&mut self, ip: &str, port: u16) -> GossipResult<()> {
        self.addr = Some(Addr::new(ip, port));
        self.status = Running;

        // FIXME: We'll probably need a select! macro invocation to allow the ability
        // to read from multiple sources.
        loop {
            // Receive the next message from the channel. This can be from any component.
            match self.receiver.recv() {
                // Ok, so we are tasked with shutting down. We'll relay the shutdown
                // message back to the user so they can do some cleanup or other operations.
                //
                // FIXME: We'll need to broadcast to the cluster that this server is shutting down.
                Shutdown(reason) => {
                    self.tx.send(Shutdown(reason));
                    break;
                },
                _ => {}
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{Arc, Mutex};

    #[test]
    fn default_server() {
        let (tx, rx) = channel();
        let s = InternalServer::new(tx);
        assert!(s.addr.is_none())
        assert_eq!(s.status, Initializing);
    }

    #[test]
    fn status_running() {
        let (tx, rx) = channel();

        // Create the task local mutex.
        let mutex = Arc::new(Mutex::new(InternalServer::new(tx)));

        // Copy the mutex (through the Arc) for use in another task.
        let mutex2 = mutex.clone();

        // We need to get the sender from the server.
        let mut val = mutex.lock();
        let sender = (*val).sender.clone();

        // Release the mutex.
        drop(val);

        spawn(proc() {
            let mut val = mutex2.lock();
            val.listen("127.0.0.1", 8777);
        });

        sender.send(Shutdown(UserInitiatedShutdown));

        match rx.recv() {
            Shutdown(reason) if reason == UserInitiatedShutdown => {
                assert!(true);
            },
            _ => fail!("Unexpected output")
        }
    }

    #[test]
    fn shutdown_server() {
        let (tx, rx) = channel();
        let mut s = InternalServer::new(tx);

        s.sender.send(Shutdown(UserInitiatedShutdown));
    }
}
<commit_msg>Renamed test<commit_after>use std::comm::{Receiver, Sender};
use uuid::Uuid;
use std::io::timer::Timer;
use std::time::duration::Duration;

use addr::Addr;
use broadcast::Broadcast;
use result::{GossipResult, GossipError};

use node::Node;
use health::{Health};
use state::State;

/// Each shutdown command needs to have a reason. Sometimes, we may not know the reason
/// of a particular shutdown (the network may fail, but we don't know if it's them or us, etc...).
/// This also improves error handling and error reporting to where it allows one to report the type
/// of shutdown and when.
#[deriving(Show, PartialEq)]
pub enum ShutdownReason {
    UserInitiatedShutdown,
    NetworkFailure,
    Failure
}

/// Current status of a particular server.
#[deriving(Show, PartialEq, Clone)]
pub enum Status {
    Initializing,
    Running,
    ShuttingDown,
    Failing
}

/// All the possible types of messages we can send to most of the channels that communicate with
/// the server. The most common one is the `Message` variant, which initiates/receives a new
/// broadcast/gossip to the appropriate nodes.
#[deriving(Show, PartialEq)]
pub enum ServerMessage {
    /// A broadcast/gossip that can be sent and/or received!
    Message(Broadcast),
    /// A shutdown command to the local node. This is an internal variant and thus isn't used
    /// to kill another member within the cluster. If we have received one of those commands, then
    /// this is emitted internally.
    Shutdown(ShutdownReason),
}

/// Handle the communication and setup of the server. Each server is spawned on
/// a separate task for isolation and independence. Thus, the only communication mechanism
/// is through the use of channels. Instead of requiring the user of the crate to initialize
/// all the local channels and such, this handles it automatically resulting in a super
/// clean API.
pub struct Server {
    /// Part of a channel that the server sends messages to.
    receiver: Receiver<ServerMessage>,
    /// Part of a channel that communicates with the server.
    sender: Sender<ServerMessage>
}

impl Server {
    /// Create a new `Server` that will handle the initialization of
    /// a server in a separate task. This will also handle creating all the required
    /// channels and such.
    ///
    /// ```rust
    /// use gossip::{Server};
    ///
    /// let mut server = Server::create("127.0.0.1", 4555);
    ///
    /// // We need to shutdown the system so that we don't hang in the
    /// // tests.
    /// server.shutdown();
    /// ```
    pub fn create(ip: &str, port: u16) -> Server {
        // Create an intermediate channel to send and receive another Sender
        // that will be used in the `Server`. This channel is only used
        // once and then thrown away.
        let (tx, rx) = channel();

        // Create another channel that will act as the local receiver. The sender
        // will be sent to the server.
        let (sender, receiver) = channel();

        // A slice does not implement `Send` so we have to allocate it first.
        let addr = ip.to_string();

        spawn(proc() {
            // Create a new server sending our `Sender`. This allows the server to send the user
            // messages over the channel.
            let mut server = InternalServer::new(sender.clone());

            // Send back the server's sender portion of the channel. This is how
            // we can further communicate with the server.
            tx.send(server.sender.clone());

            // Start the server. This will run forever until it's killed.
            server.listen(addr.as_slice(), port).unwrap();
        });

        Server {
            receiver: receiver,
            sender: rx.recv()
        }
    }

    /// Call the shutdown method after a set duration. This uses a
    /// synchronous timer.
    pub fn shutdown_in(&mut self, time: Duration) {
        let mut timer = Timer::new().unwrap();
        timer.sleep(time);
        self.shutdown();
    }

    /// Shutdown the current server now. This may not happen right away,
    /// but as soon as the proper protocol has been followed.
    pub fn shutdown(&mut self) {
        self.sender.send(Shutdown(UserInitiatedShutdown));
    }

    /// A slightly nicer interface for sending messages to the Server. This
    /// allows us to keep the `receiver` and `sender` private.
    pub fn recv(&mut self) -> ServerMessage {
        self.receiver.recv()
    }
}

/// A server/node/peer is the most atomic unit within a cluster. Each node is equal with it's peers,
/// thus we don't have any leader or election processes. Each server is identified with a unique ID
/// that is randomly generated, along with the appropriate state.
///
/// A server requires a bit of metadata about the cluster, the cluster's state and things like
/// channels. Each server has it's own Receiver to handle incoming messages. A separate Receiver
/// is used for users of this library. We then have a Sender that sends to the server's receiver.
/// This is meant to be copied to the appropriate task.
///
/// Usage:
///
/// ```rust
/// use gossip::{InternalServer, Shutdown};
/// use std::time::duration::Duration;
///
/// let mut server = InternalServer::create("127.0.0.1", 5666);
///
/// // Shutdown in the specified time in seconds.
/// server.shutdown_in(Duration::seconds(1));
///
/// // Wait for new messages. This will block the main task until the
/// // server has been shutdown.
/// loop {
///     match server.recv() {
///         Shutdown(reason) => break,
///         _ => {}
///     }
/// }
/// ```
pub struct InternalServer {
    /// A unique id for the server. This allows servers to talk about each other in
    /// a consistent manner.
    id: Uuid,
    /// The server may have an address to bind to. We make it optional to have a cleaner API
    /// to initially create the server, as the address is only needed at the .listen method.
    addr: Option<Addr>,
    /// Keep track of the server's status so that operations can be applied or rejected depending
    /// on which status it's current set on. This allows us to track whether the server
    /// has already initiated a shutdown or whether it's still running.
    status: Status,
    /// The state handles the core Gossip protocol. It's basically a giant state machine
    /// that keeps track of which nodes to communicate with, which nodes are alive/dead/failing,
    /// etc...
    state: State,
    /// A collection of servers within the cluster. Note that these aren't allocated/running
    /// servers, so we use another record called `Node` to handle that understanding.
    servers: Vec<Node>,
    /// The internal receiver to handle incoming messages. These can be messages coming from a
    /// transport, or from a user.
    receiver: Receiver<ServerMessage>,
    /// The sender-half of the previous channel. This is copied to the user and transports to send
    /// incoming messages. These aren't always broadcasts! Broadcasts are simply one kind of server
    /// message.
    sender: Sender<ServerMessage>,
    /// This is the user sender so that we can communicate with the end user of this crate. Any
    /// broadcasts that we don't handle will be relayed to the user's sender and they can take
    /// care of it.
    tx: Sender<ServerMessage>
}

impl InternalServer {

    /// Create a standard, default server. This only initializes the server
    /// but does **not** start it! So it doesn't spawn a new thread.
    ///
    /// This function requires a Sender so that the server can relay messages
    /// externally (such as the user of the crate).
    pub fn new(sender: Sender<ServerMessage>) -> InternalServer {
        // Create an internal channel for the server. The sender is often
        // copied around to various components.
        let (tx, rx) = channel();

        InternalServer {
            id: Uuid::new_v4(),
            addr: None,
            status: Initializing,
            state: State::new(),
            servers: Vec::new(),
            receiver: rx,
            sender: tx,
            tx: sender
        }
    }

    /// Create a new `Server` that is responsible for fully initializing and starting
    /// the server component. A `Server` is what the user will interact with as the server
    /// is running within another task, so the communication protocol is through channels
    /// exclusively.
    pub fn create(ip: &str, port: u16) -> Server {
        Server::create(ip, port)
    }

    /// Bind the server to the specified address. If there's a transport,
    /// it has the possibility of failing.
    pub fn listen(&mut self, ip: &str, port: u16) -> GossipResult<()> {
        self.addr = Some(Addr::new(ip, port));
        self.status = Running;

        // FIXME: We'll probably need a select! macro invocation to allow the ability
        // to read from multiple sources.
        loop {
            // Receive the next message from the channel. This can be from any component.
            match self.receiver.recv() {
                // Ok, so we are tasked with shutting down. We'll relay the shutdown
                // message back to the user so they can do some cleanup or other operations.
                //
                // FIXME: We'll need to broadcast to the cluster that this server is shutting down.
                Shutdown(reason) => {
                    self.tx.send(Shutdown(reason));
                    break;
                },
                _ => {}
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{Arc, Mutex};

    #[test]
    fn default_server() {
        let (tx, rx) = channel();
        let s = InternalServer::new(tx);
        assert!(s.addr.is_none())
        assert_eq!(s.status, Initializing);
    }

    #[test]
    fn server_access_with_mutex() {
        let (tx, rx) = channel();

        // Create the task local mutex.
        let mutex = Arc::new(Mutex::new(InternalServer::new(tx)));

        // Copy the mutex (through the Arc) for use in another task.
        let mutex2 = mutex.clone();

        // We need to get the sender from the server.
        let mut val = mutex.lock();
        let sender = (*val).sender.clone();

        // Release the mutex.
        drop(val);

        spawn(proc() {
            let mut val = mutex2.lock();
            val.listen("127.0.0.1", 8777);
        });

        // Shutdown the server so we can finish the test.
        sender.send(Shutdown(UserInitiatedShutdown));

        match rx.recv() {
            Shutdown(reason) if reason == UserInitiatedShutdown => {
                assert!(true);
            },
            _ => fail!("Unexpected output")
        }
    }

    #[test]
    fn shutdown_server() {
        let (tx, rx) = channel();
        let mut s = InternalServer::new(tx);

        s.sender.send(Shutdown(UserInitiatedShutdown));
    }
}
<|endoftext|>


<commit_before>use internal::*;
use internal::IResult::*;

pub trait FlatMapper<O,N> for Sized? {
  fn flat_map(& self, f: |O| -> IResult<O,N>) -> IResult<O,N>;
}

impl<'a,R,S,T> FlatMapper<&'a[S], T> for IResult<R,&'a [S]> {
  fn flat_map(&self, f: |&'a[S]| -> IResult<&'a[S],T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }
}

impl<'a,R,T> FlatMapper<&'a str, T> for IResult<R,&'a str> {
  fn flat_map(&self, f: |&'a str| -> IResult<&'a str,T>) -> IResult<&'a str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }
}

impl<'a,R,T> FlatMapper<(), T> for IResult<R,()> {
  fn flat_map(&self, f: |()| -> IResult<(),T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, _) => f(())
    }
  }
}

pub trait Mapper<O,N> for Sized? {
  fn map_opt(& self, f: |O| -> Option<N>) -> IResult<O,N>;
  fn map_res<P>(& self, f: |O| -> Result<N,P>) -> IResult<O,N>;
}

impl<'a,R,S,T> Mapper<&'a[S], T> for IResult<R,&'a [S]> {
  fn map_opt(&self, f: |&'a[S]| -> Option<T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a[S]| -> Result<T,U>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Ok(output) => Done(*o, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,R,T> Mapper<&'a str, T> for IResult<R,&'a str> {
  fn map_opt(&self, f: |&'a str| -> Option<T>) -> IResult<&'a str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a str| -> Result<T,U>) -> IResult<&'a str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Ok(output) => Done(*o, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,R,T> Mapper<(), T> for IResult<R,()> {
  fn map_opt(&self, f: |()| -> Option<T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, __) => match f(()) {
        Some(output) => Done((), output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |()| -> Result<T,U>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Ok(output) => Done(*o, output),
        Err(_)     => Error(0)
      }
    }
  }
}

pub trait Mapper2<O,N,I> for Sized? {
  fn map(& self, f: |O| -> N) -> IResult<I,N>;
}

impl<'a,R,S,T> Mapper2<&'a[S], T, &'a R> for IResult<&'a R,&'a [S]> {
  fn map(&self, f: |&'a[S]| -> T) -> IResult<&'a R,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => Done(*i,f(*o))
    }
  }
}

impl<'a,R,S,T> Mapper2<&'a[S], T, &'a [R]> for IResult<&'a [R],&'a [S]> {
  fn map(&self, f: |&'a[S]| -> T) -> IResult<&'a [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => Done(*i,f(*o))
    }
  }
}

impl<'a,R,T> Mapper2<(), T, &'a R> for IResult<&'a R,()> {
  fn map(&self, f: |()| -> T) -> IResult<&'a R,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ()) => Done(*i,f(()))
    }
  }
}

impl<'a,S,T> Mapper2<&'a[S], T, ()> for IResult<(),&'a [S]> {
  fn map(&self, f: |&'a[S]| -> T) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => Done((),f(*o))
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use internal::IResult;
  use internal::IResult::*;
  use std::str;
  use std::fmt::Show;

  fn local_print<'a,T: Show>(input: T) -> IResult<T, ()> {
    println!("{}", input);
    Done(input, ())
  }

  #[test]
  fn flat_map_fn() {
    Done((),()).flat_map(local_print);
  }

  #[test]
  fn flat_map_closure() {
    Done((),()).flat_map(|data| { println!("data: {}", data); Done(data,())});
    //assert_eq!(decoded.number, 10);
  }

  #[test]
  fn map() {
    let res = Done((),"abcd".as_bytes()).map(|data| { str::from_utf8(data).unwrap() });
    assert_eq!(res, Done((), "abcd"));
  }

  #[test]
  fn map_2() {
    let res = Done("abcd".as_bytes(),"efgh".as_bytes()).map(|data| { str::from_utf8(data).unwrap() });
    assert_eq!(res, Done("abcd".as_bytes(), "efgh"));
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(local_print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }
}
<commit_msg>map should return the original input<commit_after>use internal::*;
use internal::IResult::*;

pub trait FlatMapper<O,N> for Sized? {
  fn flat_map(& self, f: |O| -> IResult<O,N>) -> IResult<O,N>;
}

impl<'a,R,S,T> FlatMapper<&'a[S], T> for IResult<R,&'a [S]> {
  fn flat_map(&self, f: |&'a[S]| -> IResult<&'a[S],T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }
}

impl<'a,R,T> FlatMapper<&'a str, T> for IResult<R,&'a str> {
  fn flat_map(&self, f: |&'a str| -> IResult<&'a str,T>) -> IResult<&'a str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }
}

impl<R,T> FlatMapper<(), T> for IResult<R,()> {
  fn flat_map(&self, f: |()| -> IResult<(),T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, _) => f(())
    }
  }
}

pub trait Mapper<I,O,N> for Sized? {
  fn map_opt(& self, f: |O| -> Option<N>) -> IResult<I,N>;
  fn map_res<P>(& self, f: |O| -> Result<N,P>) -> IResult<I,N>;
}

impl<'a,'b,R,S,T> Mapper<&'b [R],&'a[S], T> for IResult<&'b [R],&'a [S]> {
  fn map_opt(&self, f: |&'a[S]| -> Option<T>) -> IResult<&'b [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Some(output) => Done(*i, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a[S]| -> Result<T,U>) -> IResult<&'b [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Ok(output) => Done(*i, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,'b,S,T> Mapper<&'b str, &'a[S], T> for IResult<&'b str,&'a [S]> {
  fn map_opt(&self, f: |&'a[S]| -> Option<T>) -> IResult<&'b str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Some(output) => Done(*i, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a[S]| -> Result<T,U>) -> IResult<&'b str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Ok(output) => Done(*i, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,S,T> Mapper<(), &'a[S], T> for IResult<(),&'a [S]> {
  fn map_opt(&self, f: |&'a[S]| -> Option<T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => match f(*o) {
        Some(output) => Done((), output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a[S]| -> Result<T,U>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => match f(*o) {
        Ok(output) => Done((), output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,'b,R,T> Mapper<&'b [R],&'a str, T> for IResult<&'b [R],&'a str> {
  fn map_opt(&self, f: |&'a str| -> Option<T>) -> IResult<&'b [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Some(output) => Done(*i, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a str| -> Result<T,U>) -> IResult<&'b [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Ok(output) => Done(*i, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,'b,T> Mapper<&'b str, &'a str, T> for IResult<&'b str,&'a str> {
  fn map_opt(&self, f: |&'a str| -> Option<T>) -> IResult<&'b str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Some(output) => Done(*i, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a str| -> Result<T,U>) -> IResult<&'b str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Ok(output) => Done(*i, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,T> Mapper<(),&'a str, T> for IResult<(),&'a str> {
  fn map_opt(&self, f: |&'a str| -> Option<T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => match f(*o) {
        Some(output) => Done((), output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |&'a str| -> Result<T,U>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => match f(*o) {
        Ok(output) => Done((), output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,R,T> Mapper<&'a[R], (), T> for IResult<&'a[R],()> {
  fn map_opt(&self, f: |()| -> Option<T>) -> IResult<&'a[R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, __) => match f(()) {
        Some(output) => Done(*i, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |()| -> Result<T,U>) -> IResult<&'a [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Ok(output) => Done(*i, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<'a,T> Mapper<&'a str, (), T> for IResult<&'a str,()> {
  fn map_opt(&self, f: |()| -> Option<T>) -> IResult<&'a str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, __) => match f(()) {
        Some(output) => Done(*i, output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |()| -> Result<T,U>) -> IResult<&'a str,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => match f(*o) {
        Ok(output) => Done(*i, output),
        Err(_)     => Error(0)
      }
    }
  }
}

impl<T> Mapper<(),(), T> for IResult<(),()> {
  fn map_opt(&self, f: |()| -> Option<T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), __) => match f(()) {
        Some(output) => Done((), output),
        None         => Error(0)
      }
    }
  }

  fn map_res<U>(&self, f: |()| -> Result<T,U>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => match f(*o) {
        Ok(output) => Done(*o, output),
        Err(_)     => Error(0)
      }
    }
  }
}

pub trait Mapper2<O,N,I> for Sized? {
  fn map(& self, f: |O| -> N) -> IResult<I,N>;
}

impl<'a,R,S,T> Mapper2<&'a[S], T, &'a R> for IResult<&'a R,&'a [S]> {
  fn map(&self, f: |&'a[S]| -> T) -> IResult<&'a R,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => Done(*i,f(*o))
    }
  }
}

impl<'a,R,S,T> Mapper2<&'a[S], T, &'a [R]> for IResult<&'a [R],&'a [S]> {
  fn map(&self, f: |&'a[S]| -> T) -> IResult<&'a [R],T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ref o) => Done(*i,f(*o))
    }
  }
}

impl<'a,R,T> Mapper2<(), T, &'a R> for IResult<&'a R,()> {
  fn map(&self, f: |()| -> T) -> IResult<&'a R,T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(ref i, ()) => Done(*i,f(()))
    }
  }
}

impl<'a,S,T> Mapper2<&'a[S], T, ()> for IResult<(),&'a [S]> {
  fn map(&self, f: |&'a[S]| -> T) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      &Incomplete(ref i) => Incomplete(*i),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done((), ref o) => Done((),f(*o))
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use internal::IResult;
  use internal::IResult::*;
  use std::str;
  use std::fmt::Show;

  fn local_print<'a,T: Show>(input: T) -> IResult<T, ()> {
    println!("{}", input);
    Done(input, ())
  }

  #[test]
  fn flat_map_fn() {
    Done((),()).flat_map(local_print);
  }

  #[test]
  fn flat_map_closure() {
    Done((),()).flat_map(|data| { println!("data: {}", data); Done(data,())});
    //assert_eq!(decoded.number, 10);
  }

  #[test]
  fn map() {
    let res = Done((),"abcd".as_bytes()).map(|data| { str::from_utf8(data).unwrap() });
    assert_eq!(res, Done((), "abcd"));
  }

  #[test]
  fn map_2() {
    let res = Done("abcd".as_bytes(),"efgh".as_bytes()).map(|data| { str::from_utf8(data).unwrap() });
    assert_eq!(res, Done("abcd".as_bytes(), "efgh"));
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(local_print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }
}
<|endoftext|>


<commit_before>#[allow(non_camel_case_types)]
enum SubCommand {
    bind_interdomain    = 0,
    bind_virq           = 1,
    bind_pirq           = 2,
    close               = 3,
    send                = 4,
    status              = 5,
    alloc_unbound       = 6,
    bind_ipi            = 7,
    bind_vcpu           = 8,
    unmask              = 9,
    reset               = 10,
    init_control        = 11,
    expand_array        = 12,
    set_priority        = 13
}

// Port implements Drop, which is incompatible with repr(C)
// https://github.com/rust-lang/rust/issues/24585
// Use _Port when interfacing with the hypervisor
#[derive(Copy, Clone)]
struct Port(u32);
pub struct EventChannel(Port);

//pub mod bind_interdomain;
pub mod bind_virq;
//pub mod bind_pirq;
pub mod close;
//pub mod send;
//pub mod status;
//pub mod alloc_unbound;
//pub mod bind_ipi;
//pub mod bind_vcpu;
//pub mod unmask;
//pub mod reset;
//pub mod init_control;
//pub mod expand_array;
//pub mod set_priority;
<commit_msg>comments<commit_after>#[allow(non_camel_case_types)]
enum SubCommand {
    bind_interdomain    = 0,
    bind_virq           = 1,
    bind_pirq           = 2,
    close               = 3,
    send                = 4,
    status              = 5,
    alloc_unbound       = 6,
    bind_ipi            = 7,
    bind_vcpu           = 8,
    unmask              = 9,
    reset               = 10,
    init_control        = 11,
    expand_array        = 12,
    set_priority        = 13
}

#[repr(C)]
#[derive(Copy, Clone)]
struct Port(u32);
pub struct EventChannel(Port);

//pub mod bind_interdomain;
pub mod bind_virq;
//pub mod bind_pirq;
pub mod close;
//pub mod send;
//pub mod status;
//pub mod alloc_unbound;
//pub mod bind_ipi;
//pub mod bind_vcpu;
//pub mod unmask;
//pub mod reset;
//pub mod init_control;
//pub mod expand_array;
//pub mod set_priority;
<|endoftext|>


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

//!
//! test?
//!

use std::f32::consts::{PI, PI_2};
use super::{Quad, Triangle, Polygon};
use super::{PolyTri, PolyQuad};
use super::generators::{SharedVertex, IndexedPolygon};

/// Represents a sphere with radius of 1, centered at (0, 0, 0)
pub struct SphereUV {
    u: uint,
    v: uint,
    sub_u: uint,
    sub_v: uint
}

impl SphereUV {
    /// Create a new sphere.
    /// `u` is the number of points across the equator of the sphere.
    /// `v` is the number of points from pole to pole.
    pub fn new(u: uint, v: uint) -> SphereUV {
        SphereUV {
            u: 0,
            v: 0,
            sub_u: u,
            sub_v: v
        }
    }

    fn vert(&self, u: uint, v: uint) -> (f32, f32, f32) {
        let u = (u as f32 / self.sub_u as f32) * PI_2;
        let v = (v as f32 / self.sub_v as f32) * PI;

        (u.cos() * v.sin(),
         u.sin() * v.sin(),
         v.cos())
    }
}

impl Iterator<Polygon<(f32, f32, f32)>> for SphereUV {
    fn next(&mut self) -> Option<Polygon<(f32, f32, f32)>> {
        if self.u == self.sub_u {
            self.u = 0;
            self.v += 1;
            if self.v == self.sub_v {
                return None;
            }
        }

        let x = self.vert(self.u,   self.v);
        let y = self.vert(self.u,   self.v+1);
        let z = self.vert(self.u+1, self.v+1);
        let w = self.vert(self.u+1, self.v);
        let v = self.v;
        self.u += 1;

        if v == 0 {
            Some(PolyTri(Triangle::new(x, y, z)))
        } else if v == self.sub_v - 1 {
            Some(PolyTri(Triangle::new(z, w, x)))
        } else {
            Some(PolyQuad(Quad::new(x, y, z, w)))
        }
    }
}

impl SharedVertex<(f32, f32, f32)> for SphereUV {
    fn shared_vertex(&self, idx: uint) -> (f32, f32, f32) {
        if idx == 0 {
            self.vert(0, 0)
        } else if idx == self.shared_vertex_count() - 1 {
            self.vert(0, self.sub_v)
        } else {
            // since the bottom verts all map to the same
            // we jump over them in index space
            let idx = idx - 1;
            let u = idx % (self.sub_u);
            let v = idx / (self.sub_u);
            self.vert(u, v+1)
        }
    }

    fn shared_vertex_count(&self) -> uint {
        (self.sub_v - 1) * (self.sub_u) + 2
    }
}

impl IndexedPolygon<Polygon<uint>> for SphereUV {
    fn indexed_polygon(&self, idx: uint) -> Polygon<uint> {
        let u = idx % self.sub_u;
        let v = idx / self.sub_u;

        let f = |u: uint, v: uint| {
            if v == 0 {
                0
            } else if self.sub_v == v {
                (self.sub_v-1) * (self.sub_u) + 1
            } else {
                (v-1) * self.sub_u + (u % self.sub_u) + 1
            }
        };

        if v == 0 {
            PolyTri(Triangle::new(f(u,   v),
                                  f(u,   v+1),
                                  f(u+1, v+1)))
        } else if self.sub_v - 1 == v {
            PolyTri(Triangle::new(f(u+1, v+1),
                                  f(u+1, v),
                                  f(u,   v)))
        } else {
            PolyQuad(Quad::new(f(u,   v),
                               f(u,   v+1),
                               f(u+1, v+1),
                               f(u+1, v)))
        }
    }

    fn indexed_polygon_count(&self) -> uint {
        self.sub_v * self.sub_u
    }
}

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

//!
//! test?
//!

use std::f32::consts::{PI, PI_2};
use std::num::FloatMath;
use super::{Quad, Triangle, Polygon};
use super::{PolyTri, PolyQuad};
use super::generators::{SharedVertex, IndexedPolygon};

/// Represents a sphere with radius of 1, centered at (0, 0, 0)
pub struct SphereUV {
    u: uint,
    v: uint,
    sub_u: uint,
    sub_v: uint
}

impl SphereUV {
    /// Create a new sphere.
    /// `u` is the number of points across the equator of the sphere.
    /// `v` is the number of points from pole to pole.
    pub fn new(u: uint, v: uint) -> SphereUV {
        SphereUV {
            u: 0,
            v: 0,
            sub_u: u,
            sub_v: v
        }
    }

    fn vert(&self, u: uint, v: uint) -> (f32, f32, f32) {
        let u = (u as f32 / self.sub_u as f32) * PI_2;
        let v = (v as f32 / self.sub_v as f32) * PI;

        (u.cos() * v.sin(),
         u.sin() * v.sin(),
         v.cos())
    }
}

impl Iterator<Polygon<(f32, f32, f32)>> for SphereUV {
    fn next(&mut self) -> Option<Polygon<(f32, f32, f32)>> {
        if self.u == self.sub_u {
            self.u = 0;
            self.v += 1;
            if self.v == self.sub_v {
                return None;
            }
        }

        let x = self.vert(self.u,   self.v);
        let y = self.vert(self.u,   self.v+1);
        let z = self.vert(self.u+1, self.v+1);
        let w = self.vert(self.u+1, self.v);
        let v = self.v;
        self.u += 1;

        if v == 0 {
            Some(PolyTri(Triangle::new(x, y, z)))
        } else if v == self.sub_v - 1 {
            Some(PolyTri(Triangle::new(z, w, x)))
        } else {
            Some(PolyQuad(Quad::new(x, y, z, w)))
        }
    }
}

impl SharedVertex<(f32, f32, f32)> for SphereUV {
    fn shared_vertex(&self, idx: uint) -> (f32, f32, f32) {
        if idx == 0 {
            self.vert(0, 0)
        } else if idx == self.shared_vertex_count() - 1 {
            self.vert(0, self.sub_v)
        } else {
            // since the bottom verts all map to the same
            // we jump over them in index space
            let idx = idx - 1;
            let u = idx % (self.sub_u);
            let v = idx / (self.sub_u);
            self.vert(u, v+1)
        }
    }

    fn shared_vertex_count(&self) -> uint {
        (self.sub_v - 1) * (self.sub_u) + 2
    }
}

impl IndexedPolygon<Polygon<uint>> for SphereUV {
    fn indexed_polygon(&self, idx: uint) -> Polygon<uint> {
        let u = idx % self.sub_u;
        let v = idx / self.sub_u;

        let f = |u: uint, v: uint| {
            if v == 0 {
                0
            } else if self.sub_v == v {
                (self.sub_v-1) * (self.sub_u) + 1
            } else {
                (v-1) * self.sub_u + (u % self.sub_u) + 1
            }
        };

        if v == 0 {
            PolyTri(Triangle::new(f(u,   v),
                                  f(u,   v+1),
                                  f(u+1, v+1)))
        } else if self.sub_v - 1 == v {
            PolyTri(Triangle::new(f(u+1, v+1),
                                  f(u+1, v),
                                  f(u,   v)))
        } else {
            PolyQuad(Quad::new(f(u,   v),
                               f(u,   v+1),
                               f(u+1, v+1),
                               f(u+1, v)))
        }
    }

    fn indexed_polygon_count(&self) -> uint {
        self.sub_v * self.sub_u
    }
}

<|endoftext|>