<commit_before>pub mod parse;

use self::parse::{EpisodeData, SaveData, SeasonState};
use backend::{AnimeEntry, AnimeInfo, Status, SyncBackend};
use chrono::Local;
use error::SeriesError;
use input::{self, Answer};
use process;
use std::borrow::Cow;
use std::ops::Range;
use std::path::Path;

pub struct SeriesConfig<B>
where
    B: SyncBackend,
{
    pub offline_mode: bool,
    pub sync_service: B,
    pub season_num: usize,
}

pub struct FolderData {
    pub episodes: EpisodeData,
    pub savefile: SaveData,
}

impl FolderData {
    pub fn load_dir(path: &Path) -> Result<FolderData, SeriesError> {
        let mut savefile = SaveData::from_dir(path)?;
        let episodes = EpisodeData::parse_until_valid_pattern(path, &mut savefile.episode_matcher)?;

        Ok(FolderData { episodes, savefile })
    }

    pub fn save(&self) -> Result<(), SeriesError> {
        self.savefile.write_to_file()
    }

    pub fn populate_season_data<B>(
        &mut self,
        config: &SeriesConfig<B>,
        desired_season: usize,
    ) -> Result<(), SeriesError>
    where
        B: SyncBackend,
    {
        let num_seasons = self.seasons().len();

        if num_seasons > desired_season {
            return Ok(());
        }

        for cur_season in num_seasons..=desired_season {
            let info = self.fetch_series_info(config, cur_season)?;
            let entry = AnimeEntry::new(info);

            let season = SeasonState {
                state: entry,
                needs_info: config.offline_mode,
                needs_sync: config.offline_mode,
            };

            self.seasons_mut().push(season);
        }

        Ok(())
    }

    pub fn fetch_series_info<B>(
        &mut self,
        config: &SeriesConfig<B>,
        season: usize,
    ) -> Result<AnimeInfo, SeriesError>
    where
        B: SyncBackend,
    {
        if config.offline_mode {
            // Return existing data if we already have it, otherwise return barebones info
            if self.seasons().len() > season {
                let info = self.seasons()[season].state.info.clone();
                Ok(info)
            } else {
                let mut info = AnimeInfo::default();
                info.title = self.episodes.series_name.clone();

                Ok(info)
            }
        } else {
            search_for_series_info(&config.sync_service, &self.episodes.series_name, season)
        }
    }

    pub fn sync_remote_season_info<B>(
        &mut self,
        config: &SeriesConfig<B>,
        season: usize,
    ) -> Result<(), SeriesError>
    where
        B: SyncBackend,
    {
        if season >= self.seasons().len() {
            return Ok(());
        }

        let mut season_data = self.seasons_mut()[season].clone();

        if season_data.needs_info {
            season_data.state.info = self.fetch_series_info(config, season)?;

            // We want to stay in a needs-sync state in offline mode so the "real" info
            // can be inserted when the series is played in online mode
            if !config.offline_mode {
                season_data.needs_info = false;
            }
        }

        // Sync data from the backend when not offline
        if !config.offline_mode {
            let entry = config
                .sync_service
                .get_list_entry(season_data.state.info.clone())?;

            if let Some(entry) = entry {
                // If we don't have new data to report, we should sync the data from the backend to keep up with
                // any changes made outside of the program
                if !season_data.needs_sync {
                    season_data.state = entry;
                }
            }
        }

        self.seasons_mut()[season] = season_data;
        Ok(())
    }

    pub fn calculate_season_offset(&self, mut range: Range<usize>) -> u32 {
        let num_seasons = self.savefile.season_states.len();
        range.start = num_seasons.min(range.start);
        range.end = num_seasons.min(range.end);

        let mut offset = 0;

        for i in range {
            let season = &self.savefile.season_states[i];

            match season.state.info.episodes {
                Some(eps) => offset += eps,
                None => return offset,
            }
        }

        offset
    }

    pub fn seasons(&self) -> &Vec<SeasonState> {
        &self.savefile.season_states
    }

    pub fn seasons_mut(&mut self) -> &mut Vec<SeasonState> {
        &mut self.savefile.season_states
    }
}

pub struct Series<B>
where
    B: SyncBackend,
{
    config: SeriesConfig<B>,
    dir: FolderData,
    ep_offset: u32,
}

impl<B> Series<B>
where
    B: SyncBackend,
{
    pub fn new(config: SeriesConfig<B>, dir: FolderData) -> Series<B> {
        Series {
            config,
            dir,
            ep_offset: 0,
        }
    }

    pub fn prepare(&mut self) -> Result<(), SeriesError> {
        // We want to sync the remote season data before we populate missing seasons to avoid working on the same data twice
        self.dir
            .sync_remote_season_info(&self.config, self.config.season_num)?;
        self.dir
            .populate_season_data(&self.config, self.config.season_num)?;

        self.ep_offset = self.dir.calculate_season_offset(0..self.config.season_num);
        self.dir.save()?;

        self.prepare_list_entry()?;

        Ok(())
    }

    fn prepare_list_entry(&mut self) -> Result<(), SeriesError> {
        let status = self.cur_season().state.status;

        match status {
            Status::Watching | Status::Rewatching => Ok(()),
            Status::PlanToWatch => self.update_list_entry_status(Status::Watching),
            Status::Completed => self.update_list_entry_status(Status::Rewatching),
            Status::OnHold | Status::Dropped => self.prompt_to_watch_paused_series(),
        }
    }

    fn update_list_entry_status(&mut self, status: Status) -> Result<(), SeriesError> {
        match status {
            Status::Watching => {
                let entry = &mut self.cur_season_mut().state;

                // A series that was on hold probably already has a starting date, and it would make
                // more sense to use that one instead of replacing it
                if entry.status != Status::OnHold {
                    entry.start_date = Some(Local::today().naive_local());
                }

                entry.finish_date = None;
            }
            Status::Rewatching => {
                let entry = &mut self.cur_season_mut().state;

                println!("[{}] already completed", entry.info.title);
                println!("do you want to reset the start and end dates of the series? (Y/n)");

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

                entry.watched_episodes = 0;
            }
            Status::Completed => {
                let entry = &mut self.cur_season_mut().state;

                if entry.finish_date.is_none() {
                    entry.finish_date = Some(Local::today().naive_local());
                }

                println!("[{}] completed!", entry.info.title);

                self.prompt_to_update_score();
            }
            Status::Dropped => {
                let entry = &mut self.cur_season_mut().state;

                if entry.finish_date.is_none() {
                    entry.finish_date = Some(Local::today().naive_local());
                }
            }
            Status::OnHold | Status::PlanToWatch => (),
        }

        let entry = &mut self.cur_season_mut().state;
        entry.status = status;

        self.update_list_entry()?;

        Ok(())
    }

    pub fn update_list_entry(&mut self) -> Result<(), SeriesError> {
        if self.config.offline_mode {
            let season = &mut self.cur_season_mut();
            season.needs_sync = true;

            self.dir.save()?;

            return Ok(());
        }

        self.dir.save()?;

        self.config
            .sync_service
            .update_list_entry(&self.cur_season().state)?;

        Ok(())
    }

    pub fn play_episode(&mut self, episode: u32) -> Result<(), SeriesError> {
        let absolute_ep = self.ep_offset + episode;
        let path = self.dir.episodes.get_episode(absolute_ep)?.clone();

        let status = process::open_with_default(path).map_err(SeriesError::FailedToOpenPlayer)?;

        let entry = &mut self.cur_season_mut().state;
        entry.watched_episodes = episode.max(entry.watched_episodes);

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

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

        match entry.info.episodes {
            Some(total_eps) if episode >= total_eps => {
                self.update_list_entry_status(Status::Completed)?;
                return Err(SeriesError::RequestExit);
            }
            _ => self.prompt_episode_completed()?,
        }

        Ok(())
    }

    pub fn play_all_episodes(&mut self) -> Result<(), SeriesError> {
        self.prepare()?;

        loop {
            let next_episode = self.cur_season().state.watched_episodes + 1;

            self.play_episode(next_episode)?;
            self.prompt_next_episode_options()?;
        }
    }

    fn prompt_episode_completed(&mut self) -> Result<(), SeriesError> {
        let entry = &self.cur_season().state;

        let total_episodes = entry
            .info
            .episodes
            .map(|e| Cow::Owned(e.to_string()))
            .unwrap_or_else(|| Cow::Borrowed("?"));

        println!(
            "[{}] episode {}/{} completed",
            entry.info.title, entry.watched_episodes, total_episodes
        );

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

    fn prompt_next_episode_options(&mut self) -> Result<(), SeriesError> {
        let current_score_text: Cow<str> = match self.format_entry_score() {
            Some(score) => Cow::Owned(format!(" [{}]", score)),
            None => Cow::Borrowed(""),
        };

        println!("series options:");
        println!("\t[d] drop\n\t[h] put on hold\n\t[r] rate{}\n\t[x] exit\n\t[n] watch next episode (default)", current_score_text);

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

        match input.as_str() {
            "d" => {
                self.update_list_entry_status(Status::Dropped)?;
                Err(SeriesError::RequestExit)
            }
            "h" => {
                self.update_list_entry_status(Status::OnHold)?;
                Err(SeriesError::RequestExit)
            }
            "r" => {
                self.prompt_to_update_score();
                self.update_list_entry()?;

                self.prompt_next_episode_options()
            }
            "x" => Err(SeriesError::RequestExit),
            _ => Ok(()),
        }
    }

    fn prompt_to_update_score(&mut self) {
        let (min_score, max_score) = self.config.sync_service.formatted_score_range();

        println!(
            "enter your score between {} and {} (press return to skip):",
            min_score, max_score
        );

        // TODO: use read_range() with empty line bypassing
        let input = match input::read_line() {
            Ok(ref input) if input.is_empty() => return,
            Ok(input) => input,
            Err(err) => {
                eprintln!("failed to read score input: {}", err);
                return;
            }
        };

        match self.config.sync_service.parse_score(&input) {
            Ok(score) => {
                let entry = &mut self.cur_season_mut().state;
                entry.score = Some(score);
            }
            Err(err) => eprintln!("failed to parse score: {}", err),
        }
    }

    fn prompt_to_watch_paused_series(&mut self) -> Result<(), SeriesError> {
        let entry = &mut self.cur_season_mut().state;

        println!(
            "[{}] was previously put on hold or dropped",
            entry.info.title
        );

        println!("do you want to watch it from the beginning? (Y/n)");

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

        self.update_list_entry_status(Status::Watching)?;
        Ok(())
    }

    fn format_entry_score(&self) -> Option<String> {
        let entry = &self.cur_season().state;

        match entry.score {
            Some(score) => {
                let formatted_score = self.config.sync_service.format_score(score);

                match formatted_score {
                    Ok(score) => Some(score),
                    Err(err) => {
                        eprintln!("failed to read existing list entry score: {}", err);
                        None
                    }
                }
            }
            None => None,
        }
    }

    pub fn cur_season(&self) -> &SeasonState {
        &self.dir.seasons()[self.config.season_num]
    }

    pub fn cur_season_mut(&mut self) -> &mut SeasonState {
        &mut self.dir.seasons_mut()[self.config.season_num]
    }
}

pub fn search_for_series_info<B>(
    backend: &B,
    name: &str,
    season: usize,
) -> Result<AnimeInfo, SeriesError>
where
    B: SyncBackend,
{
    println!("[{}] searching on {}..", name, B::name());

    let mut found = backend.search_by_name(name)?;

    if !found.is_empty() {
        println!(
            "select season {} by entering the number next to its name:\n",
            1 + season
        );

        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()?;
            search_for_series_info(backend, &name, season)
        } else {
            let info = found.swap_remove(index - 1);
            Ok(info)
        }
    } else {
        println!("no results found\nplease enter a custom search term:");

        let name = input::read_line()?;
        search_for_series_info(backend, &name, season)
    }
}
<commit_msg>[series] Fix improper syncing behavior<commit_after>pub mod parse;

use self::parse::{EpisodeData, SaveData, SeasonState};
use backend::{AnimeEntry, AnimeInfo, Status, SyncBackend};
use chrono::Local;
use error::SeriesError;
use input::{self, Answer};
use process;
use std::borrow::Cow;
use std::ops::Range;
use std::path::Path;

pub struct SeriesConfig<B>
where
    B: SyncBackend,
{
    pub offline_mode: bool,
    pub sync_service: B,
    pub season_num: usize,
}

pub struct FolderData {
    pub episodes: EpisodeData,
    pub savefile: SaveData,
}

impl FolderData {
    pub fn load_dir(path: &Path) -> Result<FolderData, SeriesError> {
        let mut savefile = SaveData::from_dir(path)?;
        let episodes = EpisodeData::parse_until_valid_pattern(path, &mut savefile.episode_matcher)?;

        Ok(FolderData { episodes, savefile })
    }

    pub fn save(&self) -> Result<(), SeriesError> {
        self.savefile.write_to_file()
    }

    pub fn populate_season_data<B>(
        &mut self,
        config: &SeriesConfig<B>,
        desired_season: usize,
    ) -> Result<(), SeriesError>
    where
        B: SyncBackend,
    {
        let num_seasons = self.seasons().len();

        if num_seasons > desired_season {
            return Ok(());
        }

        for cur_season in num_seasons..=desired_season {
            let info = self.fetch_series_info(config, cur_season)?;
            let entry = AnimeEntry::new(info);

            let season = SeasonState {
                state: entry,
                needs_info: config.offline_mode,
                needs_sync: config.offline_mode,
            };

            self.seasons_mut().push(season);
        }

        Ok(())
    }

    pub fn fetch_series_info<B>(
        &mut self,
        config: &SeriesConfig<B>,
        season: usize,
    ) -> Result<AnimeInfo, SeriesError>
    where
        B: SyncBackend,
    {
        if config.offline_mode {
            // Return existing data if we already have it, otherwise return barebones info
            if self.seasons().len() > season {
                let info = self.seasons()[season].state.info.clone();
                Ok(info)
            } else {
                let mut info = AnimeInfo::default();
                info.title = self.episodes.series_name.clone();

                Ok(info)
            }
        } else {
            search_for_series_info(&config.sync_service, &self.episodes.series_name, season)
        }
    }

    pub fn sync_remote_season_info<B>(
        &mut self,
        config: &SeriesConfig<B>,
        season: usize,
    ) -> Result<(), SeriesError>
    where
        B: SyncBackend,
    {
        if season >= self.seasons().len() {
            return Ok(());
        }

        let mut season_data = self.seasons_mut()[season].clone();

        if season_data.needs_info {
            season_data.state.info = self.fetch_series_info(config, season)?;

            // We want to stay in a needs-sync state in offline mode so the "real" info
            // can be inserted when the series is played in online mode
            if !config.offline_mode {
                season_data.needs_info = false;
            }
        }

        // Sync data from the backend when not offline
        if !config.offline_mode {
            let entry = config
                .sync_service
                .get_list_entry(season_data.state.info.clone())?;

            if let Some(entry) = entry {
                // If we don't have new data to report, we should sync the data from the backend to keep up with
                // any changes made outside of the program
                if !season_data.needs_sync {
                    season_data.state = entry;
                }
            }
        }

        self.seasons_mut()[season] = season_data;
        Ok(())
    }

    pub fn calculate_season_offset(&self, mut range: Range<usize>) -> u32 {
        let num_seasons = self.savefile.season_states.len();
        range.start = num_seasons.min(range.start);
        range.end = num_seasons.min(range.end);

        let mut offset = 0;

        for i in range {
            let season = &self.savefile.season_states[i];

            match season.state.info.episodes {
                Some(eps) => offset += eps,
                None => return offset,
            }
        }

        offset
    }

    pub fn seasons(&self) -> &Vec<SeasonState> {
        &self.savefile.season_states
    }

    pub fn seasons_mut(&mut self) -> &mut Vec<SeasonState> {
        &mut self.savefile.season_states
    }
}

pub struct Series<B>
where
    B: SyncBackend,
{
    config: SeriesConfig<B>,
    dir: FolderData,
    ep_offset: u32,
}

impl<B> Series<B>
where
    B: SyncBackend,
{
    pub fn new(config: SeriesConfig<B>, dir: FolderData) -> Series<B> {
        Series {
            config,
            dir,
            ep_offset: 0,
        }
    }

    pub fn prepare(&mut self) -> Result<(), SeriesError> {
        self.dir
            .populate_season_data(&self.config, self.config.season_num)?;
        self.dir
            .sync_remote_season_info(&self.config, self.config.season_num)?;

        self.ep_offset = self.dir.calculate_season_offset(0..self.config.season_num);
        self.dir.save()?;

        self.prepare_list_entry()?;

        Ok(())
    }

    fn prepare_list_entry(&mut self) -> Result<(), SeriesError> {
        let status = self.cur_season().state.status;

        match status {
            Status::Watching | Status::Rewatching => Ok(()),
            Status::PlanToWatch => self.update_list_entry_status(Status::Watching),
            Status::Completed => self.update_list_entry_status(Status::Rewatching),
            Status::OnHold | Status::Dropped => self.prompt_to_watch_paused_series(),
        }
    }

    fn update_list_entry_status(&mut self, status: Status) -> Result<(), SeriesError> {
        match status {
            Status::Watching => {
                let entry = &mut self.cur_season_mut().state;

                // A series that was on hold probably already has a starting date, and it would make
                // more sense to use that one instead of replacing it
                if entry.status != Status::OnHold {
                    entry.start_date = Some(Local::today().naive_local());
                }

                entry.finish_date = None;
            }
            Status::Rewatching => {
                let entry = &mut self.cur_season_mut().state;

                println!("[{}] already completed", entry.info.title);
                println!("do you want to reset the start and end dates of the series? (Y/n)");

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

                entry.watched_episodes = 0;
            }
            Status::Completed => {
                let entry = &mut self.cur_season_mut().state;

                if entry.finish_date.is_none() {
                    entry.finish_date = Some(Local::today().naive_local());
                }

                println!("[{}] completed!", entry.info.title);

                self.prompt_to_update_score();
            }
            Status::Dropped => {
                let entry = &mut self.cur_season_mut().state;

                if entry.finish_date.is_none() {
                    entry.finish_date = Some(Local::today().naive_local());
                }
            }
            Status::OnHold | Status::PlanToWatch => (),
        }

        let entry = &mut self.cur_season_mut().state;
        entry.status = status;

        self.update_list_entry()?;

        Ok(())
    }

    pub fn update_list_entry(&mut self) -> Result<(), SeriesError> {
        self.cur_season_mut().needs_sync = self.config.offline_mode;
        self.dir.save()?;

        if self.config.offline_mode {
            return Ok(());
        }

        self.config
            .sync_service
            .update_list_entry(&self.cur_season().state)?;

        Ok(())
    }

    pub fn play_episode(&mut self, episode: u32) -> Result<(), SeriesError> {
        let absolute_ep = self.ep_offset + episode;
        let path = self.dir.episodes.get_episode(absolute_ep)?.clone();

        let status = process::open_with_default(path).map_err(SeriesError::FailedToOpenPlayer)?;

        let entry = &mut self.cur_season_mut().state;
        entry.watched_episodes = episode.max(entry.watched_episodes);

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

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

        match entry.info.episodes {
            Some(total_eps) if episode >= total_eps => {
                self.update_list_entry_status(Status::Completed)?;
                return Err(SeriesError::RequestExit);
            }
            _ => self.prompt_episode_completed()?,
        }

        Ok(())
    }

    pub fn play_all_episodes(&mut self) -> Result<(), SeriesError> {
        self.prepare()?;

        loop {
            let next_episode = self.cur_season().state.watched_episodes + 1;

            self.play_episode(next_episode)?;
            self.prompt_next_episode_options()?;
        }
    }

    fn prompt_episode_completed(&mut self) -> Result<(), SeriesError> {
        let entry = &self.cur_season().state;

        let total_episodes = entry
            .info
            .episodes
            .map(|e| Cow::Owned(e.to_string()))
            .unwrap_or_else(|| Cow::Borrowed("?"));

        println!(
            "[{}] episode {}/{} completed",
            entry.info.title, entry.watched_episodes, total_episodes
        );

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

    fn prompt_next_episode_options(&mut self) -> Result<(), SeriesError> {
        let current_score_text: Cow<str> = match self.format_entry_score() {
            Some(score) => Cow::Owned(format!(" [{}]", score)),
            None => Cow::Borrowed(""),
        };

        println!("series options:");
        println!("\t[d] drop\n\t[h] put on hold\n\t[r] rate{}\n\t[x] exit\n\t[n] watch next episode (default)", current_score_text);

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

        match input.as_str() {
            "d" => {
                self.update_list_entry_status(Status::Dropped)?;
                Err(SeriesError::RequestExit)
            }
            "h" => {
                self.update_list_entry_status(Status::OnHold)?;
                Err(SeriesError::RequestExit)
            }
            "r" => {
                self.prompt_to_update_score();
                self.update_list_entry()?;

                self.prompt_next_episode_options()
            }
            "x" => Err(SeriesError::RequestExit),
            _ => Ok(()),
        }
    }

    fn prompt_to_update_score(&mut self) {
        let (min_score, max_score) = self.config.sync_service.formatted_score_range();

        println!(
            "enter your score between {} and {} (press return to skip):",
            min_score, max_score
        );

        // TODO: use read_range() with empty line bypassing
        let input = match input::read_line() {
            Ok(ref input) if input.is_empty() => return,
            Ok(input) => input,
            Err(err) => {
                eprintln!("failed to read score input: {}", err);
                return;
            }
        };

        match self.config.sync_service.parse_score(&input) {
            Ok(score) => {
                let entry = &mut self.cur_season_mut().state;
                entry.score = Some(score);
            }
            Err(err) => eprintln!("failed to parse score: {}", err),
        }
    }

    fn prompt_to_watch_paused_series(&mut self) -> Result<(), SeriesError> {
        let entry = &mut self.cur_season_mut().state;

        println!(
            "[{}] was previously put on hold or dropped",
            entry.info.title
        );

        println!("do you want to watch it from the beginning? (Y/n)");

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

        self.update_list_entry_status(Status::Watching)?;
        Ok(())
    }

    fn format_entry_score(&self) -> Option<String> {
        let entry = &self.cur_season().state;

        match entry.score {
            Some(score) => {
                let formatted_score = self.config.sync_service.format_score(score);

                match formatted_score {
                    Ok(score) => Some(score),
                    Err(err) => {
                        eprintln!("failed to read existing list entry score: {}", err);
                        None
                    }
                }
            }
            None => None,
        }
    }

    pub fn cur_season(&self) -> &SeasonState {
        &self.dir.seasons()[self.config.season_num]
    }

    pub fn cur_season_mut(&mut self) -> &mut SeasonState {
        &mut self.dir.seasons_mut()[self.config.season_num]
    }
}

pub fn search_for_series_info<B>(
    backend: &B,
    name: &str,
    season: usize,
) -> Result<AnimeInfo, SeriesError>
where
    B: SyncBackend,
{
    println!("[{}] searching on {}..", name, B::name());

    let mut found = backend.search_by_name(name)?;

    if !found.is_empty() {
        println!(
            "select season {} by entering the number next to its name:\n",
            1 + season
        );

        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()?;
            search_for_series_info(backend, &name, season)
        } else {
            let info = found.swap_remove(index - 1);
            Ok(info)
        }
    } else {
        println!("no results found\nplease enter a custom search term:");

        let name = input::read_line()?;
        search_for_series_info(backend, &name, season)
    }
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use fibers::Spawn;
use fibers::sync::{mpsc, oneshot};
use fibers::net::{TcpListener, TcpStream};
use fibers::net::streams::Incoming;
use futures::{self, Future, Stream, Poll, Async};
use futures::future::Either;

pub use self::request::{Request, ReadRequest};
pub use self::response::{Response, ResponseBuilder};

use {Result, Error, ErrorKind, TransportStream, Version};
use status::RawStatus;
use connection;

mod request;
mod response;

pub trait Server {
    type Transport: TransportStream;
    type SocketHandler: HandleSocket<Transport = Self::Transport>;
    type ConnectionHandler: HandleConnection<Transport = Self::Transport>;

    #[allow(unused_variables)]
    fn before_listen(&mut self, listener: &mut TcpListener) -> Result<()> {
        Ok(())
    }
    fn create_handlers(&mut self) -> (Self::SocketHandler, Self::ConnectionHandler);
    fn start<S>(self, bind_addr: SocketAddr, spawner: S) -> ServerHandle
        where Self: Sized + Send + 'static,
              S: Spawn + Clone + Send + 'static
    {
        ServerHandle::start(self, bind_addr, spawner)
    }
}

pub trait HandleSocket: Sized + Send + 'static {
    type Transport: TransportStream;
    type Future: Future<Item = Connection<Self::Transport>, Error = Error> + Send + 'static;
    fn handle(self, socket: TcpStream) -> Self::Future;
}

pub trait HandleConnection: Sized + Send + 'static {
    type Transport: TransportStream;
    type Future: Future<Item = (), Error = ()> + Send + 'static;

    fn handle(self, connection: Connection<Self::Transport>) -> Self::Future;

    #[allow(unused_variables)]
    fn on_error(self, client: SocketAddr, error: Error) {}
}

#[derive(Debug)]
pub struct Connection<T> {
    inner: connection::Connection<T>,
    version: Version,
}
impl<T: TransportStream> Connection<T> {
    pub fn new(stream: T,
               min_buffer_size: usize,
               max_buffer_size: usize,
               max_header_count: usize)
               -> Self {
        let inner =
            connection::Connection::new(stream, min_buffer_size, max_buffer_size, max_header_count);
        Connection {
            inner: inner,
            version: Version::default(),
        }
    }
    pub fn read_request(self) -> ReadRequest<T> {
        ReadRequest::new(self)
    }
    pub fn build_response<'a, S>(self, status: S) -> ResponseBuilder<T>
        where S: Into<RawStatus<'a>>
    {
        response::builder(self, status.into())
    }
}
impl<T> AsMut<connection::Connection<T>> for Connection<T> {
    fn as_mut(&mut self) -> &mut connection::Connection<T> {
        &mut self.inner
    }
}

#[derive(Debug)]
enum Command {
    Stop,
}

#[derive(Debug)]
pub struct ServerHandle {
    command_tx: mpsc::Sender<Command>,
    monitor: oneshot::Monitor<(), Error>,
}
impl ServerHandle {
    fn start<S, T>(mut server: S, bind_addr: SocketAddr, spawner: T) -> ServerHandle
        where S: Server + Send + 'static,
              T: Spawn + Clone + Send + 'static
    {
        let (command_tx, command_rx) = mpsc::channel();
        let future = {
            let spawner = spawner.clone();
            TcpListener::bind(bind_addr)
                .map_err(Error::from)
                .and_then(move |mut listener| if let Err(e) =
                    server.before_listen(&mut listener) {
                    Either::A(futures::failed(e))
                } else {
                    let server_loop = ServerLoop {
                        server: server,
                        spawner: spawner,
                        incoming: listener.incoming(),
                        command_rx: command_rx,
                    };
                    Either::B(server_loop)
                })
        };
        let monitor = spawner.spawn_monitor(future);
        ServerHandle {
            monitor: monitor,
            command_tx: command_tx,
        }
    }
    pub fn stop(self) -> JoinServer {
        let _ = self.command_tx.send(Command::Stop);
        JoinServer(self)
    }
    pub fn join(self) -> JoinServer {
        JoinServer(self)
    }
}

#[derive(Debug)]
pub struct JoinServer(ServerHandle);
impl Future for JoinServer {
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.0.monitor.poll().map_err(|e| e.unwrap_or(ErrorKind::ServerAborted.into()))
    }
}

#[derive(Debug)]
struct ServerLoop<S, T> {
    server: S,
    spawner: T,
    incoming: Incoming,
    command_rx: mpsc::Receiver<Command>,
}
impl<S, T> ServerLoop<S, T> {
    fn handle_command(&mut self, command: Command) -> Option<Result<()>> {
        match command {
            Command::Stop => Some(Ok(())),
        }
    }
}
impl<S, T> Future for ServerLoop<S, T>
    where S: Server,
          T: Spawn
{
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        'toplevel: loop {
            match self.command_rx.poll().expect("unreachable") {
                Async::Ready(None) => return Ok(Async::Ready(())),
                Async::Ready(Some(command)) => {
                    if let Some(shutdown) = self.handle_command(command) {
                        return shutdown.map(|()| Async::Ready(()));
                    } else {
                        continue;
                    }
                }
                Async::NotReady => {}
            }
            // FIXME: delete below loop in fibers-v0.1.3
            for _ in 0..2 {
                match self.incoming.poll()? {
                    Async::NotReady => {
                        // return Ok(Async::NotReady);
                    }
                    Async::Ready(None) => unreachable!(),
                    Async::Ready(Some((socket, address))) => {
                        let (socket_handler, connection_handler) = self.server.create_handlers();
                        self.spawner.spawn(socket.map_err(Error::from)
                            .and_then(move |socket| socket_handler.handle(socket))
                            .then(move |result| match result {
                                Err(e) => {
                                    connection_handler.on_error(address, e);
                                    Either::A(futures::failed(()))
                                }
                                Ok(connection) => Either::B(connection_handler.handle(connection)),
                            }));
                        continue 'toplevel;
                    }
                }
            }
            return Ok(Async::NotReady);
        }
    }
}
<commit_msg>Remove temporary patch for fibers-v0.1.2<commit_after>use std::net::SocketAddr;
use fibers::Spawn;
use fibers::sync::{mpsc, oneshot};
use fibers::net::{TcpListener, TcpStream};
use fibers::net::streams::Incoming;
use futures::{self, Future, Stream, Poll, Async};
use futures::future::Either;

pub use self::request::{Request, ReadRequest};
pub use self::response::{Response, ResponseBuilder};

use {Result, Error, ErrorKind, TransportStream, Version};
use status::RawStatus;
use connection;

mod request;
mod response;

pub trait Server {
    type Transport: TransportStream;
    type SocketHandler: HandleSocket<Transport = Self::Transport>;
    type ConnectionHandler: HandleConnection<Transport = Self::Transport>;

    #[allow(unused_variables)]
    fn before_listen(&mut self, listener: &mut TcpListener) -> Result<()> {
        Ok(())
    }
    fn create_handlers(&mut self) -> (Self::SocketHandler, Self::ConnectionHandler);
    fn start<S>(self, bind_addr: SocketAddr, spawner: S) -> ServerHandle
        where Self: Sized + Send + 'static,
              S: Spawn + Clone + Send + 'static
    {
        ServerHandle::start(self, bind_addr, spawner)
    }
}

pub trait HandleSocket: Sized + Send + 'static {
    type Transport: TransportStream;
    type Future: Future<Item = Connection<Self::Transport>, Error = Error> + Send + 'static;
    fn handle(self, socket: TcpStream) -> Self::Future;
}

pub trait HandleConnection: Sized + Send + 'static {
    type Transport: TransportStream;
    type Future: Future<Item = (), Error = ()> + Send + 'static;

    fn handle(self, connection: Connection<Self::Transport>) -> Self::Future;

    #[allow(unused_variables)]
    fn on_error(self, client: SocketAddr, error: Error) {}
}

#[derive(Debug)]
pub struct Connection<T> {
    inner: connection::Connection<T>,
    version: Version,
}
impl<T: TransportStream> Connection<T> {
    pub fn new(stream: T,
               min_buffer_size: usize,
               max_buffer_size: usize,
               max_header_count: usize)
               -> Self {
        let inner =
            connection::Connection::new(stream, min_buffer_size, max_buffer_size, max_header_count);
        Connection {
            inner: inner,
            version: Version::default(),
        }
    }
    pub fn read_request(self) -> ReadRequest<T> {
        ReadRequest::new(self)
    }
    pub fn build_response<'a, S>(self, status: S) -> ResponseBuilder<T>
        where S: Into<RawStatus<'a>>
    {
        response::builder(self, status.into())
    }
}
impl<T> AsMut<connection::Connection<T>> for Connection<T> {
    fn as_mut(&mut self) -> &mut connection::Connection<T> {
        &mut self.inner
    }
}

#[derive(Debug)]
enum Command {
    Stop,
}

#[derive(Debug)]
pub struct ServerHandle {
    command_tx: mpsc::Sender<Command>,
    monitor: oneshot::Monitor<(), Error>,
}
impl ServerHandle {
    fn start<S, T>(mut server: S, bind_addr: SocketAddr, spawner: T) -> ServerHandle
        where S: Server + Send + 'static,
              T: Spawn + Clone + Send + 'static
    {
        let (command_tx, command_rx) = mpsc::channel();
        let future = {
            let spawner = spawner.clone();
            TcpListener::bind(bind_addr)
                .map_err(Error::from)
                .and_then(move |mut listener| if let Err(e) =
                    server.before_listen(&mut listener) {
                    Either::A(futures::failed(e))
                } else {
                    let server_loop = ServerLoop {
                        server: server,
                        spawner: spawner,
                        incoming: listener.incoming(),
                        command_rx: command_rx,
                    };
                    Either::B(server_loop)
                })
        };
        let monitor = spawner.spawn_monitor(future);
        ServerHandle {
            monitor: monitor,
            command_tx: command_tx,
        }
    }
    pub fn stop(self) -> JoinServer {
        let _ = self.command_tx.send(Command::Stop);
        JoinServer(self)
    }
    pub fn join(self) -> JoinServer {
        JoinServer(self)
    }
}

#[derive(Debug)]
pub struct JoinServer(ServerHandle);
impl Future for JoinServer {
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.0.monitor.poll().map_err(|e| e.unwrap_or(ErrorKind::ServerAborted.into()))
    }
}

#[derive(Debug)]
struct ServerLoop<S, T> {
    server: S,
    spawner: T,
    incoming: Incoming,
    command_rx: mpsc::Receiver<Command>,
}
impl<S, T> ServerLoop<S, T> {
    fn handle_command(&mut self, command: Command) -> Option<Result<()>> {
        match command {
            Command::Stop => Some(Ok(())),
        }
    }
}
impl<S, T> Future for ServerLoop<S, T>
    where S: Server,
          T: Spawn
{
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            match self.command_rx.poll().expect("unreachable") {
                Async::Ready(None) => return Ok(Async::Ready(())),
                Async::Ready(Some(command)) => {
                    if let Some(shutdown) = self.handle_command(command) {
                        return shutdown.map(|()| Async::Ready(()));
                    } else {
                        continue;
                    }
                }
                Async::NotReady => {}
            }
            match self.incoming.poll()? {
                Async::NotReady => return Ok(Async::NotReady),
                Async::Ready(None) => unreachable!(),
                Async::Ready(Some((socket, address))) => {
                    let (socket_handler, connection_handler) = self.server.create_handlers();
                    self.spawner.spawn(socket.map_err(Error::from)
                        .and_then(move |socket| socket_handler.handle(socket))
                        .then(move |result| match result {
                            Err(e) => {
                                connection_handler.on_error(address, e);
                                Either::A(futures::failed(()))
                            }
                            Ok(connection) => Either::B(connection_handler.handle(connection)),
                        }));
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::time::{Duration, SystemTime, Instant};
use std::convert::TryFrom;

use crate::stacked_borrows::Tag;
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};

use rustc_middle::ty::layout::LayoutOf;

/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("linux", "clock_gettime");
        this.check_no_isolation("clock_gettime")?;

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        let tp = this.deref_operand(tp_op)?;

        let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
            system_time_to_duration(&SystemTime::now())?
        } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
            // Absolute time does not matter, only relative time does, so we can just
            // use our own time anchor here.
            Instant::now().duration_since(this.machine.time_anchor)
        } else {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        };

        let tv_sec = duration.as_secs();
        let tv_nsec = duration.subsec_nanos();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
        ];

        this.write_packed_immediates(tp, &imms)?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("macos", "gettimeofday");
        this.check_no_isolation("gettimeofday")?;

        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.deref_operand(tv_op)?;

        let duration = system_time_to_duration(&SystemTime::now())?;
        let tv_sec = duration.as_secs();
        let tv_usec = duration.subsec_micros();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
        ];

        this.write_packed_immediates(tv, &imms)?;

        Ok(0)
    }

    #[allow(non_snake_case)]
    fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "GetSystemTimeAsFileTime");
        this.check_no_isolation("GetSystemTimeAsFileTime")?;

        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;

        let duration = system_time_to_duration(&SystemTime::now())?
            .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
            .unwrap();
        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?;

        let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
        let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
        let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
        let imms = [
            immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
            immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
        ];
        this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
        Ok(())
    }

    #[allow(non_snake_case)]
    fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "QueryPerformanceCounter");
        this.check_no_isolation("QueryPerformanceCounter")?;

        // QPC uses a hardware counter as its basis.
        // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        let qpc = i64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?;
        this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?;
        Ok(-1) // return non-zero on success
    }

    #[allow(non_snake_case)]
    fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "QueryPerformanceFrequency");
        this.check_no_isolation("QueryPerformanceFrequency")?;

        // Retrieves the frequency of the hardware performance counter.
        // The frequency of the performance counter is fixed at system boot and
        // is consistent across all processors.
        // Miri will assume that the frequency of
        // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz).
        this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?;
        Ok(-1) // Return non-zero on success
    }

    fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
        let this = self.eval_context_ref();

        this.assert_target_os("macos", "mach_absolute_time");
        this.check_no_isolation("mach_absolute_time")?;

        // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
        // We return plain nanoseconds.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        u64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into())
    }
}
<commit_msg>Update comments in src/shims/time.rs<commit_after>use std::time::{Duration, SystemTime, Instant};
use std::convert::TryFrom;

use crate::stacked_borrows::Tag;
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};

use rustc_middle::ty::layout::LayoutOf;

/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("linux", "clock_gettime");
        this.check_no_isolation("clock_gettime")?;

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        let tp = this.deref_operand(tp_op)?;

        let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
            system_time_to_duration(&SystemTime::now())?
        } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
            // Absolute time does not matter, only relative time does, so we can just
            // use our own time anchor here.
            Instant::now().duration_since(this.machine.time_anchor)
        } else {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        };

        let tv_sec = duration.as_secs();
        let tv_nsec = duration.subsec_nanos();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
        ];

        this.write_packed_immediates(tp, &imms)?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("macos", "gettimeofday");
        this.check_no_isolation("gettimeofday")?;

        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.deref_operand(tv_op)?;

        let duration = system_time_to_duration(&SystemTime::now())?;
        let tv_sec = duration.as_secs();
        let tv_usec = duration.subsec_micros();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
        ];

        this.write_packed_immediates(tv, &imms)?;

        Ok(0)
    }

    #[allow(non_snake_case)]
    fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "GetSystemTimeAsFileTime");
        this.check_no_isolation("GetSystemTimeAsFileTime")?;

        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;

        let duration = system_time_to_duration(&SystemTime::now())?
            .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
            .unwrap();
        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?;

        let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
        let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
        let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
        let imms = [
            immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
            immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
        ];
        this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
        Ok(())
    }

    #[allow(non_snake_case)]
    fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "QueryPerformanceCounter");
        this.check_no_isolation("QueryPerformanceCounter")?;

        // QPC uses a hardware counter as its basis.
        // Miri will emulate a counter with a resolution of 1 nanosecond.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        let qpc = i64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?;
        this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?;
        Ok(-1) // return non-zero on success
    }

    #[allow(non_snake_case)]
    fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "QueryPerformanceFrequency");
        this.check_no_isolation("QueryPerformanceFrequency")?;

        // Retrieves the frequency of the hardware performance counter.
        // The frequency of the performance counter is fixed at system boot and
        // is consistent across all processors.
        // Miri will assume that the frequency of
        // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz).
        this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?;
        Ok(-1) // Return non-zero on success
    }

    fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
        let this = self.eval_context_ref();

        this.assert_target_os("macos", "mach_absolute_time");
        this.check_no_isolation("mach_absolute_time")?;

        // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
        // We return plain nanoseconds.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        u64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into())
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::iter::Iterator;
use std::slice;

use flate2::read::GzDecoder;
use tar;
use time::Timespec;

use collections::{CollectionsStatus, SignatureChain, SignatureFile};
use backend::Backend;

pub struct BackupFiles<B> {
    backend: B,
    snapshots: Vec<Snapshot>
}

impl<B: Backend> BackupFiles<B> {
    pub fn new(backend: B) -> io::Result<BackupFiles<B>> {
        let collection = {
            let filenames = try!(backend.get_file_names());
            CollectionsStatus::from_filenames(&filenames)
        };
        let chains = collection.signature_chains();
        // TODO: go from signature chains to snapshots
        Ok(BackupFiles{ backend: backend, snapshots: Vec::new() })
    }

    pub fn snapshots(&self) -> Snapshots {
        self.snapshots.iter()
    }

//    fn signatures_files(chain: &SignatureChain) -> Vec<TarHeaderIter> {
//        unimplemented!()
//    }

    fn signature_file_iter(&self, signature: &SignatureFile) -> io::Result<TarHeaderIter> {
        let file = try!(self.backend.open_file(signature.file_name.as_ref()));
        if signature.compressed {
            let gz_decoder = try!(GzDecoder::new(file));
            let mut tar = tar::Archive::new(gz_decoder);
        }
        unimplemented!()
    }
}

type TarHeaderIter<'a> = Box<Iterator<Item=&'a tar::Header>>;

struct TarHeaderIterImpl<'a, R: 'a>(tar::FilesMut<'a, R>);

impl<'a, R> Iterator for TarHeaderIterImpl<'a, R> {
    type Item = &'a tar::Header;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

/// Iterator over a list of backup snapshots.
pub type Snapshots<'a> = slice::Iter<'a, Snapshot>;

pub struct Snapshot {
    pub time: Timespec
}

// impl Snapshot {
//     pub fn files(&self) ->
// }

pub struct File {
    pub name: String,
    pub last_modified: Timespec
}
<commit_msg>Still working on tar type erasure. Not building :(<commit_after>use std::io;
use std::iter::Iterator;
use std::slice;

use flate2::read::GzDecoder;
use tar;
use time::Timespec;

use collections::{CollectionsStatus, SignatureChain, SignatureFile};
use backend::Backend;

pub struct BackupFiles<B> {
    backend: B,
    snapshots: Vec<Snapshot>
}

impl<B: Backend> BackupFiles<B> {
    pub fn new(backend: B) -> io::Result<BackupFiles<B>> {
        let collection = {
            let filenames = try!(backend.get_file_names());
            CollectionsStatus::from_filenames(&filenames)
        };
        let chains = collection.signature_chains();
        // TODO: go from signature chains to snapshots
        Ok(BackupFiles{ backend: backend, snapshots: Vec::new() })
    }

    pub fn snapshots(&self) -> Snapshots {
        self.snapshots.iter()
    }

//    fn signatures_files(chain: &SignatureChain) -> Vec<TarHeaderIter> {
//        unimplemented!()
//    }

//    fn signature_file_iter(&self, signature: &SignatureFile) -> io::Result<BoxTarHeaderIter> {
//        let file = try!(self.backend.open_file(signature.file_name.as_ref()));
//        if signature.compressed {
//            let gz_decoder = try!(GzDecoder::new(file));
//            let mut tar = tar::Archive::new(gz_decoder);
//        }
//        unimplemented!()
//    }
}

trait TarArchive {
    fn file_headers(&mut self) -> io::Result<Box<TarHeaderIter>>;
}

impl<R: io::Read> TarArchive for tar::Archive<R> {
    fn file_headers(&mut self) -> io::Result<Box<TarHeaderIter>> {
        let files = try!(self.files_mut());
        Ok(Box::new(TarHeaderIterImpl(files)))
    }
}

type TarHeaderIter<'a> = Iterator<Item=&'a tar::Header>;

struct TarHeaderIterImpl<'a, R: 'a>(tar::FilesMut<'a, R>);

impl<'a, R> Iterator for TarHeaderIterImpl<'a, R> {
    type Item = &'a tar::Header;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

/// Iterator over a list of backup snapshots.
pub type Snapshots<'a> = slice::Iter<'a, Snapshot>;

pub struct Snapshot {
    pub time: Timespec
}

// impl Snapshot {
//     pub fn files(&self) ->
// }

pub struct File {
    pub name: String,
    pub last_modified: Timespec
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Word_wrap

//! Using the [minimum length greedy algorithm].
//!
//! Implemented as a lazy `String` iterator, returning a wrapped line each time.
//!
//! [minimum length greedy algorithm]: http://en.wikipedia.org/wiki/Word_wrap#Minimum_length
use std::mem::swap;
use std::str::SplitWhitespace;

pub struct WordWrap<'a> {
    words: SplitWhitespace<'a>,
    line_length: usize,
    next_line: String,
}

impl<'a> WordWrap<'a> {
    fn new(text: &'a str, line_length: usize) -> WordWrap {
        WordWrap {
            words: text.split_whitespace(),
            line_length: line_length,
            next_line: String::new(),
        }
    }
}

impl<'a> Iterator for WordWrap<'a> {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        // Move anything left over from last run to this_line
        let mut this_line = String::new();
        swap(&mut self.next_line, &mut this_line);

        let mut space_left = self.line_length - this_line.chars().count();
        const SPACE_WIDTH: usize = 1;

        // Loop, adding words until we run out of words or hit the line length
        while let Some(word) = self.words.next() {
            let word_length = word.chars().count();

            // If not the first word for this line
            if space_left != self.line_length {
                if word_length + SPACE_WIDTH > space_left {
                    // Out of space, save word for next line
                    self.next_line.push_str(word);
                    break;
                } else {
                    // Add a space and keep going
                    this_line.push(' ');
                    space_left -= SPACE_WIDTH;
                }
            }

            // Add word to this line
            this_line.push_str(word);
            space_left -= word_length;
        }

        if this_line.is_empty() {
            None
        } else {
            Some(this_line)
        }
    }
}

fn main() {
    let text = "In olden times when wishing still helped one, there lived a king whose daughters \
                were all beautiful, but the youngest was so beautiful that the sun itself, which \
                has seen so much, was astonished whenever it shone in her face.  Close by the \
                king's castle lay a great dark forest, and under an old lime tree in the forest \
                was a well, and when the day was very warm, the king's child went out into the \
                forest and sat down by the side of the cool fountain, and when she was bored she \
                took a golden ball, and threw it up on high and caught it, and this ball was her \
                favorite plaything.";

    for length in 72..81 {
        println!("Text wrapped at {}", length);
        for line in WordWrap::new(text, length) {
            println!("{}", line);
        }
        println!("");
    }
}

#[test]
fn test_empty_string() {
    assert_eq!(WordWrap::new("", 80).next(), None);
}

#[test]
fn test_single_word_shorter_than_line() {
    assert_eq!(WordWrap::new("Hello", 80).next().unwrap(), "Hello");
}

#[test]
fn test_two_words_shorter_than_line() {
    assert_eq!(WordWrap::new("Hello world", 80).next().unwrap(),
               "Hello world");
}

#[test]
fn test_wrap_second_word() {
    let mut w = WordWrap::new("Hello world", 10);
    assert_eq!(w.next().unwrap(), "Hello");
    assert_eq!(w.next().unwrap(), "world");
}

#[test]
fn test_wrap_punctuation() {
    let mut w = WordWrap::new("Hello, world", 6);
    assert_eq!(w.next().unwrap(), "Hello,");
    assert_eq!(w.next().unwrap(), "world");
}

#[test]
fn test_squash_multiple_spaces() {
    let mut w = WordWrap::new(" Hello  to the    world    ", 10);
    assert_eq!(w.next().unwrap(), "Hello to");
    assert_eq!(w.next().unwrap(), "the world");
    assert_eq!(w.next(), None);
}

#[test]
fn test_unicode() {
    let mut w = WordWrap::new("Nous étions à l'Étude, quand le Proviseur entra", 11);
    assert_eq!(w.next().unwrap(), "Nous étions");
    assert_eq!(w.next().unwrap(), "à l'Étude,");
    assert_eq!(w.next().unwrap(), "quand le");
    assert_eq!(w.next().unwrap(), "Proviseur");
    assert_eq!(w.next().unwrap(), "entra");
}
<commit_msg>only use `while let` on iterators if needed<commit_after>// http://rosettacode.org/wiki/Word_wrap

//! Using the [minimum length greedy algorithm].
//!
//! Implemented as a lazy `String` iterator, returning a wrapped line each time.
//!
//! [minimum length greedy algorithm]: http://en.wikipedia.org/wiki/Word_wrap#Minimum_length
use std::mem::swap;
use std::str::SplitWhitespace;

pub struct WordWrap<'a> {
    words: SplitWhitespace<'a>,
    line_length: usize,
    next_line: String,
}

impl<'a> WordWrap<'a> {
    fn new(text: &'a str, line_length: usize) -> WordWrap {
        WordWrap {
            words: text.split_whitespace(),
            line_length: line_length,
            next_line: String::new(),
        }
    }
}

impl<'a> Iterator for WordWrap<'a> {
    type Item = String;

    #[cfg_attr(feature="clippy", allow(while_let_on_iterator))]
    fn next(&mut self) -> Option<String> {
        // Move anything left over from last run to this_line
        let mut this_line = String::new();
        swap(&mut self.next_line, &mut this_line);

        let mut space_left = self.line_length - this_line.chars().count();
        const SPACE_WIDTH: usize = 1;

        // Loop, adding words until we run out of words or hit the line length
        while let Some(word) = self.words.next() {
            let word_length = word.chars().count();

            // If not the first word for this line
            if space_left != self.line_length {
                if word_length + SPACE_WIDTH > space_left {
                    // Out of space, save word for next line
                    self.next_line.push_str(word);
                    break;
                } else {
                    // Add a space and keep going
                    this_line.push(' ');
                    space_left -= SPACE_WIDTH;
                }
            }

            // Add word to this line
            this_line.push_str(word);
            space_left -= word_length;
        }

        if this_line.is_empty() {
            None
        } else {
            Some(this_line)
        }
    }
}

fn main() {
    let text = "In olden times when wishing still helped one, there lived a king whose daughters \
                were all beautiful, but the youngest was so beautiful that the sun itself, which \
                has seen so much, was astonished whenever it shone in her face.  Close by the \
                king's castle lay a great dark forest, and under an old lime tree in the forest \
                was a well, and when the day was very warm, the king's child went out into the \
                forest and sat down by the side of the cool fountain, and when she was bored she \
                took a golden ball, and threw it up on high and caught it, and this ball was her \
                favorite plaything.";

    for length in 72..81 {
        println!("Text wrapped at {}", length);
        for line in WordWrap::new(text, length) {
            println!("{}", line);
        }
        println!("");
    }
}

#[test]
fn test_empty_string() {
    assert_eq!(WordWrap::new("", 80).next(), None);
}

#[test]
fn test_single_word_shorter_than_line() {
    assert_eq!(WordWrap::new("Hello", 80).next().unwrap(), "Hello");
}

#[test]
fn test_two_words_shorter_than_line() {
    assert_eq!(WordWrap::new("Hello world", 80).next().unwrap(),
               "Hello world");
}

#[test]
fn test_wrap_second_word() {
    let mut w = WordWrap::new("Hello world", 10);
    assert_eq!(w.next().unwrap(), "Hello");
    assert_eq!(w.next().unwrap(), "world");
}

#[test]
fn test_wrap_punctuation() {
    let mut w = WordWrap::new("Hello, world", 6);
    assert_eq!(w.next().unwrap(), "Hello,");
    assert_eq!(w.next().unwrap(), "world");
}

#[test]
fn test_squash_multiple_spaces() {
    let mut w = WordWrap::new(" Hello  to the    world    ", 10);
    assert_eq!(w.next().unwrap(), "Hello to");
    assert_eq!(w.next().unwrap(), "the world");
    assert_eq!(w.next(), None);
}

#[test]
fn test_unicode() {
    let mut w = WordWrap::new("Nous étions à l'Étude, quand le Proviseur entra", 11);
    assert_eq!(w.next().unwrap(), "Nous étions");
    assert_eq!(w.next().unwrap(), "à l'Étude,");
    assert_eq!(w.next().unwrap(), "quand le");
    assert_eq!(w.next().unwrap(), "Proviseur");
    assert_eq!(w.next().unwrap(), "entra");
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate env_logger;
extern crate futuremio;
extern crate ssl;

#[macro_use]
extern crate cfg_if;

use std::io::Error;
use std::net::ToSocketAddrs;

use futures::Future;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl as ossl;

        fn get(err: &Error) -> &[ossl::error::OpenSslError] {
            let err = err.get_ref().unwrap();
            match *err.downcast_ref::<ossl::error::Error>().unwrap() {
                ossl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            }
        }

        fn verify_failed(err: &Error) {
            assert!(get(err).iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", err);
        }

        use verify_failed as assert_expired_error;
        use verify_failed as assert_wrong_host;
        use verify_failed as assert_self_signed;
        use verify_failed as assert_untrusted_root;

        fn assert_dh_too_small(err: &Error) {
            assert!(get(err).iter().any(|e| {
                e.reason() == "dh key too small"
            }), "bad errors: {:?}", err);
        }
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_expired_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        fn assert_wrong_host(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        fn assert_self_signed(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        fn assert_untrusted_root(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        fn assert_dh_too_small(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }
    } else {
        extern crate winapi;

        fn assert_expired_error(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_wrong_host(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_self_signed(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_untrusted_root(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_dh_too_small(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }
    }
}

fn get_host(host: &'static str) -> Error {
    drop(env_logger::init());

    let addr = format!("{}:443", host);
    let addr = t!(addr.to_socket_addrs()).next().unwrap();

    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake(host, socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    res.err().unwrap()
}

#[test]
fn expired() {
    assert_expired_error(&get_host("expired.badssl.com"))
}

#[test]
fn wrong_host() {
    assert_wrong_host(&get_host("wrong.host.badssl.com"))
}

#[test]
fn self_signed() {
    assert_self_signed(&get_host("self-signed.badssl.com"))
}

#[test]
fn untrusted_root() {
    assert_untrusted_root(&get_host("untrusted-root.badssl.com"))
}

#[test]
fn dh_too_small() {
    assert_dh_too_small(&get_host("dh480.badssl.com"))
}
<commit_msg>Fix bad SSL tests on OSX<commit_after>extern crate futures;
extern crate env_logger;
extern crate futuremio;
extern crate ssl;

#[macro_use]
extern crate cfg_if;

use std::io::Error;
use std::net::ToSocketAddrs;

use futures::Future;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl as ossl;

        fn get(err: &Error) -> &[ossl::error::OpenSslError] {
            let err = err.get_ref().unwrap();
            match *err.downcast_ref::<ossl::error::Error>().unwrap() {
                ossl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            }
        }

        fn verify_failed(err: &Error) {
            assert!(get(err).iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", err);
        }

        use verify_failed as assert_expired_error;
        use verify_failed as assert_wrong_host;
        use verify_failed as assert_self_signed;
        use verify_failed as assert_untrusted_root;

        fn assert_dh_too_small(err: &Error) {
            assert!(get(err).iter().any(|e| {
                e.reason() == "dh key too small"
            }), "bad errors: {:?}", err);
        }
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_invalid_cert_chain(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }

        use assert_invalid_cert_chain as assert_expired_error;
        use assert_invalid_cert_chain as assert_wrong_host;
        use assert_invalid_cert_chain as assert_self_signed;
        use assert_invalid_cert_chain as assert_untrusted_root;

        fn assert_dh_too_small(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "handshake failure");
        }
    } else {
        extern crate winapi;

        fn assert_expired_error(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_wrong_host(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_self_signed(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_untrusted_root(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }

        fn assert_dh_too_small(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }
    }
}

fn get_host(host: &'static str) -> Error {
    drop(env_logger::init());

    let addr = format!("{}:443", host);
    let addr = t!(addr.to_socket_addrs()).next().unwrap();

    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake(host, socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    res.err().unwrap()
}

#[test]
fn expired() {
    assert_expired_error(&get_host("expired.badssl.com"))
}

#[test]
fn wrong_host() {
    assert_wrong_host(&get_host("wrong.host.badssl.com"))
}

#[test]
fn self_signed() {
    assert_self_signed(&get_host("self-signed.badssl.com"))
}

#[test]
fn untrusted_root() {
    assert_untrusted_root(&get_host("untrusted-root.badssl.com"))
}

#[test]
fn dh_too_small() {
    assert_dh_too_small(&get_host("dh480.badssl.com"))
}
<|endoftext|>


<commit_before>//! Access to open sqlite3 database by filename.
//!
//! The `core` module requires explicit authority to access files and such,
//! following the principle of least authority.
//!
//! This module provides the privileged functions to create such authorities.
//!
//! *TODO: move `mod access` to its own crate so that linking to `sqlite3` doesn't
//! bring in this ambient authority.*
#![unstable]

use libc::c_int;
use std::ptr;

use super::SqliteResult;
use core::{Access, DatabaseConnection, str_charstar};
use ffi;

use access::flags::OpenFlags;

// submodule KLUDGE around missing_docs for bitflags!()
#[allow(missing_docs)]
pub mod flags;

/// Open a database by filename.
///
/// *TODO: test for "Note that sqlite3_open() can be used to either
/// open existing database files or to create and open new database
/// files."*
///
///
/// Refer to [Opening A New Database][open] regarding URI filenames.
///
/// [open]: http://www.sqlite.org/c3ref/open.html
#[stable]
pub fn open(filename: &str, flags: Option<OpenFlags>) -> SqliteResult<DatabaseConnection> {
    DatabaseConnection::new(
        ByFilename {
            filename: filename,
            flags: flags.unwrap_or_default()
        })
}

/// Access to a database by filename
pub struct ByFilename<'a> {
    /// Filename or sqlite3 style URI.
    pub filename: &'a str,
    /// Flags for additional control over the new database connection.
    pub flags: OpenFlags
}

impl<'a> Access for ByFilename<'a> {
    fn open(self, db: *mut *mut ffi::sqlite3) -> c_int {
        let c_filename = str_charstar(self.filename).as_ptr();
        let flags = self.flags.bits();
        unsafe { ffi::sqlite3_open_v2(c_filename, db, flags, ptr::null()) }
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use super::ByFilename;
    use core::DatabaseConnection;

    #[test]
    fn open_file_db() {
        DatabaseConnection::new(
            ByFilename {
                filename: "/tmp/db1", flags: Default::default()
            })
            .unwrap();
    }
}

// Local Variables:
// flycheck-rust-crate-root: "lib.rs"
// End:
<commit_msg>open_file_db test works on Windows<commit_after>//! Access to open sqlite3 database by filename.
//!
//! The `core` module requires explicit authority to access files and such,
//! following the principle of least authority.
//!
//! This module provides the privileged functions to create such authorities.
//!
//! *TODO: move `mod access` to its own crate so that linking to `sqlite3` doesn't
//! bring in this ambient authority.*
#![unstable]

use libc::c_int;
use std::ptr;

use super::SqliteResult;
use core::{Access, DatabaseConnection, str_charstar};
use ffi;

use access::flags::OpenFlags;

// submodule KLUDGE around missing_docs for bitflags!()
#[allow(missing_docs)]
pub mod flags;

/// Open a database by filename.
///
/// *TODO: test for "Note that sqlite3_open() can be used to either
/// open existing database files or to create and open new database
/// files."*
///
///
/// Refer to [Opening A New Database][open] regarding URI filenames.
///
/// [open]: http://www.sqlite.org/c3ref/open.html
#[stable]
pub fn open(filename: &str, flags: Option<OpenFlags>) -> SqliteResult<DatabaseConnection> {
    DatabaseConnection::new(
        ByFilename {
            filename: filename,
            flags: flags.unwrap_or_default()
        })
}

/// Access to a database by filename
pub struct ByFilename<'a> {
    /// Filename or sqlite3 style URI.
    pub filename: &'a str,
    /// Flags for additional control over the new database connection.
    pub flags: OpenFlags
}

impl<'a> Access for ByFilename<'a> {
    fn open(self, db: *mut *mut ffi::sqlite3) -> c_int {
        let c_filename = str_charstar(self.filename).as_ptr();
        let flags = self.flags.bits();
        unsafe { ffi::sqlite3_open_v2(c_filename, db, flags, ptr::null()) }
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use super::ByFilename;
    use core::DatabaseConnection;
    use std::os::tmpdir;
    use std::path::BytesContainer;

    #[test]
    fn open_file_db() {
        let mut temp_directory = tmpdir();
        temp_directory.push("db1");
        let path = temp_directory.container_as_str().unwrap();
        DatabaseConnection::new(
            ByFilename {
                filename: path, flags: Default::default()
            })
            .unwrap();
    }
}

// Local Variables:
// flycheck-rust-crate-root: "lib.rs"
// End:
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Handlers and types for agent's actions.
//!
//! The basic functionality that a GRR agent exposes is called an _action_.
//! Actions are invoked by the server (when running a _flow_), should gather
//! requested information and report back to the server.
//!
//! In RRG each action consists of three components: a request type, a response
//! type and an action handler. Request and response types wrap lower-level
//! Protocol Buffer messages sent by and to the GRR server. Handlers accept one
//! instance of the corresponding request type and send some (zero or more)
//! instances of the corresponding response type.

mod error;

#[cfg(feature = "action-filesystems")]
#[cfg(target_os = "linux")]
pub mod filesystems;

#[cfg(feature = "action-interfaces")]
#[cfg(target_family = "unix")]
pub mod interfaces;

#[cfg(feature = "action-metadata")]
pub mod metadata;

#[cfg(feature = "action-listdir")]
pub mod listdir;

#[cfg(feature = "action-timeline")]
pub mod timeline;

#[cfg(feature = "action-network")]
pub mod network;

#[cfg(feature = "action-stat")]
pub mod stat;

#[cfg(feature = "action-insttime")]
pub mod insttime;

#[cfg(feature = "action-memsize")]
pub mod memsize;

#[cfg(feature = "action-finder")]
pub mod finder;

pub use error::{ParseArgsError, ParseArgsErrorKind, DispatchError};
use crate::session::{self, Session};

/// Dispatches the given `request` to an appropriate action handler.
///
/// This method is a mapping between action names (as specified in the protocol)
/// and action handlers (implemented on the agent).
///
/// # Errors
///
/// This function will return an error if the given action is unknown (or not
/// yet implemented).
///
/// It will also error out if the action execution itself fails for whatever
/// reason.
pub fn dispatch<'s, S>(session: &mut S, request: crate::message::Request) -> Result<(), DispatchError>
where
    S: Session,
{
    match request.action_name() {
        #[cfg(feature = "action-metadata")]
        "GetClientInfo" => handle(session, request, self::metadata::handle),

        #[cfg(feature = "action-listdir")]
        "ListDirectory" => handle(session, request, self::listdir::handle),

        #[cfg(feature = "action-timeline")]
        "Timeline" => handle(session, request, self::timeline::handle),

        #[cfg(feature = "action-network")]
        "ListNetworkConnections" => handle(session, request, self::network::handle),

        #[cfg(feature = "action-stat")]
        "GetFileStat" => handle(session, request, self::stat::handle),

        #[cfg(feature = "action-insttime")]
        "GetInstallDate" => handle(session, request, self::insttime::handle),

        #[cfg(feature = "action-interfaces")]
        #[cfg(target_family = "unix")]
        "EnumerateInterfaces" => handle(session, request, self::interfaces::handle),

        #[cfg(feature = "action-filesystems")]
        #[cfg(target_os = "linux")]
        "EnumerateFilesystems" => handle(session, request, self::filesystems::handle),

        #[cfg(feature = "action-memsize")]
        "GetMemorySize" => handle(session, request, self::memsize::handle),

        action_name => {
            return Err(error::UnknownActionError::new(action_name).into())
        }
    }
}

/// Handles a `request` using the specified `handler`.
///
/// This method will attempt to interpret request arguments for the specific
/// action and execute the handler with them.
///
/// # Errors
///
/// This function will return an error if the request arguments cannot be parsed
/// for the specific action or if the action execution fails.
fn handle<S, A, H>(session: &mut S, request: crate::message::Request, handler: H) -> Result<(), DispatchError>
where
    S: crate::session::Session,
    A: Args,
    H: FnOnce(&mut S, A) -> session::Result<()>,
{
    let args = request.parse_args()?;
    Ok(handler(session, args)?)
}

// TODO(panhania@): Remove all usages of the `Request` trait and replace it with
// `Args`.
pub trait Args: Sized {
    /// Low-level Protocol Buffers type representing the action arguments.
    type Proto: protobuf::Message + Default;

    /// Converts a low-level type to a structured request arguments.
    fn from_proto(proto: Self::Proto) -> Result<Self, ParseArgsError>;
}

impl Args for () {

    type Proto = protobuf::well_known_types::Empty;

    fn from_proto(_: protobuf::well_known_types::Empty) -> Result<(), ParseArgsError> {
        Ok(())
    }
}

pub trait Item: Sized {
    /// Low-level Protocol Buffers type representing the action results.
    type Proto: protobuf::Message + Default;

    /// A name of the corresponding RDF class in GRR.
    const RDF_NAME: &'static str;

    /// Converts an action result ot its low-level representation.
    fn into_proto(self) -> Self::Proto;
}

impl Item for () {

    // This implementation is intended to be used only in tests and we do not
    // really care about the `RDF_NAME` field there. And since GRR does not have
    // any RDF wrapper for empty type (except maybe `EmptyFlowArgs`, but this is
    // semantically different), we just leave it blank.
    const RDF_NAME: &'static str = "";

    type Proto = protobuf::well_known_types::Empty;

    fn into_proto(self) -> protobuf::well_known_types::Empty {
        protobuf::well_known_types::Empty::new()
    }
}
<commit_msg>Improve code style in the `action` module.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Handlers and types for agent's actions.
//!
//! The basic functionality that a GRR agent exposes is called an _action_.
//! Actions are invoked by the server (when running a _flow_), should gather
//! requested information and report back to the server.
//!
//! In RRG each action consists of three components: a request type, a response
//! type and an action handler. Request and response types wrap lower-level
//! Protocol Buffer messages sent by and to the GRR server. Handlers accept one
//! instance of the corresponding request type and send some (zero or more)
//! instances of the corresponding response type.

mod error;

#[cfg(feature = "action-filesystems")]
#[cfg(target_os = "linux")]
pub mod filesystems;

#[cfg(feature = "action-interfaces")]
#[cfg(target_family = "unix")]
pub mod interfaces;

#[cfg(feature = "action-metadata")]
pub mod metadata;

#[cfg(feature = "action-listdir")]
pub mod listdir;

#[cfg(feature = "action-timeline")]
pub mod timeline;

#[cfg(feature = "action-network")]
pub mod network;

#[cfg(feature = "action-stat")]
pub mod stat;

#[cfg(feature = "action-insttime")]
pub mod insttime;

#[cfg(feature = "action-memsize")]
pub mod memsize;

#[cfg(feature = "action-finder")]
pub mod finder;

pub use error::{ParseArgsError, ParseArgsErrorKind, DispatchError};

/// Dispatches the given `request` to an appropriate action handler.
///
/// This method is a mapping between action names (as specified in the protocol)
/// and action handlers (implemented on the agent).
///
/// # Errors
///
/// This function will return an error if the given action is unknown (or not
/// yet implemented).
///
/// It will also error out if the action execution itself fails for whatever
/// reason.
pub fn dispatch<'s, S>(session: &mut S, request: crate::message::Request) -> Result<(), DispatchError>
where
    S: crate::session::Session,
{
    match request.action_name() {
        #[cfg(feature = "action-metadata")]
        "GetClientInfo" => {
            handle(session, request, self::metadata::handle)
        }

        #[cfg(feature = "action-listdir")]
        "ListDirectory" => {
            handle(session, request, self::listdir::handle)
        }

        #[cfg(feature = "action-timeline")]
        "Timeline" => {
            handle(session, request, self::timeline::handle)
        }

        #[cfg(feature = "action-network")]
        "ListNetworkConnections" => {
            handle(session, request, self::network::handle)
        }

        #[cfg(feature = "action-stat")]
        "GetFileStat" => {
            handle(session, request, self::stat::handle)
        }

        #[cfg(feature = "action-insttime")]
        "GetInstallDate" => {
            handle(session, request, self::insttime::handle)
        }

        #[cfg(feature = "action-interfaces")]
        #[cfg(target_family = "unix")]
        "EnumerateInterfaces" => {
            handle(session, request, self::interfaces::handle)
        }

        #[cfg(feature = "action-filesystems")]
        #[cfg(target_os = "linux")]
        "EnumerateFilesystems" => {
            handle(session, request, self::filesystems::handle)
        }

        #[cfg(feature = "action-memsize")]
        "GetMemorySize" => {
            handle(session, request, self::memsize::handle)
        }

        action_name => {
            return Err(error::UnknownActionError::new(action_name).into())
        }
    }
}

/// Handles a `request` using the specified `handler`.
///
/// This method will attempt to interpret request arguments for the specific
/// action and execute the handler with them.
///
/// # Errors
///
/// This function will return an error if the request arguments cannot be parsed
/// for the specific action or if the action execution fails.
fn handle<S, A, H>(session: &mut S, request: crate::message::Request, handler: H) -> Result<(), DispatchError>
where
    S: crate::session::Session,
    A: Args,
    H: FnOnce(&mut S, A) -> crate::session::Result<()>,
{
    let args = request.parse_args()?;
    Ok(handler(session, args)?)
}

// TODO(panhania@): Remove all usages of the `Request` trait and replace it with
// `Args`.
pub trait Args: Sized {
    /// Low-level Protocol Buffers type representing the action arguments.
    type Proto: protobuf::Message + Default;

    /// Converts a low-level type to a structured request arguments.
    fn from_proto(proto: Self::Proto) -> Result<Self, ParseArgsError>;
}

impl Args for () {

    type Proto = protobuf::well_known_types::Empty;

    fn from_proto(_: protobuf::well_known_types::Empty) -> Result<(), ParseArgsError> {
        Ok(())
    }
}

pub trait Item: Sized {
    /// Low-level Protocol Buffers type representing the action results.
    type Proto: protobuf::Message + Default;

    /// A name of the corresponding RDF class in GRR.
    const RDF_NAME: &'static str;

    /// Converts an action result ot its low-level representation.
    fn into_proto(self) -> Self::Proto;
}

impl Item for () {

    // This implementation is intended to be used only in tests and we do not
    // really care about the `RDF_NAME` field there. And since GRR does not have
    // any RDF wrapper for empty type (except maybe `EmptyFlowArgs`, but this is
    // semantically different), we just leave it blank.
    const RDF_NAME: &'static str = "";

    type Proto = protobuf::well_known_types::Empty;

    fn into_proto(self) -> protobuf::well_known_types::Empty {
        protobuf::well_known_types::Empty::new()
    }
}
<|endoftext|>


<commit_before>use super::{ApiLinks, ApiMeta};
use super::{HasPagination, HasResponse, HasValue};
use crate::method::List;
use crate::request::RegionRequest;
use crate::request::Request;
use crate::{ROOT_URL, STATIC_URL_ERROR};
use getset::{Getters, Setters};
use url::Url;

const REGIONS_SEGMENT: &str = "regions";

/// A region in DigitalOcean represents a datacenter where Droplets can be
/// deployed and images can be transferred.
///
/// Each region represents a specific datacenter in a geographic location. Some
/// geographical locations may have multiple "regions" available. This means
/// that there are multiple datacenters available within that area.
///
/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#regions)
#[derive(Deserialize, Serialize, Debug, Clone, Getters, Setters)]
pub struct Region {
    /// A human-readable string that is used as a unique identifier for each
    /// region.
    #[get = "pub"]
    name: String,
    /// The display name of the region. This will be a full name that is used
    /// in the control panel and other interfaces.
    #[get = "pub"]
    slug: String,
    /// This attribute is set to an array which contains the identifying slugs
    ///  for the sizes available in this region.
    #[get = "pub"]
    sizes: Vec<String>,
    /// This is a boolean value that represents whether new Droplets can be
    /// created in this region.
    #[get = "pub"]
    available: bool,
    /// This attribute is set to an array which contains features available in
    /// this region
    #[get = "pub"]
    features: Vec<String>,
}

impl Region {
    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-domain)
    pub fn list() -> RegionRequest<List, Vec<Region>> {
        let mut url = ROOT_URL.clone();
        url.path_segments_mut()
            .expect(STATIC_URL_ERROR)
            .push(REGIONS_SEGMENT);

        Request::new(url)
    }
}

/// Response type returned from Digital Ocean.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct RegionListResponse {
    regions: Vec<Region>,
    links: ApiLinks,
    meta: ApiMeta,
}

impl HasResponse for Vec<Region> {
    type Response = RegionListResponse;
}

impl HasPagination for RegionListResponse {
    fn next_page(&self) -> Option<Url> {
        self.links.next()
    }
}

impl HasValue for RegionListResponse {
    type Value = Vec<Region>;
    fn value(self) -> Vec<Region> {
        self.regions
    }
}
<commit_msg>Fix a link<commit_after>use super::{ApiLinks, ApiMeta};
use super::{HasPagination, HasResponse, HasValue};
use crate::method::List;
use crate::request::RegionRequest;
use crate::request::Request;
use crate::{ROOT_URL, STATIC_URL_ERROR};
use getset::{Getters, Setters};
use url::Url;

const REGIONS_SEGMENT: &str = "regions";

/// A region in DigitalOcean represents a datacenter where Droplets can be
/// deployed and images can be transferred.
///
/// Each region represents a specific datacenter in a geographic location. Some
/// geographical locations may have multiple "regions" available. This means
/// that there are multiple datacenters available within that area.
///
/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#regions)
#[derive(Deserialize, Serialize, Debug, Clone, Getters, Setters)]
pub struct Region {
    /// A human-readable string that is used as a unique identifier for each
    /// region.
    #[get = "pub"]
    name: String,
    /// The display name of the region. This will be a full name that is used
    /// in the control panel and other interfaces.
    #[get = "pub"]
    slug: String,
    /// This attribute is set to an array which contains the identifying slugs
    ///  for the sizes available in this region.
    #[get = "pub"]
    sizes: Vec<String>,
    /// This is a boolean value that represents whether new Droplets can be
    /// created in this region.
    #[get = "pub"]
    available: bool,
    /// This attribute is set to an array which contains features available in
    /// this region
    #[get = "pub"]
    features: Vec<String>,
}

impl Region {
    /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-regions)
    pub fn list() -> RegionRequest<List, Vec<Region>> {
        let mut url = ROOT_URL.clone();
        url.path_segments_mut()
            .expect(STATIC_URL_ERROR)
            .push(REGIONS_SEGMENT);

        Request::new(url)
    }
}

/// Response type returned from Digital Ocean.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct RegionListResponse {
    regions: Vec<Region>,
    links: ApiLinks,
    meta: ApiMeta,
}

impl HasResponse for Vec<Region> {
    type Response = RegionListResponse;
}

impl HasPagination for RegionListResponse {
    fn next_page(&self) -> Option<Url> {
        self.links.next()
    }
}

impl HasValue for RegionListResponse {
    type Value = Vec<Region>;
    fn value(self) -> Vec<Region> {
        self.regions
    }
}
<|endoftext|>