<commit_before>use super::{AnimeEntry, AnimeInfo, Status, SyncBackend};
use chrono::{Date, Datelike, Local, NaiveDate, TimeZone};
use config::Config;
use error::BackendError;
use input;
use reqwest::header::{Accept, Authorization, Bearer, ContentType, Headers};
use reqwest::{Client, Response};
use serde_json;
use std::io;
use std::process::{Command, ExitStatus};

const LOGIN_URL: &str =
    "https://anilist.co/api/v2/oauth/authorize?client_id=427&response_type=token";

const API_URL: &str = "https://graphql.anilist.co";

macro_rules! send_query {
    ($backend:expr, $query_str:expr, {$($vars:tt)*}, $($response_root:expr)=>*) => {{
        let vars = json!({
            $($vars)*
        });

        let json = $backend.send_json_request($query_str, &vars)?;
        json$([$response_root])*.clone()
    }};
}

pub struct Anilist {
    client: Client,
    user_id: u32,
    access_token: String,
}

impl Anilist {
    fn send_request(
        &self,
        query_str: &str,
        variables: &serde_json::Value,
    ) -> Result<Response, BackendError> {
        let body = json!({
            "query": query_str,
            "variables": variables,
        }).to_string();

        let mut headers = Headers::new();
        headers.set(ContentType::json());
        headers.set(Accept::json());
        headers.set(Authorization(Bearer {
            token: self.access_token.to_owned(),
        }));

        let response = self
            .client
            .post(API_URL)
            .headers(headers)
            .body(body)
            .send()?;

        Ok(response)
    }

    fn send_json_request(
        &self,
        query_str: &str,
        variables: &serde_json::Value,
    ) -> Result<serde_json::Value, BackendError> {
        let text = self.send_request(query_str, variables)?.text()?;
        let json: serde_json::Value = serde_json::from_str(&text)?;

        if json["errors"] != serde_json::Value::Null {
            // TODO: add error chaining
            let err = &json["errors"][0];

            let msg = err["message"].as_str().unwrap_or("unknown error");
            let status_code = err["status"].as_u64().unwrap_or(0) as u32;

            return Err(BackendError::BadResponse(status_code, msg.into()));
        }

        Ok(json)
    }

    fn request_user_id(&self) -> Result<u32, BackendError> {
        let resp = send_query!(self,
            r#"
                query {
                    Viewer {
                        id
                    }
                }
            "#,
            {},
            "data" => "Viewer" => "id"
        );

        let id = serde_json::from_value(resp)?;
        Ok(id)
    }
}

impl SyncBackend for Anilist {
    fn init(config: &mut Config) -> Result<Anilist, BackendError> {
        let access_token = match config.user.access_token {
            Some(_) => config.user.decode_access_token()?,
            None => {
                match open_url(LOGIN_URL) {
                    Ok(status) if status.success() => (),
                    result => {
                        eprintln!(
                            "failed to open URL in default browser. please open it manually: {}",
                            LOGIN_URL
                        );

                        if let Err(err) = result {
                            eprintln!("error message: {}", err);
                        }
                    }
                }

                println!("please authorize your account in the opened browser tab and paste the code below:");
                let token = input::read_line()?;
                config.user.encode_access_token(&token);

                token
            }
        };

        let mut instance = Anilist {
            client: Client::new(),
            user_id: 0,
            access_token,
        };

        instance.user_id = instance.request_user_id()?;

        Ok(instance)
    }

    fn search_by_name(&self, name: &str) -> Result<Vec<AnimeInfo>, BackendError> {
        let resp = send_query!(self,
            r#"
                query ($name: String) {
                    Page (page: 1, perPage: 30) {
                        media (search: $name, type: ANIME) {
                            id
                            title {
                                romaji
                            }
                            episodes
                        }
                    }
                }
            "#,
            { "name": name },
            "data" => "Page" => "media"
        );

        use serde_json::Value;
        let mut series = Vec::new();

        match resp {
            Value::Array(ref entries) => {
                for entry in entries {
                    let series_info: MediaData = serde_json::from_value(entry.clone())?;
                    series.push(series_info.into());
                }
            }
            _ => return Err(BackendError::InvalidJsonResponse),
        }

        Ok(series)
    }

    fn get_series_info_by_id(&self, id: u32) -> Result<AnimeInfo, BackendError> {
        let resp = send_query!(self,
            r#"
                query ($id: Int) {
                    Media (id: $id) {
                        id
                        title {
                            romaji
                        }
                        episodes
                    }
                }
            "#,
            { "id": id },
            "data" => "Media"
        );

        let info: MediaData = serde_json::from_value(resp)?;
        Ok(info.into())
    }

    fn get_list_entry(&self, info: AnimeInfo) -> Result<Option<AnimeEntry>, BackendError> {
        let resp = send_query!(self,
            r#"
                query ($id: Int, $userID: Int) {
                    MediaList(mediaId: $id, userId: $userID) {
                        progress
                        status
                        score
                        startedAt {
                            year
                            month
                            day
                        }
                        completedAt {
                            year
                            month
                            day
                        }
                    }
                }
            "#,
            { "id": info.id, "userID": self.user_id },
            "data" => "MediaList"
        );

        match resp {
            serde_json::Value::Null => Ok(None),
            _ => {
                let media_entry: MediaListEntry = serde_json::from_value(resp)?;
                Ok(Some(media_entry.into_generic_entry(info)))
            }
        }
    }

    fn update_list_entry(&self, entry: &AnimeEntry) -> Result<(), BackendError> {
        send_query!(self,
            r#"
                mutation ($mediaId: Int, $watched_eps: Int, $score: Float, $status: MediaListStatus, $start_date: FuzzyDateInput, $finish_date: FuzzyDateInput) {
                    SaveMediaListEntry (mediaId: $mediaId, progress: $watched_eps, score: $score, status: $status, startedAt: $start_date, completedAt: $finish_date) {
                        mediaId
                    }
                }
            "#,
            {
                "mediaId": entry.info.id,
                "watched_eps": entry.watched_episodes,
                "score": entry.score,
                "status": MediaStatus::from(entry.status.clone()),
                "start_date": MediaDate::from_date(entry.start_date),
                "finish_date": MediaDate::from_date(entry.finish_date),
            },
        );

        Ok(())
    }

    fn max_score(&self) -> u8 {
        // TODO: add support for other scoring types
        10
    }
}

fn open_url(url: &str) -> io::Result<ExitStatus> {
    #[cfg(target_os = "windows")]
    const LAUNCH_PROGRAM: &str = "start";
    #[cfg(target_os = "macos")]
    const LAUNCH_PROGRAM: &str = "open";
    #[cfg(target_os = "linux")]
    const LAUNCH_PROGRAM: &str = "xdg-open";

    #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
    compile_error!("support for opening URL's not implemented for this platform");

    Command::new(LAUNCH_PROGRAM).arg(url).status()
}

#[derive(Deserialize)]
struct MediaData {
    id: u32,
    title: Title,
    episodes: Option<u32>,
}

#[derive(Deserialize)]
struct Title {
    romaji: String,
}

impl Into<AnimeInfo> for MediaData {
    fn into(self) -> AnimeInfo {
        AnimeInfo {
            id: self.id,
            title: self.title.romaji,
            episodes: self.episodes,
        }
    }
}

#[derive(Deserialize)]
struct MediaListEntry {
    progress: u32,
    status: MediaStatus,
    score: f32,
    #[serde(rename = "startedAt")]
    start_date: MediaDate,
    #[serde(rename = "completedAt")]
    finish_date: MediaDate,
}

impl MediaListEntry {
    fn into_generic_entry(self, info: AnimeInfo) -> AnimeEntry {
        AnimeEntry {
            info,
            watched_episodes: self.progress,
            score: self.score,
            status: self.status.into(),
            start_date: self.start_date.into_date(),
            finish_date: self.finish_date.into_date(),
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone, PartialEq)]
enum MediaStatus {
    #[serde(rename = "CURRENT")]
    Current,
    #[serde(rename = "COMPLETED")]
    Completed,
    #[serde(rename = "PAUSED")]
    Paused,
    #[serde(rename = "DROPPED")]
    Dropped,
    #[serde(rename = "PLANNING")]
    Planning,
    #[serde(rename = "REPEATING")]
    Repeating,
}

impl Into<Status> for MediaStatus {
    fn into(self) -> Status {
        match self {
            MediaStatus::Current => Status::Watching,
            MediaStatus::Completed => Status::Completed,
            MediaStatus::Paused => Status::OnHold,
            MediaStatus::Dropped => Status::Dropped,
            MediaStatus::Planning => Status::PlanToWatch,
            MediaStatus::Repeating => Status::Rewatching,
        }
    }
}

impl From<Status> for MediaStatus {
    fn from(status: Status) -> MediaStatus {
        match status {
            Status::Watching => MediaStatus::Current,
            Status::Completed => MediaStatus::Completed,
            Status::OnHold => MediaStatus::Paused,
            Status::Dropped => MediaStatus::Dropped,
            Status::PlanToWatch => MediaStatus::Planning,
            Status::Rewatching => MediaStatus::Repeating,
        }
    }
}

#[derive(Serialize, Deserialize)]
struct MediaDate {
    year: Option<i32>,
    month: Option<u32>,
    day: Option<u32>,
}

impl MediaDate {
    fn into_date(self) -> Option<Date<Local>> {
        match (self.year, self.month, self.day) {
            (Some(year), Some(month), Some(day)) => Some(Local.ymd(year, month, day)),
            _ => None,
        }
    }

    fn from_date(date: Option<Date<Local>>) -> MediaDate {
        match date {
            Some(date) => MediaDate {
                year: Some(date.year()),
                month: Some(date.month()),
                day: Some(date.day()),
            },
            None => MediaDate {
                year: None,
                month: None,
                day: None,
            },
        }
    }
}

impl From<NaiveDate> for MediaDate {
    fn from(date: NaiveDate) -> MediaDate {
        MediaDate {
            year: Some(date.year()),
            month: Some(date.month()),
            day: Some(date.day()),
        }
    }
}
<commit_msg>Add functionality to update the AniList access token if invalid<commit_after>use super::{AnimeEntry, AnimeInfo, Status, SyncBackend};
use chrono::{Date, Datelike, Local, NaiveDate, TimeZone};
use config::Config;
use error::BackendError;
use input;
use reqwest::header::{Accept, Authorization, Bearer, ContentType, Headers};
use reqwest::{Client, Response};
use serde_json;
use std::io;
use std::process::{Command, ExitStatus};

const LOGIN_URL: &str =
    "https://anilist.co/api/v2/oauth/authorize?client_id=427&response_type=token";

const API_URL: &str = "https://graphql.anilist.co";

macro_rules! send_query {
    ($backend:expr, $query_str:expr, {$($vars:tt)*}, $($response_root:expr)=>*) => {{
        let vars = json!({
            $($vars)*
        });

        let json = $backend.send_json_request($query_str, &vars)?;
        json$([$response_root])*.clone()
    }};
}

pub struct Anilist {
    client: Client,
    user_id: u32,
    access_token: String,
}

impl Anilist {
    fn send_request(
        &self,
        query_str: &str,
        variables: &serde_json::Value,
    ) -> Result<Response, BackendError> {
        let body = json!({
            "query": query_str,
            "variables": variables,
        }).to_string();

        let mut headers = Headers::new();
        headers.set(ContentType::json());
        headers.set(Accept::json());
        headers.set(Authorization(Bearer {
            token: self.access_token.to_owned(),
        }));

        let response = self
            .client
            .post(API_URL)
            .headers(headers)
            .body(body)
            .send()?;

        Ok(response)
    }

    fn send_json_request(
        &self,
        query_str: &str,
        variables: &serde_json::Value,
    ) -> Result<serde_json::Value, BackendError> {
        let text = self.send_request(query_str, variables)?.text()?;
        let json: serde_json::Value = serde_json::from_str(&text)?;

        if json["errors"] != serde_json::Value::Null {
            // TODO: add error chaining
            let err = &json["errors"][0];

            let msg = err["message"].as_str().unwrap_or("unknown error");
            let status_code = err["status"].as_u64().unwrap_or(0) as u32;

            return Err(BackendError::BadResponse(status_code, msg.into()));
        }

        Ok(json)
    }

    fn request_user_id(&self) -> Result<u32, BackendError> {
        let resp = send_query!(self,
            r#"
                query {
                    Viewer {
                        id
                    }
                }
            "#,
            {},
            "data" => "Viewer" => "id"
        );

        let id = serde_json::from_value(resp)?;
        Ok(id)
    }

    fn prompt_for_access_token(open_url: bool) -> Result<String, BackendError> {
        if open_url {
            try_open_url(LOGIN_URL);
        }

        println!(
            "please authorize your account in the opened browser tab and paste the code below:"
        );

        let token = input::read_line()?;
        Ok(token)
    }

    fn login(&mut self, is_first_launch: bool, config: &mut Config) -> Result<(), BackendError> {
        let mut times_token_incorrect = 0;

        loop {
            match self.request_user_id() {
                Ok(user_id) => {
                    self.user_id = user_id;
                    break;
                }
                // As bad as checking for a specific error via its message is, the API does not provide
                // anything else to narrow it down to an invalid token error
                Err(BackendError::BadResponse(400, ref msg))
                    if msg.to_lowercase() == "invalid token" =>
                {
                    times_token_incorrect += 1;
                    println!("\ninvalid access token");

                    let should_open_url = !is_first_launch && times_token_incorrect <= 1;
                    let token = Anilist::prompt_for_access_token(should_open_url)?;

                    self.access_token = token;
                }
                Err(err) => return Err(err),
            }
        }

        if times_token_incorrect > 0 {
            config.user.encode_access_token(&self.access_token);
        }

        Ok(())
    }
}

impl SyncBackend for Anilist {
    fn init(config: &mut Config) -> Result<Anilist, BackendError> {
        let is_first_launch = config.user.access_token.is_none();

        let access_token = if is_first_launch {
            let token = Anilist::prompt_for_access_token(true)?;
            config.user.encode_access_token(&token);
            token
        } else {
            config.user.decode_access_token()?
        };

        let mut anilist = Anilist {
            client: Client::new(),
            user_id: 0,
            access_token,
        };

        anilist.login(is_first_launch, config)?;

        Ok(anilist)
    }

    fn search_by_name(&self, name: &str) -> Result<Vec<AnimeInfo>, BackendError> {
        let resp = send_query!(self,
            r#"
                query ($name: String) {
                    Page (page: 1, perPage: 30) {
                        media (search: $name, type: ANIME) {
                            id
                            title {
                                romaji
                            }
                            episodes
                        }
                    }
                }
            "#,
            { "name": name },
            "data" => "Page" => "media"
        );

        use serde_json::Value;
        let mut series = Vec::new();

        match resp {
            Value::Array(ref entries) => {
                for entry in entries {
                    let series_info: MediaData = serde_json::from_value(entry.clone())?;
                    series.push(series_info.into());
                }
            }
            _ => return Err(BackendError::InvalidJsonResponse),
        }

        Ok(series)
    }

    fn get_series_info_by_id(&self, id: u32) -> Result<AnimeInfo, BackendError> {
        let resp = send_query!(self,
            r#"
                query ($id: Int) {
                    Media (id: $id) {
                        id
                        title {
                            romaji
                        }
                        episodes
                    }
                }
            "#,
            { "id": id },
            "data" => "Media"
        );

        let info: MediaData = serde_json::from_value(resp)?;
        Ok(info.into())
    }

    fn get_list_entry(&self, info: AnimeInfo) -> Result<Option<AnimeEntry>, BackendError> {
        let resp = send_query!(self,
            r#"
                query ($id: Int, $userID: Int) {
                    MediaList(mediaId: $id, userId: $userID) {
                        progress
                        status
                        score
                        startedAt {
                            year
                            month
                            day
                        }
                        completedAt {
                            year
                            month
                            day
                        }
                    }
                }
            "#,
            { "id": info.id, "userID": self.user_id },
            "data" => "MediaList"
        );

        match resp {
            serde_json::Value::Null => Ok(None),
            _ => {
                let media_entry: MediaListEntry = serde_json::from_value(resp)?;
                Ok(Some(media_entry.into_generic_entry(info)))
            }
        }
    }

    fn update_list_entry(&self, entry: &AnimeEntry) -> Result<(), BackendError> {
        send_query!(self,
            r#"
                mutation ($mediaId: Int, $watched_eps: Int, $score: Float, $status: MediaListStatus, $start_date: FuzzyDateInput, $finish_date: FuzzyDateInput) {
                    SaveMediaListEntry (mediaId: $mediaId, progress: $watched_eps, score: $score, status: $status, startedAt: $start_date, completedAt: $finish_date) {
                        mediaId
                    }
                }
            "#,
            {
                "mediaId": entry.info.id,
                "watched_eps": entry.watched_episodes,
                "score": entry.score,
                "status": MediaStatus::from(entry.status.clone()),
                "start_date": MediaDate::from_date(entry.start_date),
                "finish_date": MediaDate::from_date(entry.finish_date),
            },
        );

        Ok(())
    }

    fn max_score(&self) -> u8 {
        // TODO: add support for other scoring types
        10
    }
}

fn open_url(url: &str) -> io::Result<ExitStatus> {
    #[cfg(target_os = "windows")]
    const LAUNCH_PROGRAM: &str = "start";
    #[cfg(target_os = "macos")]
    const LAUNCH_PROGRAM: &str = "open";
    #[cfg(target_os = "linux")]
    const LAUNCH_PROGRAM: &str = "xdg-open";

    #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
    compile_error!("support for opening URL's not implemented for this platform");

    Command::new(LAUNCH_PROGRAM).arg(url).status()
}

fn try_open_url(url: &str) {
    match open_url(url) {
        Ok(status) if status.success() => (),
        result => {
            eprintln!(
                "failed to open URL in default browser. please open it manually: {}",
                url
            );

            if let Err(err) = result {
                eprintln!("error message: {}", err);
            }
        }
    }
}

#[derive(Deserialize)]
struct MediaData {
    id: u32,
    title: Title,
    episodes: Option<u32>,
}

#[derive(Deserialize)]
struct Title {
    romaji: String,
}

impl Into<AnimeInfo> for MediaData {
    fn into(self) -> AnimeInfo {
        AnimeInfo {
            id: self.id,
            title: self.title.romaji,
            episodes: self.episodes,
        }
    }
}

#[derive(Deserialize)]
struct MediaListEntry {
    progress: u32,
    status: MediaStatus,
    score: f32,
    #[serde(rename = "startedAt")]
    start_date: MediaDate,
    #[serde(rename = "completedAt")]
    finish_date: MediaDate,
}

impl MediaListEntry {
    fn into_generic_entry(self, info: AnimeInfo) -> AnimeEntry {
        AnimeEntry {
            info,
            watched_episodes: self.progress,
            score: self.score,
            status: self.status.into(),
            start_date: self.start_date.into_date(),
            finish_date: self.finish_date.into_date(),
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone, PartialEq)]
enum MediaStatus {
    #[serde(rename = "CURRENT")]
    Current,
    #[serde(rename = "COMPLETED")]
    Completed,
    #[serde(rename = "PAUSED")]
    Paused,
    #[serde(rename = "DROPPED")]
    Dropped,
    #[serde(rename = "PLANNING")]
    Planning,
    #[serde(rename = "REPEATING")]
    Repeating,
}

impl Into<Status> for MediaStatus {
    fn into(self) -> Status {
        match self {
            MediaStatus::Current => Status::Watching,
            MediaStatus::Completed => Status::Completed,
            MediaStatus::Paused => Status::OnHold,
            MediaStatus::Dropped => Status::Dropped,
            MediaStatus::Planning => Status::PlanToWatch,
            MediaStatus::Repeating => Status::Rewatching,
        }
    }
}

impl From<Status> for MediaStatus {
    fn from(status: Status) -> MediaStatus {
        match status {
            Status::Watching => MediaStatus::Current,
            Status::Completed => MediaStatus::Completed,
            Status::OnHold => MediaStatus::Paused,
            Status::Dropped => MediaStatus::Dropped,
            Status::PlanToWatch => MediaStatus::Planning,
            Status::Rewatching => MediaStatus::Repeating,
        }
    }
}

#[derive(Serialize, Deserialize)]
struct MediaDate {
    year: Option<i32>,
    month: Option<u32>,
    day: Option<u32>,
}

impl MediaDate {
    fn into_date(self) -> Option<Date<Local>> {
        match (self.year, self.month, self.day) {
            (Some(year), Some(month), Some(day)) => Some(Local.ymd(year, month, day)),
            _ => None,
        }
    }

    fn from_date(date: Option<Date<Local>>) -> MediaDate {
        match date {
            Some(date) => MediaDate {
                year: Some(date.year()),
                month: Some(date.month()),
                day: Some(date.day()),
            },
            None => MediaDate {
                year: None,
                month: None,
                day: None,
            },
        }
    }
}

impl From<NaiveDate> for MediaDate {
    fn from(date: NaiveDate) -> MediaDate {
        MediaDate {
            year: Some(date.year()),
            month: Some(date.month()),
            day: Some(date.day()),
        }
    }
}
<|endoftext|>


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

use std::io::Error as IOError;

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

fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
    match e {
        &StoreErrorKind::IdNotFound  => "ID not found",
        &StoreErrorKind::OutOfMemory => "Out of Memory",
    }
}

impl Display for StoreErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", store_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct StoreError {
    err_type: StoreErrorKind,
    cause: Option<Box<Error>>,
}

impl StoreError {

    pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
        -> StoreError
    {
        StoreError {
            err_type: errtype,
            cause: cause,
        }
    }

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

}

impl Display for StoreError {

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

}

impl Error for StoreError {

    fn description(&self) -> &str {
        store_error_type_as_str(&self.err_type.clone())
    }

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

}

<commit_msg>Add error type for communicating that an entry is locked<commit_after>use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::convert::From;

use std::io::Error as IOError;

#[derive(Clone, Copy, Debug)]
pub enum StoreErrorKind {
    IdLocked,
    IdNotFound,
    OutOfMemory,
    // maybe more
}

fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
    match e {
        &StoreErrorKind::IdLocked    => "ID locked",
        &StoreErrorKind::IdNotFound  => "ID not found",
        &StoreErrorKind::OutOfMemory => "Out of Memory",
    }
}

impl Display for StoreErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", store_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct StoreError {
    err_type: StoreErrorKind,
    cause: Option<Box<Error>>,
}

impl StoreError {

    pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
        -> StoreError
    {
        StoreError {
            err_type: errtype,
            cause: cause,
        }
    }

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

}

impl Display for StoreError {

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

}

impl Error for StoreError {

    fn description(&self) -> &str {
        store_error_type_as_str(&self.err_type.clone())
    }

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

}

<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::container::{Container, Mutable};
use core::cmp::Eq;
use core::prelude::*;
use core::uint;
use core::vec;

const initial_capacity: uint = 32u; // 2^5

pub struct Deque<T> {
    priv nelts: uint,
    priv lo: uint,
    priv hi: uint,
    priv elts: ~[Option<T>]
}

impl<T> Container for Deque<T> {
    pure fn len(&self) -> uint { self.nelts }
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Mutable for Deque<T> {
    fn clear(&mut self) {
        for vec::each_mut(self.elts) |x| { *x = None }
        self.nelts = 0;
        self.lo = 0;
        self.hi = 0;
    }
}

impl<T> Deque<T> {
    static pure fn new() -> Deque<T> {
        Deque{nelts: 0, lo: 0, hi: 0,
              elts: vec::from_fn(initial_capacity, |_| None)}
    }
}

impl<T: Copy> Deque<T> {
    fn add_front(&mut self, t: T) {
        let oldlo: uint = self.lo;
        if self.lo == 0u {
            self.lo = self.elts.len() - 1u;
        } else { self.lo -= 1u; }
        if self.lo == self.hi {
            self.elts = grow(self.nelts, oldlo, self.elts);
            self.lo = self.elts.len() - 1u;
            self.hi = self.nelts;
        }
        self.elts[self.lo] = Some(t);
        self.nelts += 1u;
    }

    fn add_back(&mut self, t: T) {
        if self.lo == self.hi && self.nelts != 0u {
            self.elts = grow(self.nelts, self.lo, self.elts);
            self.lo = 0u;
            self.hi = self.nelts;
        }
        self.elts[self.hi] = Some(t);
        self.hi = (self.hi + 1u) % self.elts.len();
        self.nelts += 1u;
    }

    fn pop_front(&mut self) -> T {
        let t: T = get(self.elts, self.lo);
        self.elts[self.lo] = None;
        self.lo = (self.lo + 1u) % self.elts.len();
        self.nelts -= 1u;
        t
    }

    fn pop_back(&mut self) -> T {
        if self.hi == 0u {
            self.hi = self.elts.len() - 1u;
        } else { self.hi -= 1u; }
        let t: T = get(self.elts, self.hi);
        self.elts[self.hi] = None;
        self.nelts -= 1u;
        t
    }

    fn peek_front(&self) -> T { get(self.elts, self.lo) }

    fn peek_back(&self) -> T { get(self.elts, self.hi - 1u) }

    fn get(&self, i: int) -> T {
        let idx = (self.lo + (i as uint)) % self.elts.len();
        get(self.elts, idx)
    }
}

/// Grow is only called on full elts, so nelts is also len(elts), unlike
/// elsewhere.
fn grow<T: Copy>(nelts: uint, lo: uint, elts: &[Option<T>]) -> ~[Option<T>] {
    assert nelts == elts.len();
    let mut rv = ~[];

    let mut i = 0u;
    let nalloc = uint::next_power_of_two(nelts + 1u);
    while i < nalloc {
        if i < nelts {
            rv.push(elts[(lo + i) % nelts]);
        } else { rv.push(None); }
        i += 1u;
    }

    rv
}

fn get<T: Copy>(elts: &[Option<T>], i: uint) -> T {
    match elts[i] { Some(t) => t, _ => fail!() }
}

#[cfg(test)]
mod tests {
    use core::prelude::*;
    use super::*;

    #[test]
    fn test_simple() {
        let mut d = Deque::new();
        assert (d.len() == 0u);
        d.add_front(17);
        d.add_front(42);
        d.add_back(137);
        assert (d.len() == 3u);
        d.add_back(137);
        assert (d.len() == 4u);
        log(debug, d.peek_front());
        assert (d.peek_front() == 42);
        log(debug, d.peek_back());
        assert (d.peek_back() == 137);
        let mut i: int = d.pop_front();
        log(debug, i);
        assert (i == 42);
        i = d.pop_back();
        log(debug, i);
        assert (i == 137);
        i = d.pop_back();
        log(debug, i);
        assert (i == 137);
        i = d.pop_back();
        log(debug, i);
        assert (i == 17);
        assert (d.len() == 0u);
        d.add_back(3);
        assert (d.len() == 1u);
        d.add_front(2);
        assert (d.len() == 2u);
        d.add_back(4);
        assert (d.len() == 3u);
        d.add_front(1);
        assert (d.len() == 4u);
        log(debug, d.get(0));
        log(debug, d.get(1));
        log(debug, d.get(2));
        log(debug, d.get(3));
        assert (d.get(0) == 1);
        assert (d.get(1) == 2);
        assert (d.get(2) == 3);
        assert (d.get(3) == 4);
    }

    #[test]
    fn test_boxes() {
        let a: @int = @5;
        let b: @int = @72;
        let c: @int = @64;
        let d: @int = @175;

        let mut deq = Deque::new();
        assert (deq.len() == 0u);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert (deq.len() == 3u);
        deq.add_back(d);
        assert (deq.len() == 4u);
        assert (deq.peek_front() == b);
        assert (deq.peek_back() == d);
        assert (deq.pop_front() == b);
        assert (deq.pop_back() == d);
        assert (deq.pop_back() == c);
        assert (deq.pop_back() == a);
        assert (deq.len() == 0u);
        deq.add_back(c);
        assert (deq.len() == 1u);
        deq.add_front(b);
        assert (deq.len() == 2u);
        deq.add_back(d);
        assert (deq.len() == 3u);
        deq.add_front(a);
        assert (deq.len() == 4u);
        assert (deq.get(0) == a);
        assert (deq.get(1) == b);
        assert (deq.get(2) == c);
        assert (deq.get(3) == d);
    }

    fn test_parameterized<T: Copy Eq Durable>(a: T, b: T, c: T, d: T) {
        let mut deq = Deque::new();
        assert (deq.len() == 0u);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert (deq.len() == 3u);
        deq.add_back(d);
        assert (deq.len() == 4u);
        assert deq.peek_front() == b;
        assert deq.peek_back() == d;
        assert deq.pop_front() == b;
        assert deq.pop_back() == d;
        assert deq.pop_back() == c;
        assert deq.pop_back() == a;
        assert (deq.len() == 0u);
        deq.add_back(c);
        assert (deq.len() == 1u);
        deq.add_front(b);
        assert (deq.len() == 2u);
        deq.add_back(d);
        assert (deq.len() == 3u);
        deq.add_front(a);
        assert (deq.len() == 4u);
        assert deq.get(0) == a;
        assert deq.get(1) == b;
        assert deq.get(2) == c;
        assert deq.get(3) == d;
    }

    #[deriving_eq]
    enum Taggy { One(int), Two(int, int), Three(int, int, int), }

    #[deriving_eq]
    enum Taggypar<T> {
        Onepar(int), Twopar(int, int), Threepar(int, int, int),
    }

    #[deriving_eq]
    struct RecCy {
        x: int,
        y: int,
        t: Taggy
    }

    #[test]
    fn test_param_int() {
        test_parameterized::<int>(5, 72, 64, 175);
    }

    #[test]
    fn test_param_at_int() {
        test_parameterized::<@int>(@5, @72, @64, @175);
    }

    #[test]
    fn test_param_taggy() {
        test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3),
                                    Two(17, 42));
    }

    #[test]
    fn test_param_taggypar() {
        test_parameterized::<Taggypar<int>>(Onepar::<int>(1),
                                            Twopar::<int>(1, 2),
                                            Threepar::<int>(1, 2, 3),
                                            Twopar::<int>(17, 42));
    }

    #[test]
    fn test_param_reccy() {
        let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
        let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
        let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
        let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
        test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
    }
}
<commit_msg>deque: avoid Copy in the get function<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::container::{Container, Mutable};
use core::cmp::Eq;
use core::prelude::*;
use core::uint;
use core::vec;

const initial_capacity: uint = 32u; // 2^5

pub struct Deque<T> {
    priv nelts: uint,
    priv lo: uint,
    priv hi: uint,
    priv elts: ~[Option<T>]
}

impl<T> Container for Deque<T> {
    pure fn len(&self) -> uint { self.nelts }
    pure fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Mutable for Deque<T> {
    fn clear(&mut self) {
        for vec::each_mut(self.elts) |x| { *x = None }
        self.nelts = 0;
        self.lo = 0;
        self.hi = 0;
    }
}

impl<T> Deque<T> {
    static pure fn new() -> Deque<T> {
        Deque{nelts: 0, lo: 0, hi: 0,
              elts: vec::from_fn(initial_capacity, |_| None)}
    }
}

impl<T: Copy> Deque<T> {
    fn add_front(&mut self, t: T) {
        let oldlo: uint = self.lo;
        if self.lo == 0u {
            self.lo = self.elts.len() - 1u;
        } else { self.lo -= 1u; }
        if self.lo == self.hi {
            self.elts = grow(self.nelts, oldlo, self.elts);
            self.lo = self.elts.len() - 1u;
            self.hi = self.nelts;
        }
        self.elts[self.lo] = Some(t);
        self.nelts += 1u;
    }

    fn add_back(&mut self, t: T) {
        if self.lo == self.hi && self.nelts != 0u {
            self.elts = grow(self.nelts, self.lo, self.elts);
            self.lo = 0u;
            self.hi = self.nelts;
        }
        self.elts[self.hi] = Some(t);
        self.hi = (self.hi + 1u) % self.elts.len();
        self.nelts += 1u;
    }

    fn pop_front(&mut self) -> T {
        let t = { *get(self.elts, self.lo) };
        self.elts[self.lo] = None;
        self.lo = (self.lo + 1u) % self.elts.len();
        self.nelts -= 1u;
        t
    }

    fn pop_back(&mut self) -> T {
        if self.hi == 0u {
            self.hi = self.elts.len() - 1u;
        } else { self.hi -= 1u; }
        let t = { *get(self.elts, self.hi) };
        self.elts[self.hi] = None;
        self.nelts -= 1u;
        t
    }

    fn peek_front(&self) -> T { *get(self.elts, self.lo) }

    fn peek_back(&self) -> T { *get(self.elts, self.hi - 1u) }

    fn get(&self, i: int) -> T {
        let idx = (self.lo + (i as uint)) % self.elts.len();
        *get(self.elts, idx)
    }
}

/// Grow is only called on full elts, so nelts is also len(elts), unlike
/// elsewhere.
fn grow<T: Copy>(nelts: uint, lo: uint, elts: &[Option<T>]) -> ~[Option<T>] {
    assert nelts == elts.len();
    let mut rv = ~[];

    let mut i = 0u;
    let nalloc = uint::next_power_of_two(nelts + 1u);
    while i < nalloc {
        if i < nelts {
            rv.push(elts[(lo + i) % nelts]);
        } else { rv.push(None); }
        i += 1u;
    }

    rv
}

fn get<T>(elts: &r/[Option<T>], i: uint) -> &r/T {
    match elts[i] { Some(ref t) => t, _ => fail!() }
}

#[cfg(test)]
mod tests {
    use core::prelude::*;
    use super::*;

    #[test]
    fn test_simple() {
        let mut d = Deque::new();
        assert (d.len() == 0u);
        d.add_front(17);
        d.add_front(42);
        d.add_back(137);
        assert (d.len() == 3u);
        d.add_back(137);
        assert (d.len() == 4u);
        log(debug, d.peek_front());
        assert (d.peek_front() == 42);
        log(debug, d.peek_back());
        assert (d.peek_back() == 137);
        let mut i: int = d.pop_front();
        log(debug, i);
        assert (i == 42);
        i = d.pop_back();
        log(debug, i);
        assert (i == 137);
        i = d.pop_back();
        log(debug, i);
        assert (i == 137);
        i = d.pop_back();
        log(debug, i);
        assert (i == 17);
        assert (d.len() == 0u);
        d.add_back(3);
        assert (d.len() == 1u);
        d.add_front(2);
        assert (d.len() == 2u);
        d.add_back(4);
        assert (d.len() == 3u);
        d.add_front(1);
        assert (d.len() == 4u);
        log(debug, d.get(0));
        log(debug, d.get(1));
        log(debug, d.get(2));
        log(debug, d.get(3));
        assert (d.get(0) == 1);
        assert (d.get(1) == 2);
        assert (d.get(2) == 3);
        assert (d.get(3) == 4);
    }

    #[test]
    fn test_boxes() {
        let a: @int = @5;
        let b: @int = @72;
        let c: @int = @64;
        let d: @int = @175;

        let mut deq = Deque::new();
        assert (deq.len() == 0u);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert (deq.len() == 3u);
        deq.add_back(d);
        assert (deq.len() == 4u);
        assert (deq.peek_front() == b);
        assert (deq.peek_back() == d);
        assert (deq.pop_front() == b);
        assert (deq.pop_back() == d);
        assert (deq.pop_back() == c);
        assert (deq.pop_back() == a);
        assert (deq.len() == 0u);
        deq.add_back(c);
        assert (deq.len() == 1u);
        deq.add_front(b);
        assert (deq.len() == 2u);
        deq.add_back(d);
        assert (deq.len() == 3u);
        deq.add_front(a);
        assert (deq.len() == 4u);
        assert (deq.get(0) == a);
        assert (deq.get(1) == b);
        assert (deq.get(2) == c);
        assert (deq.get(3) == d);
    }

    fn test_parameterized<T: Copy Eq Durable>(a: T, b: T, c: T, d: T) {
        let mut deq = Deque::new();
        assert (deq.len() == 0u);
        deq.add_front(a);
        deq.add_front(b);
        deq.add_back(c);
        assert (deq.len() == 3u);
        deq.add_back(d);
        assert (deq.len() == 4u);
        assert deq.peek_front() == b;
        assert deq.peek_back() == d;
        assert deq.pop_front() == b;
        assert deq.pop_back() == d;
        assert deq.pop_back() == c;
        assert deq.pop_back() == a;
        assert (deq.len() == 0u);
        deq.add_back(c);
        assert (deq.len() == 1u);
        deq.add_front(b);
        assert (deq.len() == 2u);
        deq.add_back(d);
        assert (deq.len() == 3u);
        deq.add_front(a);
        assert (deq.len() == 4u);
        assert deq.get(0) == a;
        assert deq.get(1) == b;
        assert deq.get(2) == c;
        assert deq.get(3) == d;
    }

    #[deriving_eq]
    enum Taggy { One(int), Two(int, int), Three(int, int, int), }

    #[deriving_eq]
    enum Taggypar<T> {
        Onepar(int), Twopar(int, int), Threepar(int, int, int),
    }

    #[deriving_eq]
    struct RecCy {
        x: int,
        y: int,
        t: Taggy
    }

    #[test]
    fn test_param_int() {
        test_parameterized::<int>(5, 72, 64, 175);
    }

    #[test]
    fn test_param_at_int() {
        test_parameterized::<@int>(@5, @72, @64, @175);
    }

    #[test]
    fn test_param_taggy() {
        test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3),
                                    Two(17, 42));
    }

    #[test]
    fn test_param_taggypar() {
        test_parameterized::<Taggypar<int>>(Onepar::<int>(1),
                                            Twopar::<int>(1, 2),
                                            Threepar::<int>(1, 2, 3),
                                            Twopar::<int>(17, 42));
    }

    #[test]
    fn test_param_reccy() {
        let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
        let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
        let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
        let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
        test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
    }
}
<|endoftext|>


<commit_before>#[doc ="
Utilities that leverage libuv's `uv_timer_*` API
"];

import uv = uv;
export delayed_send, sleep, recv_timeout;

#[doc = "
Wait for timeout period then send provided value over a channel

This call returns immediately. Useful as the building block for a number
of higher-level timer functions.

Is not guaranteed to wait for exactly the specified time, but will wait
for *at least* that period of time.

# Arguments

* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
* msecs - a timeout period, in milliseconds, to wait
* ch - a channel of type T to send a `val` on
* val - a value of type T to send over the provided `ch`
"]
fn delayed_send<T: send>(hl_loop: uv::hl::high_level_loop,
                         msecs: uint, ch: comm::chan<T>, val: T) {
    task::spawn() {||
        unsafe {
            let timer_done_po = comm::port::<()>();
            let timer_done_ch = comm::chan(timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(timer);
            uv::hl::interact(hl_loop) {|loop_ptr|
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail "timer::delayed_send() start failed: "+error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail "timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            comm::recv(timer_done_po);
            // notify the caller immediately
            comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            comm::recv(timer_done_po);
        }
    };
}

#[doc = "
Blocks the current task for (at least) the specified time period.

Is not guaranteed to sleep for exactly the specified time, but will sleep
for *at least* that period of time.

# Arguments

* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
* msecs - an amount of time, in milliseconds, for the current task to block
"]
fn sleep(hl_loop: uv::hl::high_level_loop, msecs: uint) {
    let exit_po = comm::port::<()>();
    let exit_ch = comm::chan(exit_po);
    delayed_send(hl_loop, msecs, exit_ch, ());
    comm::recv(exit_po);
}

#[doc = "
Receive on a port for (up to) a specified time, then return an `option<T>`

This call will block to receive on the provided port for up to the specified
timeout. Depending on whether the provided port receives in that time period,
`recv_timeout` will return an `option<T>` representing the result.

# Arguments

* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
* msecs - an mount of time, in milliseconds, to wait to receive
* wait_port - a `comm::port<T>` to receive on

# Returns

An `option<T>` representing the outcome of the call. If the call `recv`'d on
the provided port in the allotted timeout period, then the result will be a
`some(T)`. If not, then `none` will be returned.
"]
fn recv_timeout<T: send>(hl_loop: uv::hl::high_level_loop,
                         msecs: uint, wait_po: comm::port<T>) -> option<T> {
    let timeout_po = comm::port::<()>();
    let timeout_ch = comm::chan(timeout_po);
    delayed_send(hl_loop, msecs, timeout_ch, ());
    either::either(
        {|left_val|
            log(debug, #fmt("recv_time .. left_val %?",
                           left_val));
            none
        }, {|right_val|
            some(right_val)
        }, comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
crust fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, #fmt("delayed_send_cb handle %? status %?", handle, status));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail "timer::sleep() init failed: "+error_msg;
    }
}

crust fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, #fmt("delayed_send_close_cb handle %?", handle));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        let hl_loop = uv::global_loop::get();
        sleep(hl_loop, 1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        let hl_loop = uv::global_loop::get();
        iter::repeat(200u) {||
            sleep(hl_loop, 1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = comm::port();
        let ch = comm::chan(po);
        let hl_loop = uv::global_loop::get();

        let repeat = 20u;
        let spec = {

            [(1u,  20u),
             (10u, 10u),
             (20u, 2u)]

        };

        iter::repeat(repeat) {||

            for spec.each {|spec|
                let (times, maxms) = spec;
                task::spawn {||
                    import rand::*;
                    let rng = rng();
                    iter::repeat(times) {||
                        sleep(hl_loop, rng.next() as uint % maxms);
                    }
                    comm::send(ch, ());
                }
            }
        }

        iter::repeat(repeat * spec.len()) {||
            comm::recv(po)
        }
    }

    // Because valgrind serializes multithreaded programs it can
    // make timing-sensitive tests fail in wierd ways. In these
    // next test we run them many times and expect them to pass
    // the majority of tries.

    #[test]
    #[cfg(ignore)]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        iter::repeat(times as uint) {||
            task::yield();

            let expected = rand::rng().gen_str(16u);
            let test_po = comm::port::<str>();
            let test_ch = comm::chan(test_po);

            task::spawn() {||
                delayed_send(hl_loop, 1u, test_ch, expected);
            };

            alt recv_timeout(hl_loop, 10u, test_po) {
              some(val) { assert val == expected; successes += 1; }
              _ { failures += 1; }
            };
        }

        assert successes > times / 2;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        iter::repeat(times as uint) {||
            let expected = rand::rng().gen_str(16u);
            let test_po = comm::port::<str>();
            let test_ch = comm::chan(test_po);

            task::spawn() {||
                delayed_send(hl_loop, 1000u, test_ch, expected);
            };

            let actual = alt recv_timeout(hl_loop, 1u, test_po) {
              none { successes += 1; }
              _ { failures += 1; }
            };
        }

        assert successes > times / 2;
    }
}
<commit_msg>std: Update timer for new kind rules<commit_after>#[doc ="
Utilities that leverage libuv's `uv_timer_*` API
"];

import uv = uv;
export delayed_send, sleep, recv_timeout;

#[doc = "
Wait for timeout period then send provided value over a channel

This call returns immediately. Useful as the building block for a number
of higher-level timer functions.

Is not guaranteed to wait for exactly the specified time, but will wait
for *at least* that period of time.

# Arguments

* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
* msecs - a timeout period, in milliseconds, to wait
* ch - a channel of type T to send a `val` on
* val - a value of type T to send over the provided `ch`
"]
fn delayed_send<T: copy send>(hl_loop: uv::hl::high_level_loop,
                              msecs: uint, ch: comm::chan<T>, val: T) {
    task::spawn() {||
        unsafe {
            let timer_done_po = comm::port::<()>();
            let timer_done_ch = comm::chan(timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(timer);
            uv::hl::interact(hl_loop) {|loop_ptr|
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail "timer::delayed_send() start failed: "+error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail "timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            comm::recv(timer_done_po);
            // notify the caller immediately
            comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            comm::recv(timer_done_po);
        }
    };
}

#[doc = "
Blocks the current task for (at least) the specified time period.

Is not guaranteed to sleep for exactly the specified time, but will sleep
for *at least* that period of time.

# Arguments

* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
* msecs - an amount of time, in milliseconds, for the current task to block
"]
fn sleep(hl_loop: uv::hl::high_level_loop, msecs: uint) {
    let exit_po = comm::port::<()>();
    let exit_ch = comm::chan(exit_po);
    delayed_send(hl_loop, msecs, exit_ch, ());
    comm::recv(exit_po);
}

#[doc = "
Receive on a port for (up to) a specified time, then return an `option<T>`

This call will block to receive on the provided port for up to the specified
timeout. Depending on whether the provided port receives in that time period,
`recv_timeout` will return an `option<T>` representing the result.

# Arguments

* `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
* msecs - an mount of time, in milliseconds, to wait to receive
* wait_port - a `comm::port<T>` to receive on

# Returns

An `option<T>` representing the outcome of the call. If the call `recv`'d on
the provided port in the allotted timeout period, then the result will be a
`some(T)`. If not, then `none` will be returned.
"]
fn recv_timeout<T: copy send>(hl_loop: uv::hl::high_level_loop,
                              msecs: uint,
                              wait_po: comm::port<T>) -> option<T> {
    let timeout_po = comm::port::<()>();
    let timeout_ch = comm::chan(timeout_po);
    delayed_send(hl_loop, msecs, timeout_ch, ());
    either::either(
        {|left_val|
            log(debug, #fmt("recv_time .. left_val %?",
                           left_val));
            none
        }, {|right_val|
            some(right_val)
        }, comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
crust fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, #fmt("delayed_send_cb handle %? status %?", handle, status));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail "timer::sleep() init failed: "+error_msg;
    }
}

crust fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, #fmt("delayed_send_close_cb handle %?", handle));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        let hl_loop = uv::global_loop::get();
        sleep(hl_loop, 1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        let hl_loop = uv::global_loop::get();
        iter::repeat(200u) {||
            sleep(hl_loop, 1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = comm::port();
        let ch = comm::chan(po);
        let hl_loop = uv::global_loop::get();

        let repeat = 20u;
        let spec = {

            [(1u,  20u),
             (10u, 10u),
             (20u, 2u)]

        };

        iter::repeat(repeat) {||

            for spec.each {|spec|
                let (times, maxms) = spec;
                task::spawn {||
                    import rand::*;
                    let rng = rng();
                    iter::repeat(times) {||
                        sleep(hl_loop, rng.next() as uint % maxms);
                    }
                    comm::send(ch, ());
                }
            }
        }

        iter::repeat(repeat * spec.len()) {||
            comm::recv(po)
        }
    }

    // Because valgrind serializes multithreaded programs it can
    // make timing-sensitive tests fail in wierd ways. In these
    // next test we run them many times and expect them to pass
    // the majority of tries.

    #[test]
    #[cfg(ignore)]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        iter::repeat(times as uint) {||
            task::yield();

            let expected = rand::rng().gen_str(16u);
            let test_po = comm::port::<str>();
            let test_ch = comm::chan(test_po);

            task::spawn() {||
                delayed_send(hl_loop, 1u, test_ch, expected);
            };

            alt recv_timeout(hl_loop, 10u, test_po) {
              some(val) { assert val == expected; successes += 1; }
              _ { failures += 1; }
            };
        }

        assert successes > times / 2;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let times = 100;
        let mut successes = 0;
        let mut failures = 0;
        let hl_loop = uv::global_loop::get();

        iter::repeat(times as uint) {||
            let expected = rand::rng().gen_str(16u);
            let test_po = comm::port::<str>();
            let test_ch = comm::chan(test_po);

            task::spawn() {||
                delayed_send(hl_loop, 1000u, test_ch, expected);
            };

            let actual = alt recv_timeout(hl_loop, 1u, test_po) {
              none { successes += 1; }
              _ { failures += 1; }
            };
        }

        assert successes > times / 2;
    }
}
<|endoftext|>


<commit_before>
use {
    AddColor,
    Borrowed,
    Field,
    Line,
    LineColorContext,
    Matrix2d,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanTransform,
    HasTransform,
};

/// A line context.
pub struct LineContext<'a> {
    /// Base/original transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current line.
    pub line: Field<'a, Line>,
}

impl<'a> HasTransform<'a, Matrix2d> for LineContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, LineContext<'a>, Matrix2d> for LineContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            line: Borrowed(self.line.get()),
        }
    }
}

impl<'a> View<'a> for LineContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            line: Borrowed(self.line.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            line: Borrowed(self.line.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
        }
    }
}

impl<'a> AddColor<'a, LineColorContext<'a>> for LineContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Value([r, g, b, a]),
        }
    }
}

<commit_msg>Implemented `AddRoundBorder` for `RoundBorderLineContext`<commit_after>
use {
    AddColor,
    AddRoundBorder,
    Borrowed,
    Field,
    Line,
    LineColorContext,
    Matrix2d,
    RoundBorderLineContext,
    Value,
    View,
};
use vecmath::{
    identity,
};
use internal::{
    CanTransform,
    HasTransform,
};

/// A line context.
pub struct LineContext<'a> {
    /// Base/original transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current line.
    pub line: Field<'a, Line>,
}

impl<'a> HasTransform<'a, Matrix2d> for LineContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, LineContext<'a>, Matrix2d> for LineContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            line: Borrowed(self.line.get()),
        }
    }
}

impl<'a> View<'a> for LineContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            line: Borrowed(self.line.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            line: Borrowed(self.line.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> LineContext<'a> {
        LineContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
        }
    }
}

impl<'a> AddColor<'a, LineColorContext<'a>> for LineContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> LineColorContext<'a> {
        LineColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            color: Value([r, g, b, a]),
        }
    }
}

impl<'a> AddRoundBorder<'a, RoundBorderLineContext<'a>> for LineContext<'a> {
    #[inline(always)]
    fn round_border(&'a self, radius: f64, width: f64) -> RoundBorderLineContext<'a> {
        RoundBorderLineContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            line: Borrowed(self.line.get()),
            round_border: Value([radius, width]),
        }
    }
}

<|endoftext|>


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

use std::path;

use crate::bindgen::bindings::Bindings;
use crate::bindgen::cargo::Cargo;
use crate::bindgen::config::{Braces, Config, Language, Profile, Style};
use crate::bindgen::error::Error;
use crate::bindgen::library::Library;
use crate::bindgen::parser::{self, Parse};

/// A builder for generating a bindings header.
#[derive(Debug, Clone)]
pub struct Builder {
    config: Config,
    srcs: Vec<path::PathBuf>,
    lib: Option<(path::PathBuf, Option<String>)>,
    lib_cargo: Option<Cargo>,
    std_types: bool,
    lockfile: Option<path::PathBuf>,
}

impl Builder {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Builder {
        Builder {
            config: Config::default(),
            srcs: Vec::new(),
            lib: None,
            lib_cargo: None,
            std_types: true,
            lockfile: None,
        }
    }

    #[allow(unused)]
    pub fn with_header<S: AsRef<str>>(mut self, header: S) -> Builder {
        self.config.header = Some(String::from(header.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_no_includes(mut self) -> Builder {
        self.config.no_includes = true;
        self
    }

    #[allow(unused)]
    pub fn with_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config.includes.push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config
            .sys_includes
            .push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder {
        self.config.after_includes = Some(String::from(line.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder {
        self.config.trailer = Some(String::from(trailer.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder {
        self.config.include_guard = Some(String::from(include_guard.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_pragma_once(mut self, pragma_once: bool) -> Builder {
        self.config.pragma_once = pragma_once;
        self
    }

    #[allow(unused)]
    pub fn with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder {
        self.config.autogen_warning = Some(String::from(autogen_warning.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_version(mut self, include_version: bool) -> Builder {
        self.config.include_version = include_version;
        self
    }

    #[allow(unused)]
    pub fn with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder {
        self.config.namespace = Some(String::from(namespace.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
        self.config.namespaces = Some(
            namespaces
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_braces(mut self, braces: Braces) -> Builder {
        self.config.braces = braces;
        self
    }

    #[allow(unused)]
    pub fn with_line_length(mut self, line_length: usize) -> Builder {
        self.config.line_length = line_length;
        self
    }

    #[allow(unused)]
    pub fn with_tab_width(mut self, tab_width: usize) -> Builder {
        self.config.tab_width = tab_width;
        self
    }

    #[allow(unused)]
    pub fn with_language(mut self, language: Language) -> Builder {
        self.config.language = language;
        self
    }

    #[allow(unused)]
    pub fn with_style(mut self, style: Style) -> Builder {
        self.config.style = style;
        self
    }

    #[allow(unused)]
    pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .include
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .exclude
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder {
        self.config
            .export
            .rename
            .insert(String::from(from.as_ref()), String::from(to.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder {
        self.config.export.prefix = Some(String::from(prefix.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder {
        self.config.parse.parse_deps = parse_deps;
        self
    }

    #[allow(unused)]
    pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder {
        self.config.parse.include =
            Some(include.iter().map(|x| String::from(x.as_ref())).collect());
        self
    }

    #[allow(unused)]
    pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder {
        self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder {
        self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder {
        self.config.parse.expand.all_features = expand_all_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder {
        self.config.parse.expand.default_features = expand_default_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder {
        self.config.parse.expand.features = Some(
            expand_features
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder {
        self.config.parse.expand.profile = profile;
        self
    }

    #[allow(unused)]
    pub fn with_documentation(mut self, documentation: bool) -> Builder {
        self.config.documentation = documentation;
        self
    }

    #[allow(unused)]
    pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("target_os = {}", platform),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("{} = {}", key, value),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_config(mut self, config: Config) -> Builder {
        self.config = config;
        self
    }

    #[allow(unused)]
    pub fn with_std_types(mut self, std_types: bool) -> Builder {
        self.std_types = std_types;
        self
    }

    #[allow(unused)]
    pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder {
        self.srcs.push(src.as_ref().to_owned());
        self
    }

    #[allow(unused)]
    pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None));
        self
    }

    #[allow(unused)]
    pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
        mut self,
        lib_dir: P,
        binding_lib_name: S,
    ) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((
            path::PathBuf::from(lib_dir.as_ref()),
            Some(String::from(binding_lib_name.as_ref())),
        ));
        self
    }

    #[allow(unused)]
    pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib_cargo = Some(lib);
        self
    }

    #[allow(unused)]
    pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder {
        debug_assert!(self.lockfile.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lockfile = Some(path::PathBuf::from(lockfile.as_ref()));
        self
    }

    pub fn generate(self) -> Result<Bindings, Error> {
        let mut result = Parse::new();

        if self.std_types {
            result.add_std_types();
        }

        for x in &self.srcs {
            result.extend_with(&parser::parse_src(x, &self.config)?);
        }

        if let Some((lib_dir, binding_lib_name)) = self.lib.clone() {
            let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str());

            let cargo = Cargo::load(
                &lib_dir,
                lockfile,
                binding_lib_name.as_deref(),
                self.config.parse.parse_deps,
                self.config.parse.clean,
                /* existing_metadata = */ None,
            )?;

            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        } else if let Some(cargo) = self.lib_cargo.clone() {
            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        }

        Library::new(
            self.config,
            result.constants,
            result.globals,
            result.enums,
            result.structs,
            result.unions,
            result.opaque_items,
            result.typedefs,
            result.functions,
        )
        .generate()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn with_style() {
        assert_eq!(
            Style::Tag,
            Builder::new().with_style(Style::Tag).config.style
        );
    }
}
<commit_msg>[#644] Add parse extra bindings to builder<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path;

use crate::bindgen::bindings::Bindings;
use crate::bindgen::cargo::Cargo;
use crate::bindgen::config::{Braces, Config, Language, Profile, Style};
use crate::bindgen::error::Error;
use crate::bindgen::library::Library;
use crate::bindgen::parser::{self, Parse};

/// A builder for generating a bindings header.
#[derive(Debug, Clone)]
pub struct Builder {
    config: Config,
    srcs: Vec<path::PathBuf>,
    lib: Option<(path::PathBuf, Option<String>)>,
    lib_cargo: Option<Cargo>,
    std_types: bool,
    lockfile: Option<path::PathBuf>,
}

impl Builder {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Builder {
        Builder {
            config: Config::default(),
            srcs: Vec::new(),
            lib: None,
            lib_cargo: None,
            std_types: true,
            lockfile: None,
        }
    }

    #[allow(unused)]
    pub fn with_header<S: AsRef<str>>(mut self, header: S) -> Builder {
        self.config.header = Some(String::from(header.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_no_includes(mut self) -> Builder {
        self.config.no_includes = true;
        self
    }

    #[allow(unused)]
    pub fn with_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config.includes.push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config
            .sys_includes
            .push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder {
        self.config.after_includes = Some(String::from(line.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder {
        self.config.trailer = Some(String::from(trailer.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder {
        self.config.include_guard = Some(String::from(include_guard.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_pragma_once(mut self, pragma_once: bool) -> Builder {
        self.config.pragma_once = pragma_once;
        self
    }

    #[allow(unused)]
    pub fn with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder {
        self.config.autogen_warning = Some(String::from(autogen_warning.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_version(mut self, include_version: bool) -> Builder {
        self.config.include_version = include_version;
        self
    }

    #[allow(unused)]
    pub fn with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder {
        self.config.namespace = Some(String::from(namespace.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
        self.config.namespaces = Some(
            namespaces
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_braces(mut self, braces: Braces) -> Builder {
        self.config.braces = braces;
        self
    }

    #[allow(unused)]
    pub fn with_line_length(mut self, line_length: usize) -> Builder {
        self.config.line_length = line_length;
        self
    }

    #[allow(unused)]
    pub fn with_tab_width(mut self, tab_width: usize) -> Builder {
        self.config.tab_width = tab_width;
        self
    }

    #[allow(unused)]
    pub fn with_language(mut self, language: Language) -> Builder {
        self.config.language = language;
        self
    }

    #[allow(unused)]
    pub fn with_style(mut self, style: Style) -> Builder {
        self.config.style = style;
        self
    }

    #[allow(unused)]
    pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .include
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .exclude
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder {
        self.config
            .export
            .rename
            .insert(String::from(from.as_ref()), String::from(to.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder {
        self.config.export.prefix = Some(String::from(prefix.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder {
        self.config.parse.parse_deps = parse_deps;
        self
    }

    #[allow(unused)]
    pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder {
        self.config.parse.include =
            Some(include.iter().map(|x| String::from(x.as_ref())).collect());
        self
    }

    #[allow(unused)]
    pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder {
        self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder {
        self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder {
        self.config.parse.expand.all_features = expand_all_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder {
        self.config.parse.expand.default_features = expand_default_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder {
        self.config.parse.expand.features = Some(
            expand_features
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder {
        self.config.parse.expand.profile = profile;
        self
    }

    #[allow(unused)]
    pub fn with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder {
        self.config.parse.extra_bindings = extra_bindings
            .iter()
            .map(|x| String::from(x.as_ref()))
            .collect();
        self
    }

    #[allow(unused)]
    pub fn with_documentation(mut self, documentation: bool) -> Builder {
        self.config.documentation = documentation;
        self
    }

    #[allow(unused)]
    pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("target_os = {}", platform),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("{} = {}", key, value),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_config(mut self, config: Config) -> Builder {
        self.config = config;
        self
    }

    #[allow(unused)]
    pub fn with_std_types(mut self, std_types: bool) -> Builder {
        self.std_types = std_types;
        self
    }

    #[allow(unused)]
    pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder {
        self.srcs.push(src.as_ref().to_owned());
        self
    }

    #[allow(unused)]
    pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None));
        self
    }

    #[allow(unused)]
    pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
        mut self,
        lib_dir: P,
        binding_lib_name: S,
    ) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((
            path::PathBuf::from(lib_dir.as_ref()),
            Some(String::from(binding_lib_name.as_ref())),
        ));
        self
    }

    #[allow(unused)]
    pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib_cargo = Some(lib);
        self
    }

    #[allow(unused)]
    pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder {
        debug_assert!(self.lockfile.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lockfile = Some(path::PathBuf::from(lockfile.as_ref()));
        self
    }

    pub fn generate(self) -> Result<Bindings, Error> {
        let mut result = Parse::new();

        if self.std_types {
            result.add_std_types();
        }

        for x in &self.srcs {
            result.extend_with(&parser::parse_src(x, &self.config)?);
        }

        if let Some((lib_dir, binding_lib_name)) = self.lib.clone() {
            let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str());

            let cargo = Cargo::load(
                &lib_dir,
                lockfile,
                binding_lib_name.as_deref(),
                self.config.parse.parse_deps,
                self.config.parse.clean,
                /* existing_metadata = */ None,
            )?;

            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        } else if let Some(cargo) = self.lib_cargo.clone() {
            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        }

        Library::new(
            self.config,
            result.constants,
            result.globals,
            result.enums,
            result.structs,
            result.unions,
            result.opaque_items,
            result.typedefs,
            result.functions,
        )
        .generate()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn with_style() {
        assert_eq!(
            Style::Tag,
            Builder::new().with_style(Style::Tag).config.style
        );
    }
}
<|endoftext|>


<commit_before>use diesel::RunQueryDsl;
use std::marker::PhantomData;

pub struct CreateTable<'a, Cols> {
    name: &'a str,
    columns: Cols,
}

impl<'a, Cols> CreateTable<'a, Cols> {
    pub fn new(name: &'a str, columns: Cols) -> Self {
        CreateTable {
            name: name,
            columns: columns,
        }
    }
}

impl<'a, Cols, Conn> RunQueryDsl<Conn> for CreateTable<'a, Cols> {}

pub struct Column<'a, T> {
    name: &'a str,
    type_name: &'a str,
    _marker: PhantomData<T>,
}

impl<'a, T> Column<'a, T> {
    pub fn new(name: &'a str, type_name: &'a str) -> Self {
        Column {
            name: name,
            type_name: type_name,
            _marker: PhantomData,
        }
    }

    pub fn primary_key(self) -> PrimaryKey<Self> {
        PrimaryKey(self)
    }

    pub fn not_null(self) -> NotNull<Self> {
        NotNull(self)
    }
}

pub struct PrimaryKey<Col>(Col);

impl<Col> PrimaryKey<Col> {
    pub fn auto_increment(self) -> AutoIncrement<Self> {
        AutoIncrement(self)
    }
}

pub struct AutoIncrement<Col>(Col);

pub struct NotNull<Col>(Col);

impl<'a, T> NotNull<Column<'a, T>> {
    pub fn default(self, expr: &str) -> Default<Self> {
        Default {
            column: self,
            value: expr,
        }
    }
}

pub struct Default<'a, Col> {
    column: Col,
    value: &'a str,
}

use diesel::backend::*;
#[cfg(feature = "mysql")]
use diesel::mysql::Mysql;
#[cfg(feature = "postgres")]
use diesel::pg::Pg;
use diesel::query_builder::*;
use diesel::result::QueryResult;
#[cfg(feature = "sqlite")]
use diesel::sqlite::Sqlite;

impl<'a, DB, Cols> QueryFragment<DB> for CreateTable<'a, Cols>
where
    DB: Backend,
    Cols: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_sql("CREATE TABLE ");
        out.push_identifier(self.name)?;
        out.push_sql(" (");
        self.columns.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl<'a, Cols> QueryId for CreateTable<'a, Cols> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, DB, T> QueryFragment<DB> for Column<'a, T>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_identifier(self.name)?;
        out.push_sql(" ");
        out.push_sql(self.type_name);
        Ok(())
    }
}

impl<'a, Cols> QueryId for Column<'a, Cols> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<DB, Col> QueryFragment<DB> for PrimaryKey<Col>
where
    DB: Backend,
    Col: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" PRIMARY KEY");
        Ok(())
    }
}

impl<Col> QueryId for PrimaryKey<Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

#[cfg(feature = "sqlite")]
impl<Col> QueryFragment<Sqlite> for AutoIncrement<Col>
where
    Col: QueryFragment<Sqlite>,
{
    fn walk_ast(&self, mut out: AstPass<Sqlite>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" AUTOINCREMENT");
        Ok(())
    }
}

#[cfg(feature = "mysql")]
impl<Col> QueryFragment<Mysql> for AutoIncrement<Col>
where
    Col: QueryFragment<Mysql>,
{
    fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" AUTO_INCREMENT");
        Ok(())
    }
}

impl<Col> QueryId for AutoIncrement<Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

#[cfg(feature = "postgres")]
impl<'a> QueryFragment<Pg> for AutoIncrement<PrimaryKey<Column<'a, diesel::sql_types::Integer>>> {
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_identifier((self.0).0.name)?;
        out.push_sql(" SERIAL PRIMARY KEY");
        Ok(())
    }
}

impl<DB, Col> QueryFragment<DB> for NotNull<Col>
where
    DB: Backend,
    Col: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" NOT NULL");
        Ok(())
    }
}

impl<Col> QueryId for NotNull<Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, DB, Col> QueryFragment<DB> for Default<'a, Col>
where
    DB: Backend,
    Col: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.column.walk_ast(out.reborrow())?;
        out.push_sql(" DEFAULT ");
        out.push_sql(self.value);
        Ok(())
    }
}

impl<'a, Col> QueryId for Default<'a, Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}
<commit_msg>add: add "IF NOT EXISTS"<commit_after>use diesel::RunQueryDsl;
use std::marker::PhantomData;

pub struct CreateTable<'a, Cols> {
    name: &'a str,
    columns: Cols,
}

impl<'a, Cols> CreateTable<'a, Cols> {
    pub fn new(name: &'a str, columns: Cols) -> Self {
        CreateTable {
            name: name,
            columns: columns,
        }
    }
}

impl<'a, Cols, Conn> RunQueryDsl<Conn> for CreateTable<'a, Cols> {}

pub struct Column<'a, T> {
    name: &'a str,
    type_name: &'a str,
    _marker: PhantomData<T>,
}

impl<'a, T> Column<'a, T> {
    pub fn new(name: &'a str, type_name: &'a str) -> Self {
        Column {
            name: name,
            type_name: type_name,
            _marker: PhantomData,
        }
    }

    pub fn primary_key(self) -> PrimaryKey<Self> {
        PrimaryKey(self)
    }

    pub fn not_null(self) -> NotNull<Self> {
        NotNull(self)
    }
}

pub struct PrimaryKey<Col>(Col);

impl<Col> PrimaryKey<Col> {
    pub fn auto_increment(self) -> AutoIncrement<Self> {
        AutoIncrement(self)
    }
}

pub struct AutoIncrement<Col>(Col);

pub struct NotNull<Col>(Col);

impl<'a, T> NotNull<Column<'a, T>> {
    pub fn default(self, expr: &str) -> Default<Self> {
        Default {
            column: self,
            value: expr,
        }
    }
}

pub struct Default<'a, Col> {
    column: Col,
    value: &'a str,
}

use diesel::backend::*;
#[cfg(feature = "mysql")]
use diesel::mysql::Mysql;
#[cfg(feature = "postgres")]
use diesel::pg::Pg;
use diesel::query_builder::*;
use diesel::result::QueryResult;
#[cfg(feature = "sqlite")]
use diesel::sqlite::Sqlite;

impl<'a, DB, Cols> QueryFragment<DB> for CreateTable<'a, Cols>
where
    DB: Backend,
    Cols: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_sql("CREATE TABLE IF NOT EXISTS ");
        out.push_identifier(self.name)?;
        out.push_sql(" (");
        self.columns.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl<'a, Cols> QueryId for CreateTable<'a, Cols> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, DB, T> QueryFragment<DB> for Column<'a, T>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_identifier(self.name)?;
        out.push_sql(" ");
        out.push_sql(self.type_name);
        Ok(())
    }
}

impl<'a, Cols> QueryId for Column<'a, Cols> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<DB, Col> QueryFragment<DB> for PrimaryKey<Col>
where
    DB: Backend,
    Col: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" PRIMARY KEY");
        Ok(())
    }
}

impl<Col> QueryId for PrimaryKey<Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

#[cfg(feature = "sqlite")]
impl<Col> QueryFragment<Sqlite> for AutoIncrement<Col>
where
    Col: QueryFragment<Sqlite>,
{
    fn walk_ast(&self, mut out: AstPass<Sqlite>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" AUTOINCREMENT");
        Ok(())
    }
}

#[cfg(feature = "mysql")]
impl<Col> QueryFragment<Mysql> for AutoIncrement<Col>
where
    Col: QueryFragment<Mysql>,
{
    fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" AUTO_INCREMENT");
        Ok(())
    }
}

impl<Col> QueryId for AutoIncrement<Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

#[cfg(feature = "postgres")]
impl<'a> QueryFragment<Pg> for AutoIncrement<PrimaryKey<Column<'a, diesel::sql_types::Integer>>> {
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        out.push_identifier((self.0).0.name)?;
        out.push_sql(" SERIAL PRIMARY KEY");
        Ok(())
    }
}

impl<DB, Col> QueryFragment<DB> for NotNull<Col>
where
    DB: Backend,
    Col: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.0.walk_ast(out.reborrow())?;
        out.push_sql(" NOT NULL");
        Ok(())
    }
}

impl<Col> QueryId for NotNull<Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, DB, Col> QueryFragment<DB> for Default<'a, Col>
where
    DB: Backend,
    Col: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.unsafe_to_cache_prepared();
        self.column.walk_ast(out.reborrow())?;
        out.push_sql(" DEFAULT ");
        out.push_sql(self.value);
        Ok(())
    }
}

impl<'a, Col> QueryId for Default<'a, Col> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}
<|endoftext|>