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

//! Implementation of the Bulk API

use std::collections::BTreeMap;

use hyper::status::StatusCode;

use rustc_serialize::json;
use rustc_serialize::json::{Json, ToJson};

use ::Client;
use ::do_req;
use ::error::EsError;
use ::units::Duration;

use super::common::{Options, OptionVal, VersionType};

pub struct ActionSource {
    doc:           Option<Json>,
    upsert:        Option<Json>,
    doc_as_upsert: Option<bool>,
    script:        Option<String>,
    params:        Option<Json>,
    lang:          Option<String>
}

impl ActionSource {
    pub fn new() -> ActionSource {
        ActionSource {
            doc:           None,
            upsert:        None,
            doc_as_upsert: None,
            script:        None,
            params:        None,
            lang:          None
        }
    }

    add_field!(with_doc, doc, Json);
    add_field!(with_upsert, upsert, Json);
    add_field!(with_doc_as_upsert, doc_as_upsert, bool);
    add_field!(with_script, script, String);
    add_field!(with_params, params, Json);
    add_field!(with_lang, lang, String);
}

impl ToJson for ActionSource {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        optional_add!(d, self.doc, "doc");
        optional_add!(d, self.upsert, "upsert");
        optional_add!(d, self.doc_as_upsert, "doc_as_upsert");
        optional_add!(d, self.script, "script");
        optional_add!(d, self.params, "params");
        optional_add!(d, self.lang, "lang");

        Json::Object(d)
    }
}

pub enum ActionType {
    Index,
    Create,
    Delete,
    Update
}

impl<'a> From<&'a String> for ActionType {
    fn from(from: &'a String) -> ActionType {
        if from == "index" {
            ActionType::Index
        } else if from == "create" {
            ActionType::Create
        } else if from == "delete" {
            ActionType::Delete
        } else if from == "update" {
            ActionType::Update
        } else {
            panic!("Unknown action type: {}", from)
        }
    }
}

impl ToString for ActionType {
    fn to_string(&self) -> String {
        match *self {
            ActionType::Index => "index",
            ActionType::Create => "create",
            ActionType::Delete => "delete",
            ActionType::Update => "update"
        }.to_owned()
    }
}

/// A bulk operation consists of one or more `Action`s.
pub struct Action {
    action:            ActionType,
    index:             Option<String>,
    doc_type:          Option<String>,
    id:                Option<String>,
    version:           Option<u64>,
    version_type:      Option<VersionType>,
    routing:           Option<String>,
    parent:            Option<String>,
    timestamp:         Option<String>,
    ttl:               Option<Duration>,
    retry_on_conflict: Option<u64>,
    source:            Option<Json>
}

impl Action {
    /// An index action.
    ///
    /// Takes the document to be indexed, other parameters can be set as
    /// optional on the `Action` struct returned.
    ///
    /// # Example
    ///
    /// ```
    /// use rs_es::operations::bulk::Action;
    ///
    /// let delete_action = Action::delete("doc_id");
    /// ```
    pub fn index<E: ToJson>(document: E) -> Action {
        Action {
            action:            ActionType::Index,
            index:             None,
            doc_type:          None,
            id:                None,
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            Some(document.to_json())
        }
    }

    /// Create action
    pub fn create<E: ToJson>(document: E) -> Action {
        Action {
            action:            ActionType::Create,
            index:             None,
            doc_type:          None,
            id:                None,
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            Some(document.to_json())
        }
    }

    pub fn delete<S: Into<String>>(id: S) -> Action {
        Action {
            action:            ActionType::Delete,
            index:             None,
            doc_type:          None,
            id:                Some(id.into()),
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            None
        }
    }

    pub fn update<S: Into<String>>(id: S, update: &ActionSource) -> Action {
        Action {
            action:            ActionType::Delete,
            index:             None,
            doc_type:          None,
            id:                Some(id.into()),
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            Some(update.to_json())
        }
    }

    add_field!(with_index, index, String);
    add_field!(with_doc_type, doc_type, String);
    add_field!(with_id, id, String);
    add_field!(with_version, version, u64);
    add_field!(with_version_type, version_type, VersionType);
    add_field!(with_routing, routing, String);
    add_field!(with_parent, parent, String);
    add_field!(with_timestamp, timestamp, String);
    add_field!(with_ttl, ttl, Duration);
    add_field!(with_retry_on_conflict, retry_on_conflict, u64);

    /// Add the serialized version of this action to the bulk `String`.
    fn add(&self, actstr: &mut String) -> Result<(), EsError> {
        let command_str = try!(json::encode(&self.to_json()));

        actstr.push_str(&command_str);
        actstr.push_str("\n");

        match self.source {
            Some(ref source) => {
                let payload_str = try!(json::encode(source));
                actstr.push_str(&payload_str);
                actstr.push_str("\n");
            },
            None             => ()
        }
        Ok(())
    }
}

impl ToJson for Action {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        let mut inner = BTreeMap::new();

        optional_add!(inner, self.index, "_index");
        optional_add!(inner, self.doc_type, "_type");
        optional_add!(inner, self.id, "_id");
        optional_add!(inner, self.version, "_version");
        optional_add!(inner, self.version_type, "_version_type");
        optional_add!(inner, self.routing, "_routing");
        optional_add!(inner, self.parent, "_parent");
        optional_add!(inner, self.timestamp, "_timestamp");
        optional_add!(inner, self.ttl, "_ttl");
        optional_add!(inner, self.retry_on_conflict, "_retry_on_conflict");

        d.insert(self.action.to_string(), Json::Object(inner));
        Json::Object(d)
    }
}

pub struct BulkOperation<'a, 'b> {
    client:   &'a mut Client,
    index:    Option<&'b str>,
    doc_type: Option<&'b str>,
    actions:  &'b [Action],
    options:  Options<'b>
}

impl<'a, 'b> BulkOperation<'a, 'b> {
    pub fn new(client: &'a mut Client, actions: &'b [Action]) -> BulkOperation<'a, 'b> {
        BulkOperation {
            client:   client,
            index:    None,
            doc_type: None,
            actions:  actions,
            options:  Options::new()
        }
    }

    pub fn with_index(&'b mut self, index: &'b str) -> &'b mut Self {
        self.index = Some(index);
        self
    }

    pub fn with_doc_type(&'b mut self, doc_type: &'b str) -> &'b mut Self {
        self.doc_type = Some(doc_type);
        self
    }

    add_option!(with_consistency, "consistency");
    add_option!(with_refresh, "refresh");

    fn format_url(&self) -> String {
        let mut url = String::new();
        url.push_str("/");
        match self.index {
            Some(index) => {
                url.push_str(index);
                url.push_str("/");
            },
            None        => ()
        }
        match self.doc_type {
            Some(doc_type) => {
                url.push_str(doc_type);
                url.push_str("/");
            },
            None           => ()
        }
        url.push_str("_bulk");
        url.push_str(&self.options.to_string());
        url
    }

    fn format_actions(&self) -> String {
        let mut actstr = String::new();
        for action in self.actions {
            action.add(&mut actstr).unwrap();
        }
        actstr
    }

    pub fn send(&'b mut self) -> Result<BulkResult, EsError> {
        //
        // This function does not use the standard GET/POST/DELETE functions of
        // the client, as they serve the happy path of JSON-in/JSON-out, this
        // function does send send JSON in.
        //
        // Various parts of the client are reused where it makes sense.
        //
        let full_url = {
            let url = self.format_url();
            self.client.full_url(&url)
        };
        let body = self.format_actions();

        let mut result = try!(self.client.http_client
                              .post(&full_url)
                              .body(&body)
                              .send());

        let (status_code, json_opt) = try!(do_req(&mut result));

        match status_code {
            StatusCode::Ok => Ok(BulkResult::from(&json_opt.expect("No Json payload"))),
            _              => Err(EsError::EsError(format!("Unexpected status: {}", status_code)))
        }
    }
}

/// The result of specific actions
pub struct ActionResult {
    pub action:   ActionType,
    pub index:    String,
    pub doc_type: String,
    pub version:  u64,
    pub status:   u64
}

impl<'a> From<&'a Json> for ActionResult {
    fn from(from: &'a Json) -> ActionResult {
        info!("ActionResult from: {:?}", from);

        let d = from.as_object().expect("Not a Json object");
        assert_eq!(1, d.len());
        let (key, inner) = d.iter().next().expect("No content");

        ActionResult {
            action:   ActionType::from(key),
            index:    get_json_string!(inner, "_index"),
            doc_type: get_json_string!(inner, "_type"),
            version:  get_json_u64!(inner, "_version"),
            status:   get_json_u64!(inner, "status")
        }
    }
}

/// The result of a bulk operation
pub struct BulkResult {
    pub errors: bool,
    pub items:  Vec<ActionResult>,
    pub took:   u64
}

impl<'a> From<&'a Json> for BulkResult {
    fn from(from: &'a Json) -> BulkResult {
        info!("Bulk result, result: {:?}", from);
        BulkResult {
            errors: get_json_bool!(from, "errors"),
            items:  from.find("items")
                .expect("No field called 'items'")
                .as_array()
                .expect("Field 'items' not expected array")
                .iter()
                .map(|item| {
                    ActionResult::from(item)
                })
                .collect(),
            took:   get_json_u64!(from, "took")
        }
    }
}
<commit_msg>Fix bulk update action type<commit_after>/*
 * Copyright 2015 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! Implementation of the Bulk API

use std::collections::BTreeMap;

use hyper::status::StatusCode;

use rustc_serialize::json;
use rustc_serialize::json::{Json, ToJson};

use ::Client;
use ::do_req;
use ::error::EsError;
use ::units::Duration;

use super::common::{Options, OptionVal, VersionType};

pub struct ActionSource {
    doc:           Option<Json>,
    upsert:        Option<Json>,
    doc_as_upsert: Option<bool>,
    script:        Option<String>,
    params:        Option<Json>,
    lang:          Option<String>
}

impl ActionSource {
    pub fn new() -> ActionSource {
        ActionSource {
            doc:           None,
            upsert:        None,
            doc_as_upsert: None,
            script:        None,
            params:        None,
            lang:          None
        }
    }

    add_field!(with_doc, doc, Json);
    add_field!(with_upsert, upsert, Json);
    add_field!(with_doc_as_upsert, doc_as_upsert, bool);
    add_field!(with_script, script, String);
    add_field!(with_params, params, Json);
    add_field!(with_lang, lang, String);
}

impl ToJson for ActionSource {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        optional_add!(d, self.doc, "doc");
        optional_add!(d, self.upsert, "upsert");
        optional_add!(d, self.doc_as_upsert, "doc_as_upsert");
        optional_add!(d, self.script, "script");
        optional_add!(d, self.params, "params");
        optional_add!(d, self.lang, "lang");

        Json::Object(d)
    }
}

pub enum ActionType {
    Index,
    Create,
    Delete,
    Update
}

impl<'a> From<&'a String> for ActionType {
    fn from(from: &'a String) -> ActionType {
        if from == "index" {
            ActionType::Index
        } else if from == "create" {
            ActionType::Create
        } else if from == "delete" {
            ActionType::Delete
        } else if from == "update" {
            ActionType::Update
        } else {
            panic!("Unknown action type: {}", from)
        }
    }
}

impl ToString for ActionType {
    fn to_string(&self) -> String {
        match *self {
            ActionType::Index => "index",
            ActionType::Create => "create",
            ActionType::Delete => "delete",
            ActionType::Update => "update"
        }.to_owned()
    }
}

/// A bulk operation consists of one or more `Action`s.
pub struct Action {
    action:            ActionType,
    index:             Option<String>,
    doc_type:          Option<String>,
    id:                Option<String>,
    version:           Option<u64>,
    version_type:      Option<VersionType>,
    routing:           Option<String>,
    parent:            Option<String>,
    timestamp:         Option<String>,
    ttl:               Option<Duration>,
    retry_on_conflict: Option<u64>,
    source:            Option<Json>
}

impl Action {
    /// An index action.
    ///
    /// Takes the document to be indexed, other parameters can be set as
    /// optional on the `Action` struct returned.
    ///
    /// # Example
    ///
    /// ```
    /// use rs_es::operations::bulk::Action;
    ///
    /// let delete_action = Action::delete("doc_id");
    /// ```
    pub fn index<E: ToJson>(document: E) -> Action {
        Action {
            action:            ActionType::Index,
            index:             None,
            doc_type:          None,
            id:                None,
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            Some(document.to_json())
        }
    }

    /// Create action
    pub fn create<E: ToJson>(document: E) -> Action {
        Action {
            action:            ActionType::Create,
            index:             None,
            doc_type:          None,
            id:                None,
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            Some(document.to_json())
        }
    }

    pub fn delete<S: Into<String>>(id: S) -> Action {
        Action {
            action:            ActionType::Delete,
            index:             None,
            doc_type:          None,
            id:                Some(id.into()),
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            None
        }
    }

    pub fn update<S: Into<String>>(id: S, update: &ActionSource) -> Action {
        Action {
            action:            ActionType::Update,
            index:             None,
            doc_type:          None,
            id:                Some(id.into()),
            version:           None,
            version_type:      None,
            routing:           None,
            parent:            None,
            timestamp:         None,
            ttl:               None,
            retry_on_conflict: None,
            source:            Some(update.to_json())
        }
    }

    add_field!(with_index, index, String);
    add_field!(with_doc_type, doc_type, String);
    add_field!(with_id, id, String);
    add_field!(with_version, version, u64);
    add_field!(with_version_type, version_type, VersionType);
    add_field!(with_routing, routing, String);
    add_field!(with_parent, parent, String);
    add_field!(with_timestamp, timestamp, String);
    add_field!(with_ttl, ttl, Duration);
    add_field!(with_retry_on_conflict, retry_on_conflict, u64);

    /// Add the serialized version of this action to the bulk `String`.
    fn add(&self, actstr: &mut String) -> Result<(), EsError> {
        let command_str = try!(json::encode(&self.to_json()));

        actstr.push_str(&command_str);
        actstr.push_str("\n");

        match self.source {
            Some(ref source) => {
                let payload_str = try!(json::encode(source));
                actstr.push_str(&payload_str);
                actstr.push_str("\n");
            },
            None             => ()
        }
        Ok(())
    }
}

impl ToJson for Action {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        let mut inner = BTreeMap::new();

        optional_add!(inner, self.index, "_index");
        optional_add!(inner, self.doc_type, "_type");
        optional_add!(inner, self.id, "_id");
        optional_add!(inner, self.version, "_version");
        optional_add!(inner, self.version_type, "_version_type");
        optional_add!(inner, self.routing, "_routing");
        optional_add!(inner, self.parent, "_parent");
        optional_add!(inner, self.timestamp, "_timestamp");
        optional_add!(inner, self.ttl, "_ttl");
        optional_add!(inner, self.retry_on_conflict, "_retry_on_conflict");

        d.insert(self.action.to_string(), Json::Object(inner));
        Json::Object(d)
    }
}

pub struct BulkOperation<'a, 'b> {
    client:   &'a mut Client,
    index:    Option<&'b str>,
    doc_type: Option<&'b str>,
    actions:  &'b [Action],
    options:  Options<'b>
}

impl<'a, 'b> BulkOperation<'a, 'b> {
    pub fn new(client: &'a mut Client, actions: &'b [Action]) -> BulkOperation<'a, 'b> {
        BulkOperation {
            client:   client,
            index:    None,
            doc_type: None,
            actions:  actions,
            options:  Options::new()
        }
    }

    pub fn with_index(&'b mut self, index: &'b str) -> &'b mut Self {
        self.index = Some(index);
        self
    }

    pub fn with_doc_type(&'b mut self, doc_type: &'b str) -> &'b mut Self {
        self.doc_type = Some(doc_type);
        self
    }

    add_option!(with_consistency, "consistency");
    add_option!(with_refresh, "refresh");

    fn format_url(&self) -> String {
        let mut url = String::new();
        url.push_str("/");
        match self.index {
            Some(index) => {
                url.push_str(index);
                url.push_str("/");
            },
            None        => ()
        }
        match self.doc_type {
            Some(doc_type) => {
                url.push_str(doc_type);
                url.push_str("/");
            },
            None           => ()
        }
        url.push_str("_bulk");
        url.push_str(&self.options.to_string());
        url
    }

    fn format_actions(&self) -> String {
        let mut actstr = String::new();
        for action in self.actions {
            action.add(&mut actstr).unwrap();
        }
        actstr
    }

    pub fn send(&'b mut self) -> Result<BulkResult, EsError> {
        //
        // This function does not use the standard GET/POST/DELETE functions of
        // the client, as they serve the happy path of JSON-in/JSON-out, this
        // function does send send JSON in.
        //
        // Various parts of the client are reused where it makes sense.
        //
        let full_url = {
            let url = self.format_url();
            self.client.full_url(&url)
        };
        let body = self.format_actions();

        let mut result = try!(self.client.http_client
                              .post(&full_url)
                              .body(&body)
                              .send());

        let (status_code, json_opt) = try!(do_req(&mut result));

        match status_code {
            StatusCode::Ok => Ok(BulkResult::from(&json_opt.expect("No Json payload"))),
            _              => Err(EsError::EsError(format!("Unexpected status: {}", status_code)))
        }
    }
}

/// The result of specific actions
pub struct ActionResult {
    pub action:   ActionType,
    pub index:    String,
    pub doc_type: String,
    pub version:  u64,
    pub status:   u64
}

impl<'a> From<&'a Json> for ActionResult {
    fn from(from: &'a Json) -> ActionResult {
        info!("ActionResult from: {:?}", from);

        let d = from.as_object().expect("Not a Json object");
        assert_eq!(1, d.len());
        let (key, inner) = d.iter().next().expect("No content");

        ActionResult {
            action:   ActionType::from(key),
            index:    get_json_string!(inner, "_index"),
            doc_type: get_json_string!(inner, "_type"),
            version:  get_json_u64!(inner, "_version"),
            status:   get_json_u64!(inner, "status")
        }
    }
}

/// The result of a bulk operation
pub struct BulkResult {
    pub errors: bool,
    pub items:  Vec<ActionResult>,
    pub took:   u64
}

impl<'a> From<&'a Json> for BulkResult {
    fn from(from: &'a Json) -> BulkResult {
        info!("Bulk result, result: {:?}", from);
        BulkResult {
            errors: get_json_bool!(from, "errors"),
            items:  from.find("items")
                .expect("No field called 'items'")
                .as_array()
                .expect("Field 'items' not expected array")
                .iter()
                .map(|item| {
                    ActionResult::from(item)
                })
                .collect(),
            took:   get_json_u64!(from, "took")
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::hash::BuildHasher;

use base64::{decode, encode};
use pulldown_cmark as cmark;
use tera::{to_value, try_get_value, Result as TeraResult, Value};

pub fn markdown<S: BuildHasher>(
    value: &Value,
    args: &HashMap<String, Value, S>,
) -> TeraResult<Value> {
    let s = try_get_value!("markdown", "value", String, value);
    let inline = match args.get("inline") {
        Some(val) => try_get_value!("markdown", "inline", bool, val),
        None => false,
    };

    let mut opts = cmark::Options::empty();
    opts.insert(cmark::Options::ENABLE_TABLES);
    opts.insert(cmark::Options::ENABLE_FOOTNOTES);

    let mut html = String::new();
    let parser = cmark::Parser::new_ext(&s, opts);
    cmark::html::push_html(&mut html, parser);

    if inline {
        html = html
            .trim_start_matches("
")
            // pulldown_cmark finishes a paragraph with `</p>\n`
            .trim_end_matches("
\n")
            .to_string();
    }

    Ok(to_value(&html).unwrap())
}

pub fn base64_encode<S: BuildHasher>(
    value: &Value,
    _: &HashMap<String, Value, S>,
) -> TeraResult<Value> {
    let s = try_get_value!("base64_encode", "value", String, value);
    Ok(to_value(&encode(s.as_bytes())).unwrap())
}

pub fn base64_decode<S: BuildHasher>(
    value: &Value,
    _: &HashMap<String, Value, S>,
) -> TeraResult<Value> {
    let s = try_get_value!("base64_decode", "value", String, value);
    Ok(to_value(&String::from_utf8(decode(s.as_bytes()).unwrap()).unwrap()).unwrap())
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use tera::to_value;

    use super::{base64_decode, base64_encode, markdown};

    #[test]
    fn markdown_filter() {
        let result = markdown(&to_value(&"# Hey").unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(&"
Hey
\n").unwrap());
    }

    #[test]
    fn markdown_filter_inline() {
        let mut args = HashMap::new();
        args.insert("inline".to_string(), to_value(true).unwrap());
        let result = markdown(
            &to_value(&"Using `map`, `filter`, and `fold` instead of `for`").unwrap(),
            &args,
        );
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(&"Using map, filter, and fold instead of for").unwrap());
    }

    // https://github.com/Keats/gutenberg/issues/417
    #[test]
    fn markdown_filter_inline_tables() {
        let mut args = HashMap::new();
        args.insert("inline".to_string(), to_value(true).unwrap());
        let result = markdown(
            &to_value(
                &r#"
|id|author_id|       timestamp_created|title                 |content           |
|-:|--------:|-----------------------:|:---------------------|:-----------------|
| 1|        1|2018-09-05 08:03:43.141Z|How to train your ORM |Badly written blog|
| 2|        1|2018-08-22 13:11:50.050Z|How to bake a nice pie|Badly written blog|
        "#,
            )
            .unwrap(),
            &args,
        );
        assert!(result.is_ok());
        assert!(result.unwrap().as_str().unwrap().contains("
"));
    }

    #[test]
    fn base64_encode_filter() {
        // from https://tools.ietf.org/html/rfc4648#section-10
        let tests = vec![
            ("", ""),
            ("f", "Zg=="),
            ("fo", "Zm8="),
            ("foo", "Zm9v"),
            ("foob", "Zm9vYg=="),
            ("fooba", "Zm9vYmE="),
            ("foobar", "Zm9vYmFy"),
        ];
        for (input, expected) in tests {
            let args = HashMap::new();
            let result = base64_encode(&to_value(input).unwrap(), &args);
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected).unwrap());
        }
    }

    #[test]
    fn base64_decode_filter() {
        let tests = vec![
            ("", ""),
            ("Zg==", "f"),
            ("Zm8=", "fo"),
            ("Zm9v", "foo"),
            ("Zm9vYg==", "foob"),
            ("Zm9vYmE=", "fooba"),
            ("Zm9vYmFy", "foobar"),
        ];
        for (input, expected) in tests {
            let args = HashMap::new();
            let result = base64_decode(&to_value(input).unwrap(), &args);
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected).unwrap());
        }
    }
}
<commit_msg>Enable strikethrough in markdown filter<commit_after>use std::collections::HashMap;
use std::hash::BuildHasher;

use base64::{decode, encode};
use pulldown_cmark as cmark;
use tera::{to_value, try_get_value, Result as TeraResult, Value};

pub fn markdown<S: BuildHasher>(
    value: &Value,
    args: &HashMap<String, Value, S>,
) -> TeraResult<Value> {
    let s = try_get_value!("markdown", "value", String, value);
    let inline = match args.get("inline") {
        Some(val) => try_get_value!("markdown", "inline", bool, val),
        None => false,
    };

    let mut opts = cmark::Options::empty();
    opts.insert(cmark::Options::ENABLE_TABLES);
    opts.insert(cmark::Options::ENABLE_FOOTNOTES);
    opts.insert(cmark::Options::ENABLE_STRIKETHROUGH);

    let mut html = String::new();
    let parser = cmark::Parser::new_ext(&s, opts);
    cmark::html::push_html(&mut html, parser);

    if inline {
        html = html
            .trim_start_matches("
")
            // pulldown_cmark finishes a paragraph with `</p>\n`
            .trim_end_matches("
\n")
            .to_string();
    }

    Ok(to_value(&html).unwrap())
}

pub fn base64_encode<S: BuildHasher>(
    value: &Value,
    _: &HashMap<String, Value, S>,
) -> TeraResult<Value> {
    let s = try_get_value!("base64_encode", "value", String, value);
    Ok(to_value(&encode(s.as_bytes())).unwrap())
}

pub fn base64_decode<S: BuildHasher>(
    value: &Value,
    _: &HashMap<String, Value, S>,
) -> TeraResult<Value> {
    let s = try_get_value!("base64_decode", "value", String, value);
    Ok(to_value(&String::from_utf8(decode(s.as_bytes()).unwrap()).unwrap()).unwrap())
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use tera::to_value;

    use super::{base64_decode, base64_encode, markdown};

    #[test]
    fn markdown_filter() {
        let result = markdown(&to_value(&"# Hey").unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(&"
Hey
\n").unwrap());
    }

    #[test]
    fn markdown_filter_inline() {
        let mut args = HashMap::new();
        args.insert("inline".to_string(), to_value(true).unwrap());
        let result = markdown(
            &to_value(&"Using `map`, `filter`, and `fold` instead of `for`").unwrap(),
            &args,
        );
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(&"Using map, filter, and fold instead of for").unwrap());
    }

    // https://github.com/Keats/gutenberg/issues/417
    #[test]
    fn markdown_filter_inline_tables() {
        let mut args = HashMap::new();
        args.insert("inline".to_string(), to_value(true).unwrap());
        let result = markdown(
            &to_value(
                &r#"
|id|author_id|       timestamp_created|title                 |content           |
|-:|--------:|-----------------------:|:---------------------|:-----------------|
| 1|        1|2018-09-05 08:03:43.141Z|How to train your ORM |Badly written blog|
| 2|        1|2018-08-22 13:11:50.050Z|How to bake a nice pie|Badly written blog|
        "#,
            )
            .unwrap(),
            &args,
        );
        assert!(result.is_ok());
        assert!(result.unwrap().as_str().unwrap().contains("
"));
    }

    #[test]
    fn base64_encode_filter() {
        // from https://tools.ietf.org/html/rfc4648#section-10
        let tests = vec![
            ("", ""),
            ("f", "Zg=="),
            ("fo", "Zm8="),
            ("foo", "Zm9v"),
            ("foob", "Zm9vYg=="),
            ("fooba", "Zm9vYmE="),
            ("foobar", "Zm9vYmFy"),
        ];
        for (input, expected) in tests {
            let args = HashMap::new();
            let result = base64_encode(&to_value(input).unwrap(), &args);
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected).unwrap());
        }
    }

    #[test]
    fn base64_decode_filter() {
        let tests = vec![
            ("", ""),
            ("Zg==", "f"),
            ("Zm8=", "fo"),
            ("Zm9v", "foo"),
            ("Zm9vYg==", "foob"),
            ("Zm9vYmE=", "fooba"),
            ("Zm9vYmFy", "foobar"),
        ];
        for (input, expected) in tests {
            let args = HashMap::new();
            let result = base64_decode(&to_value(input).unwrap(), &args);
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected).unwrap());
        }
    }
}
<|endoftext|>


<commit_before>use std::process;
use std::collections::HashSet;
use std::io::Write;
use std::io;

use gb::{
    Emulator,
    OpCode,
};

pub struct Debugger {
    stepping: bool,
    address_breakpoints: HashSet<u16>,
    op_breakpoints: HashSet<u8>,
    last_command: String,
}

pub fn print_cpu_status(emulator: &Emulator) {
    let cpu = &emulator.cpu;

    println!("[Z,N,H,C] = [{},{},{},{}]",
             cpu.get_Z_flag(),
             cpu.get_N_flag(),
             cpu.get_H_flag(),
             cpu.get_C_flag());

    println!("A = ${:02X}",   cpu.get_A_reg());
    println!("B = ${:02X}",   cpu.get_B_reg());
    println!("C = ${:02X}",   cpu.get_C_reg());
    println!("D = ${:02X}",   cpu.get_D_reg());
    println!("E = ${:02X}",   cpu.get_E_reg());
    println!("F = ${:02X}",   cpu.get_F_reg());
    println!("H = ${:02X}",   cpu.get_H_reg());
    println!("L = ${:02X}",   cpu.get_L_reg());
    println!("PC = ${:02X}",  cpu.get_PC());
    println!("SP = ${:02X}",  cpu.get_SP());
    println!("IF = ${:02X}",  cpu.deref_debug(0xFFFF));
    println!("IE = ${:02X}",  cpu.deref_debug(0xFF0F));
    println!("state = {:?}",  cpu.get_state());
    println!("cycles = {:?}", cpu.get_cycles());
    println!("$FF05 = {:02X}", cpu.deref_debug(0xFF05));
    println!("=== STACK ===");
    println!("${:04X} = {:02X}", cpu.get_SP(),     cpu.deref_debug(cpu.get_SP()));

    if cpu.get_SP() != 0xFFFF && cpu.get_SP() != 0xDFFF {
        println!("${:04X} = {:02X}", cpu.get_SP() + 1, cpu.deref_debug(cpu.get_SP() + 1));
    }
    println!("");
}

fn print_help() {
    println!("Help: ");
    println!("clear            -- clear breakpoints");
    println!("[l]ist           -- list breakpoints");
    println!("bo [u8]          -- breakpoint for opcode [u8]");
    println!("ba [u16]         -- breakpoint for address [u16]");
    println!("bm [u16]         -- breaks whenever the memory at [u16] is accessed");
    println!("p cpu            -- display cpu information and registers");
    println!("[p]rint [u16]    -- print memory at [u16]");
    println!("po [u16]         -- print opcode at [u16]");
    println!("[s]et [u16] [u8] -- put value [u8] at memory address [u16]");
    println!("[c]ontinue       -- continue execution");
    println!("[s]tep           -- go to next instruction");
    println!("d                -- continue execution but print cpu information");
    println!("[q]uit           -- quit application");
    println!("");
}

fn to_value(arg: &str) -> Result<u8, ()> {
    u8::from_str_radix(arg, 16).map_err(|_| ())
}

fn to_address(arg: &str) -> Result<u16, ()> {
    u16::from_str_radix(arg, 16).map_err(|_| ())
}

impl Debugger {
    pub fn new() -> Debugger {
        Debugger {
            stepping: false,
            address_breakpoints: HashSet::new(),
            op_breakpoints: HashSet::new(),
            last_command: "s".to_string(),
        }
    }

    pub fn handle_unary(&mut self, command: &str, emulator: &mut Emulator) -> Result<bool, ()> {
        match command {
            "l" | "list" => {
                for op in self.op_breakpoints.clone() {
                    println!("Breakpoint for opcode {}",
                             OpCode::from_byte(op, false).to_string());
                }
                for address in self.address_breakpoints.clone() {
                    println!("Breakpoint for address {:04X}", address);
                }
            },
            "clear" => {
                self.op_breakpoints.clear();
                self.address_breakpoints.clear();
                emulator.cpu.clear_watch();
            },
            "c" | "continue" => {
                self.stepping = false;
                emulator.cpu.set_debug(false);
                println!("Continuing.");

                return Ok(true);
            },
            "d" => {
                self.stepping = false;

                return Ok(true);
            },
            "s" | "step" => {
                return Ok(true);
            },
            "q" | "quit" => {
                println!("Quitting.");
                process::exit(0);
            },
            "h" | "help" => {
                print_help();
            },
            _ => {
                return Err(());
            },
        }

        Ok(false)
    }

    pub fn handle_binary(&mut self, command: &str, arg: &str, emulator: &mut Emulator) -> Result<bool, ()> {
        match command {
            "bo" => {
                let op = try!(to_value(arg));
                println!("Breakpoint for opcode {}",
                         OpCode::from_byte(op, false).to_string());
                self.op_breakpoints.insert(op);
            },
            "ba" => {
                let address = try!(to_address(arg));
                println!("Breakpoint for address {:04X}", address);
                self.address_breakpoints.insert(address);
            },
            "bm" => {
                let address = try!(to_address(arg));
                println!("Breakpoint for memory access at address {:04X}", address);
                emulator.cpu.watch(address);
            },
            "p" | "print" => {
                if arg == "cpu" {
                    print_cpu_status(emulator);
                } else {
                    let address = try!(to_address(arg));
                    println!("${:04X}={:02X}", address, emulator.cpu.deref_debug(address));
                }
            },
            "po" => {
                let address = try!(to_address(arg));
                println!("${:04X} = {}", address,
                         OpCode::from_byte(emulator.cpu.deref_debug(address), false).to_string());
            }
            _ => {
                return Err(());
            },
        }

        Ok(false)
    }

    pub fn handle_trinary(&mut self, command: &str, arg1: &str, arg2: &str,
                          emulator: &mut Emulator) -> Result<bool, ()> {
        match command {
            "s" | "set" => {
                let address = try!(to_address(arg1));
                let v = try!(to_value(arg2));

                println!("Setting ${:04X}={:02X}h", address, v);
                emulator.cpu.set_deref_debug(address, v);
            },
            _ => {
                return Err(());
            },
        }

        Ok(false)
    }

    fn handle(&mut self, args: Vec<&str>, emulator: &mut Emulator) -> Result<bool, ()> {
        match args.len() {
            0 => Ok(true),
            1 => self.handle_unary(args[0], emulator),
            2 => self.handle_binary(args[0], args[1], emulator),
            3 => self.handle_trinary(args[0], args[1], args[2], emulator),
            _ => Err(()),
        }
    }

    pub fn check_breakpoints(&mut self, emulator: &mut Emulator) {
        let address = emulator.cpu.get_PC();
        let op = emulator.cpu.deref_debug(address);

        if !self.address_breakpoints.contains(&address) &&
                !self.op_breakpoints.contains(&op) &&
                !emulator.cpu.address_breakpoint() {
            return;
        }

        emulator.cpu.set_debug(true);
        self.stepping = true;
        println!("Brakepoint hit! at {:04X}", emulator.cpu.get_PC());
    }

    pub fn next_instruction(&mut self, emulator: &mut Emulator) {
        if !self.stepping {
            return;
        }

        print_cpu_status(emulator);
        loop {
            let mut input = String::new();
            print!(">");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut input).unwrap();
            input = input.replace("\n", "")
                .replace("\r", "");

            if input != "" {
                self.last_command = input.clone();
            } else {
                input = self.last_command.clone();
                println!("{}", input);
            }

            let commands: Vec<&str> = input.split(' ').collect();

            match self.handle(commands, emulator) {
                Err(()) => {
                    println!("Command not understood {:?}", input);
                    print_help();
                },
                Ok(true) => {
                    break;
                },
                Ok(false) => {
                    println!("");
                },
            }
        }
    }

    pub fn breakpoint(&mut self, emulator: &mut Emulator) {
        self.stepping = true;
        emulator.cpu.set_debug(true);
        print_cpu_status(emulator);
    }
}
<commit_msg>Add watch to the debugger.<commit_after>use std::process;
use std::collections::HashSet;
use std::io::Write;
use std::io;

use gb::{
    Emulator,
    OpCode,
};

pub struct Debugger {
    stepping: bool,
    address_breakpoints: HashSet<u16>,
    op_breakpoints: HashSet<u8>,
    last_command: String,
    watches: HashSet<u16>,
}

fn print_cpu_status(emulator: &Emulator, watches: &HashSet<u16>) {
    let cpu = &emulator.cpu;

    println!("[Z,N,H,C] = [{},{},{},{}]",
             cpu.get_Z_flag(),
             cpu.get_N_flag(),
             cpu.get_H_flag(),
             cpu.get_C_flag());

    println!("A = ${:02X}",   cpu.get_A_reg());
    println!("B = ${:02X}",   cpu.get_B_reg());
    println!("C = ${:02X}",   cpu.get_C_reg());
    println!("D = ${:02X}",   cpu.get_D_reg());
    println!("E = ${:02X}",   cpu.get_E_reg());
    println!("F = ${:02X}",   cpu.get_F_reg());
    println!("H = ${:02X}",   cpu.get_H_reg());
    println!("L = ${:02X}",   cpu.get_L_reg());
    println!("PC = ${:02X}",  cpu.get_PC());
    println!("SP = ${:02X}",  cpu.get_SP());
    println!("IF = ${:02X}",  cpu.deref_debug(0xFFFF));
    println!("IE = ${:02X}",  cpu.deref_debug(0xFF0F));
    println!("state = {:?}",  cpu.get_state());
    println!("cycles = {:?}", cpu.get_cycles());
    println!("$FF05 = {:02X}", cpu.deref_debug(0xFF05));
    if watches.len() > 0 {
        println!("=== WATCH ===");
    }
    for w in watches {
        println!("${:04X} = {:02X}", w, cpu.deref_debug(*w));
    }

    println!("=== STACK ===");
    println!("${:04X} = {:02X}", cpu.get_SP(),     cpu.deref_debug(cpu.get_SP()));

    if cpu.get_SP() != 0xFFFF && cpu.get_SP() != 0xDFFF {
        println!("${:04X} = {:02X}", cpu.get_SP() + 1, cpu.deref_debug(cpu.get_SP() + 1));
    }
    println!("");
}

fn print_help() {
    println!("Help: ");
    println!("clear            -- clear breakpoints");
    println!("[l]ist           -- list breakpoints");
    println!("bo [u8]          -- breakpoint for opcode [u8]");
    println!("ba [u16]         -- breakpoint for address [u16]");
    println!("bm [u16]         -- breaks whenever the memory at [u16] is accessed");
    println!("[w]atch [u16]    -- prints address [u16] everytime the debugger breaks");
    println!("p cpu            -- display cpu information and registers");
    println!("[p]rint [u16]    -- print memory at [u16]");
    println!("po [u16]         -- print opcode at [u16]");
    println!("[s]et [u16] [u8] -- put value [u8] at memory address [u16]");
    println!("[c]ontinue       -- continue execution");
    println!("[s]tep           -- go to next instruction");
    println!("d                -- continue execution but print cpu information");
    println!("[q]uit           -- quit application");
    println!("");
}

fn to_value(arg: &str) -> Result<u8, ()> {
    u8::from_str_radix(arg, 16).map_err(|_| ())
}

fn to_address(arg: &str) -> Result<u16, ()> {
    u16::from_str_radix(arg, 16).map_err(|_| ())
}

impl Debugger {
    pub fn new() -> Debugger {
        Debugger {
            stepping: false,
            address_breakpoints: HashSet::new(),
            op_breakpoints: HashSet::new(),
            last_command: "s".to_string(),
            watches: HashSet::new(),
        }
    }

    pub fn handle_unary(&mut self, command: &str, emulator: &mut Emulator) -> Result<bool, ()> {
        match command {
            "l" | "list" => {
                for op in self.op_breakpoints.clone() {
                    println!("Breakpoint for opcode {}",
                             OpCode::from_byte(op, false).to_string());
                }
                for address in self.address_breakpoints.clone() {
                    println!("Breakpoint for address {:04X}", address);
                }
            },
            "clear" => {
                self.op_breakpoints.clear();
                self.address_breakpoints.clear();
                emulator.cpu.clear_watch();
            },
            "c" | "continue" => {
                self.stepping = false;
                emulator.cpu.set_debug(false);
                println!("Continuing.");

                return Ok(true);
            },
            "d" => {
                self.stepping = false;

                return Ok(true);
            },
            "s" | "step" => {
                return Ok(true);
            },
            "q" | "quit" => {
                println!("Quitting.");
                process::exit(0);
            },
            "h" | "help" => {
                print_help();
            },
            _ => {
                return Err(());
            },
        }

        Ok(false)
    }

    pub fn handle_binary(&mut self, command: &str, arg: &str, emulator: &mut Emulator) -> Result<bool, ()> {
        match command {
            "bo" => {
                let op = try!(to_value(arg));
                println!("Breakpoint for opcode {}",
                         OpCode::from_byte(op, false).to_string());
                self.op_breakpoints.insert(op);
            },
            "ba" => {
                let address = try!(to_address(arg));
                println!("Breakpoint for address {:04X}", address);
                self.address_breakpoints.insert(address);
            },
            "bm" => {
                let address = try!(to_address(arg));
                println!("Breakpoint for memory access at address {:04X}", address);
                emulator.cpu.watch(address);
            },
            "p" | "print" => {
                if arg == "cpu" {
                    print_cpu_status(emulator, &self.watches);
                } else {
                    let address = try!(to_address(arg));
                    println!("${:04X}={:02X}", address, emulator.cpu.deref_debug(address));
                }
            },
            "po" => {
                let address = try!(to_address(arg));
                println!("${:04X} = {}", address,
                         OpCode::from_byte(emulator.cpu.deref_debug(address), false).to_string());
            },
            "w" | "watch" => {
                let address = try!(to_address(arg));
                println!("Adding {:04X} to the watch list.", address);
                self.watches.insert(address);
            },
            _ => {
                return Err(());
            },
        }

        Ok(false)
    }

    pub fn handle_trinary(&mut self, command: &str, arg1: &str, arg2: &str,
                          emulator: &mut Emulator) -> Result<bool, ()> {
        match command {
            "s" | "set" => {
                let address = try!(to_address(arg1));
                let v = try!(to_value(arg2));

                println!("Setting ${:04X}={:02X}h", address, v);
                emulator.cpu.set_deref_debug(address, v);
            },
            _ => {
                return Err(());
            },
        }

        Ok(false)
    }

    fn handle(&mut self, args: Vec<&str>, emulator: &mut Emulator) -> Result<bool, ()> {
        match args.len() {
            0 => Ok(true),
            1 => self.handle_unary(args[0], emulator),
            2 => self.handle_binary(args[0], args[1], emulator),
            3 => self.handle_trinary(args[0], args[1], args[2], emulator),
            _ => Err(()),
        }
    }

    pub fn check_breakpoints(&mut self, emulator: &mut Emulator) {
        let address = emulator.cpu.get_PC();
        let op = emulator.cpu.deref_debug(address);

        if !self.address_breakpoints.contains(&address) &&
                !self.op_breakpoints.contains(&op) &&
                !emulator.cpu.address_breakpoint() {
            return;
        }

        emulator.cpu.set_debug(true);
        self.stepping = true;
        println!("Brakepoint hit! at {:04X}", emulator.cpu.get_PC());
    }

    pub fn next_instruction(&mut self, emulator: &mut Emulator) {
        if !self.stepping {
            return;
        }

        print_cpu_status(emulator, &self.watches);
        loop {
            let mut input = String::new();
            print!(">");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut input).unwrap();
            input = input.replace("\n", "")
                .replace("\r", "");

            if input != "" {
                self.last_command = input.clone();
            } else {
                input = self.last_command.clone();
                println!("{}", input);
            }

            let commands: Vec<&str> = input.split(' ').collect();

            match self.handle(commands, emulator) {
                Err(()) => {
                    println!("Command not understood {:?}", input);
                    print_help();
                },
                Ok(true) => {
                    break;
                },
                Ok(false) => {
                    println!("");
                },
            }
        }
    }

    pub fn breakpoint(&mut self, emulator: &mut Emulator) {
        self.stepping = true;
        emulator.cpu.set_debug(true);
        print_cpu_status(emulator, &self.watches);
    }
}
<|endoftext|>


<commit_before>use self::code_from_cargo::Kind;
use crate::errors::*;
use std::path::PathBuf;
use url::Url;

const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";

pub fn registry_path() -> Result<PathBuf> {
    Ok(index_path()?.join(short_name(&registry_url()?)))
}

fn registry_url() -> Result<Url> {
    // TODO parse cargo config
    Ok(Url::parse(CRATES_IO_INDEX).map_err(|_| "registry url is wrong")?)
}

fn index_path() -> Result<PathBuf> {
    // TODO parse cargo config
    Ok(dirs::home_dir()
        .chain_err(|| ErrorKind::ReadHomeDirFailure)?
        .join(".cargo")
        .join("registry")
        .join("index"))
}

fn short_name(registry: &Url) -> String {
    #![allow(deprecated)]
    use std::hash::{Hash, Hasher, SipHasher};

    let mut hasher = SipHasher::new_with_keys(0, 0);
    Kind::Registry.hash(&mut hasher);
    registry.as_str().hash(&mut hasher);
    let hash = hex::encode(hasher.finish().to_le_bytes());

    let ident = registry.host_str().unwrap_or("").to_string();

    format!("{}-{}", ident, hash)
}

mod code_from_cargo {
    #![allow(dead_code)]

    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub enum Kind {
        Git(GitReference),
        Path,
        Registry,
        LocalRegistry,
        Directory,
    }

    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub enum GitReference {
        Tag(String),
        Branch(String),
        Rev(String),
    }
}
<commit_msg>add unit test for 'short_name'; add cargo code url<commit_after>use self::code_from_cargo::Kind;
use crate::errors::*;
use std::path::PathBuf;
use url::Url;

const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";

pub fn registry_path() -> Result<PathBuf> {
    Ok(index_path()?.join(short_name(&registry_url()?)))
}

fn registry_url() -> Result<Url> {
    // TODO parse cargo config
    Ok(Url::parse(CRATES_IO_INDEX).map_err(|_| "registry url is wrong")?)
}

fn index_path() -> Result<PathBuf> {
    // TODO parse cargo config
    Ok(dirs::home_dir()
        .chain_err(|| ErrorKind::ReadHomeDirFailure)?
        .join(".cargo")
        .join("registry")
        .join("index"))
}

fn short_name(registry: &Url) -> String {
    // ref: https://github.com/rust-lang/cargo/blob/4c1fa54d10f58d69ac9ff55be68e1b1c25ecb816/src/cargo/sources/registry/mod.rs#L386-L390
    #![allow(deprecated)]
    use std::hash::{Hash, Hasher, SipHasher};

    let mut hasher = SipHasher::new_with_keys(0, 0);
    Kind::Registry.hash(&mut hasher);
    registry.as_str().hash(&mut hasher);
    let hash = hex::encode(hasher.finish().to_le_bytes());

    let ident = registry.host_str().unwrap_or("").to_string();

    format!("{}-{}", ident, hash)
}

#[test]
fn test_short_name() {
    fn test_helper(url: &str, name: &str) {
        let url = Url::parse(url).unwrap();
        assert_eq!(short_name(&url), name);
    }
    test_helper(
        "https://github.com/rust-lang/crates.io-index",
        "github.com-1ecc6299db9ec823",
    );
}

mod code_from_cargo {
    #![allow(dead_code)]

    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub enum Kind {
        Git(GitReference),
        Path,
        Registry,
        LocalRegistry,
        Directory,
    }

    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub enum GitReference {
        Tag(String),
        Branch(String),
        Rev(String),
    }
}
<|endoftext|>


<commit_before>use action::Action;
use config;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::Message;
use std::cell::RefCell;
use std::rc::Rc;
use state::State;

#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = ".context.uuid";
pub const CONTEXT_NAME: &'static str = ".context.name";

#[derive(Clone)]
pub struct MessageAction {
    pub sender: Rc<RefCell<Box<ResponseSender<Response>>>>,
    pub action: config::action::MessageAction
}

#[derive(Debug)]
pub struct MessageResponse {
    message: Message,
}

impl MessageResponse {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn execute(&self, _state: &State, _context: &BaseContext) {
        trace!("MessageAction: executed");
        let mut message = Message::from(&self.action);
        message.insert(".context.uuid", &_context.uuid().to_hyphenated_string());
        message.insert(".context.len", &_state.messages().len().to_string());
        if let Some(name) = _context.name() {
            message.insert(".context.name", name);
        }
        let response = MessageResponse {
            message: message,
        };
        self.sender.borrow_mut().send_response(Response::Message(response));
    }
}
<commit_msg>action::MessageAction: remove derive(Clone)<commit_after>use action::Action;
use config;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::Message;
use std::cell::RefCell;
use std::rc::Rc;
use state::State;

#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = ".context.uuid";
pub const CONTEXT_NAME: &'static str = ".context.name";

pub struct MessageAction {
    pub sender: Rc<RefCell<Box<ResponseSender<Response>>>>,
    pub action: config::action::MessageAction
}

#[derive(Debug)]
pub struct MessageResponse {
    message: Message,
}

impl MessageResponse {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn execute(&self, _state: &State, _context: &BaseContext) {
        trace!("MessageAction: executed");
        let mut message = Message::from(&self.action);
        message.insert(".context.uuid", &_context.uuid().to_hyphenated_string());
        message.insert(".context.len", &_state.messages().len().to_string());
        if let Some(name) = _context.name() {
            message.insert(".context.name", name);
        }
        let response = MessageResponse {
            message: message,
        };
        self.sender.borrow_mut().send_response(Response::Message(response));
    }
}
<|endoftext|>


<commit_before>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) |
            Err(Ignored(s)) |
            Err(Mismatch(s)) |
            Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(env: &Env, type_id: library::TypeId, nullable: Nullable, ref_mode: RefMode) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Short => ok("libc::c_short"),   //depends of target system
                UShort => ok("libc::c_ushort"), //depends of target system
                Long => ok("libc::c_long"),     //depends of target system
                ULong => ok("libc::c_ulong"),   //depends of target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => if ref_mode.is_ref() { ok("str") } else { ok("String") },
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    } else {
                        ok("std::path::PathBuf")
                    }
                }
                Type if env.namespaces.glib_ns_id == library::MAIN_NAMESPACE => ok("types::Type"),
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        }
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode)
                .map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() { ok("VariantTy") } else { ok("VariantType") }
        }
        Enumeration(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            }
            else {
                Ok(name)
            }
        }
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) |
                    Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE
        && !implemented_in_main_namespace(&env.library, type_id) {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| format!("{}::{}",
            env.namespaces[type_id.ns_id].higher_crate_name, s));
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => rust_type = rust_type.map_any(|s| format!("&{}", s)),
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer
                | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
            Fundamental(library::Fundamental::Short) |
            Fundamental(library::Fundamental::UShort) |
            Fundamental(library::Fundamental::Long) |
            Fundamental(library::Fundamental::ULong) |
            Fundamental(library::Fundamental::Filename) |
            Alias(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Enumeration(..) |
            Interface(..) => rust_type(env, type_id),
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(env: &Env, type_id: library::TypeId,
                           direction: library::ParameterDirection, nullable: Nullable,
                           ref_mode: RefMode) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                match direction {
                    library::ParameterDirection::In |
                        library::ParameterDirection::Return => rust_type,
                    _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
                }
            } else {
                rust_type.map_any(|s| format_parameter(s, direction))
            }
        }

        Alias(ref alias) => {
            rust_type.and_then(|s| {
                parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                    .map_any(|_| s)
            })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) |
            Union(..) |
            Bitfield(..) => rust_type.map_any(|s| format_parameter(s, direction)),

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) |
            Interface (..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Out |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) |
            SList(..) |
            CArray(..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

//TODO: remove
fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    match &*type_id.full_name(library) {
        "GLib.Error" => return true,
        _ => (),
    }
    if library.namespace(library::MAIN_NAMESPACE).name != "Gtk" {
        return false;
    }
    match &*type_id.full_name(library) {
        _ => false,
    }
}
<commit_msg>Add support for gsize/gssize by using usize/isize<commit_after>use std::result;

use analysis::ref_mode::RefMode;
use env::Env;
use library::{self, Nullable};
use super::conversion_type::ConversionType;
use traits::*;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeError {
    Ignored(String),
    Mismatch(String),
    Unimplemented(String),
}

pub type Result = result::Result<String, TypeError>;

fn into_inner(res: Result) -> String {
    use self::TypeError::*;
    match res {
        Ok(s) |
            Err(Ignored(s)) |
            Err(Mismatch(s)) |
            Err(Unimplemented(s)) => s,
    }
}

impl IntoString for Result {
    fn into_string(self) -> String {
        use self::TypeError::*;
        match self {
            Ok(s) => s,
            Err(Ignored(s)) => format!("/*Ignored*/{}", s),
            Err(Mismatch(s)) => format!("/*Metadata mismatch*/{}", s),
            Err(Unimplemented(s)) => format!("/*Unimplemented*/{}", s),
        }
    }
}

impl MapAny<String> for Result {
    fn map_any<F: FnOnce(String) -> String>(self, op: F) -> Result {
        use self::TypeError::*;
        match self {
            Ok(s) => Ok(op(s)),
            Err(Ignored(s)) => Err(Ignored(op(s))),
            Err(Mismatch(s)) => Err(Mismatch(op(s))),
            Err(Unimplemented(s)) => Err(Unimplemented(op(s))),
        }
    }
}

pub fn rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::None)
}

pub fn bounds_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    rust_type_full(env, type_id, Nullable(false), RefMode::ByRefFake)
}

fn rust_type_full(env: &Env, type_id: library::TypeId, nullable: Nullable, ref_mode: RefMode) -> Result {
    use library::Type::*;
    use library::Fundamental::*;
    let ok = |s: &str| Ok(s.into());
    let err = |s: &str| Err(TypeError::Unimplemented(s.into()));
    let mut skip_option = false;
    let type_ = env.library.type_(type_id);
    let mut rust_type = match *type_ {
        Fundamental(fund) => {
            match fund {
                None => err("()"),
                Boolean => ok("bool"),
                Int8 => ok("i8"),
                UInt8 => ok("u8"),
                Int16 => ok("i16"),
                UInt16 => ok("u16"),
                Int32 => ok("i32"),
                UInt32 => ok("u32"),
                Int64 => ok("i64"),
                UInt64 => ok("u64"),

                Int => ok("i32"),      //maybe dependent on target system
                UInt => ok("u32"),     //maybe dependent on target system

                Short => ok("libc::c_short"),   //depends of target system
                UShort => ok("libc::c_ushort"), //depends of target system
                Long => ok("libc::c_long"),     //depends of target system
                ULong => ok("libc::c_ulong"),   //depends of target system

                Size => ok("usize"),     //depends of target system
                SSize => ok("isize"),    //depends of target system

                Float => ok("f32"),
                Double => ok("f64"),

                UniChar => ok("char"),
                Utf8 => if ref_mode.is_ref() { ok("str") } else { ok("String") },
                Filename => {
                    if ref_mode.is_ref() {
                        ok("std::path::Path")
                    } else {
                        ok("std::path::PathBuf")
                    }
                }
                Type if env.namespaces.glib_ns_id == library::MAIN_NAMESPACE => ok("types::Type"),
                Type => ok("glib::types::Type"),
                Unsupported => err("Unsupported"),
                _ => err(&format!("Fundamental: {:?}", fund)),
            }
        }
        Alias(ref alias) => {
            rust_type_full(env, alias.typ, nullable, ref_mode)
                .map_any(|_| alias.name.clone())
        }
        Record(library::Record { ref c_type, .. }) if c_type == "GVariantType" => {
            if ref_mode.is_ref() { ok("VariantTy") } else { ok("VariantType") }
        }
        Enumeration(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Interface(..) => {
            let name = type_.get_name().to_owned();
            if env.type_status(&type_id.full_name(&env.library)).ignored() {
                Err(TypeError::Ignored(name))
            }
            else {
                Ok(name)
            }
        }
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid)
            if ConversionType::of(&env.library, inner_tid) == ConversionType::Pointer => {
            skip_option = true;
            let inner_ref_mode = match *env.library.type_(inner_tid) {
                Class(..) |
                    Interface(..) => RefMode::None,
                _ => ref_mode,
            };
            rust_type_full(env, inner_tid, Nullable(false), inner_ref_mode)
                .map_any(|s| if ref_mode.is_ref() {
                    format!("[{}]", s)
                } else {
                    format!("Vec<{}>", s)
                })
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    };

    if type_id.ns_id != library::MAIN_NAMESPACE && type_id.ns_id != library::INTERNAL_NAMESPACE
        && !implemented_in_main_namespace(&env.library, type_id) {
        if env.type_status(&type_id.full_name(&env.library)).ignored() {
            rust_type = Err(TypeError::Ignored(into_inner(rust_type)));
        }
        rust_type = rust_type.map_any(|s| format!("{}::{}",
            env.namespaces[type_id.ns_id].higher_crate_name, s));
    }

    match ref_mode {
        RefMode::None | RefMode::ByRefFake => {}
        RefMode::ByRef | RefMode::ByRefImmut => rust_type = rust_type.map_any(|s| format!("&{}", s)),
        RefMode::ByRefMut => rust_type = rust_type.map_any(|s| format!("&mut {}", s)),
    }
    if *nullable && !skip_option {
        match ConversionType::of(&env.library, type_id) {
            ConversionType::Pointer
                | ConversionType::Scalar => {
                rust_type = rust_type.map_any(|s| format!("Option<{}>", s))
            }
            _ => (),
        }
    }

    rust_type
}

pub fn used_rust_type(env: &Env, type_id: library::TypeId) -> Result {
    use library::Type::*;
    match *env.library.type_(type_id) {
        Fundamental(library::Fundamental::Type) |
            Fundamental(library::Fundamental::Short) |
            Fundamental(library::Fundamental::UShort) |
            Fundamental(library::Fundamental::Long) |
            Fundamental(library::Fundamental::ULong) |
            Fundamental(library::Fundamental::Filename) |
            Alias(..) |
            Bitfield(..) |
            Record(..) |
            Union(..) |
            Class(..) |
            Enumeration(..) |
            Interface(..) => rust_type(env, type_id),
        List(inner_tid) |
            SList(inner_tid) |
            CArray(inner_tid) => used_rust_type(env, inner_tid),
        _ => Err(TypeError::Ignored("Don't need use".to_owned())),
    }
}

pub fn parameter_rust_type(env: &Env, type_id: library::TypeId,
                           direction: library::ParameterDirection, nullable: Nullable,
                           ref_mode: RefMode) -> Result {
    use library::Type::*;
    let type_ = env.library.type_(type_id);
    let rust_type = rust_type_full(env, type_id, nullable, ref_mode);
    match *type_ {
        Fundamental(fund) => {
            if fund == library::Fundamental::Utf8 || fund == library::Fundamental::Filename {
                match direction {
                    library::ParameterDirection::In |
                        library::ParameterDirection::Return => rust_type,
                    _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
                }
            } else {
                rust_type.map_any(|s| format_parameter(s, direction))
            }
        }

        Alias(ref alias) => {
            rust_type.and_then(|s| {
                parameter_rust_type(env, alias.typ, direction, nullable, ref_mode)
                    .map_any(|_| s)
            })
                .map_any(|s| format_parameter(s, direction))
        }

        Enumeration(..) |
            Union(..) |
            Bitfield(..) => rust_type.map_any(|s| format_parameter(s, direction)),

        Record(..) => {
            if direction == library::ParameterDirection::InOut {
                Err(TypeError::Unimplemented(into_inner(rust_type)))
            } else {
                rust_type
            }
        }

        Class(..) |
            Interface (..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Out |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }

        List(..) |
            SList(..) |
            CArray(..) => {
            match direction {
                library::ParameterDirection::In |
                    library::ParameterDirection::Return => rust_type,
                _ => Err(TypeError::Unimplemented(into_inner(rust_type))),
            }
        }
        _ => Err(TypeError::Unimplemented(type_.get_name().to_owned())),
    }
}

#[inline]
fn format_parameter(rust_type: String, direction: library::ParameterDirection) -> String {
    if direction.is_out() {
        format!("&mut {}", rust_type)
    } else {
        rust_type
    }
}

//TODO: remove
fn implemented_in_main_namespace(library: &library::Library, type_id: library::TypeId) -> bool {
    match &*type_id.full_name(library) {
        "GLib.Error" => return true,
        _ => (),
    }
    if library.namespace(library::MAIN_NAMESPACE).name != "Gtk" {
        return false;
    }
    match &*type_id.full_name(library) {
        _ => false,
    }
}
<|endoftext|>


<commit_before>#![feature(no_std,lang_items,asm,core,alloc,collections,step_by,start)]
#![no_std]

#![crate_type="staticlib"]
#![crate_name="rustcode"]

#[macro_use]
extern crate core;
extern crate rlibc;

use core::fmt;

#[lang="start"]
#[start]
#[no_mangle]
pub fn kernel_main() {

}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
pub extern fn rust_begin_unwind(args: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
//    use core::fmt::Write;
//    log!("\r\nPanic at {}:{}: ", file, line);
//    let _ = console::Console.write_fmt(args);
    loop {};
}
<commit_msg>Minor changes to lib.rs<commit_after>#![feature(no_std,lang_items,core)]
#![no_std]

#![crate_type = "staticlib"]
#![crate_name = "rustcode"]

#[macro_use]
extern crate core;
extern crate rlibc;

use core::fmt;

#[no_mangle]
pub fn kernel_main() {

}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
pub extern fn rust_begin_unwind(args: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
//    use core::fmt::Write;
//    log!("\r\nPanic at {}:{}: ", file, line);
//    let _ = console::Console.write_fmt(args);
    loop {};
}
<|endoftext|>


<commit_before>use platform::drivers::vga;
use platform::io;

#[start]
#[no_mangle]
pub unsafe fn main(_argc: int, _argv: *mut u8) -> int {
  vga::clear_screen(vga::Black);
  io::write("olarmundo");
  0
}

<commit_msg>remove old hacks needed by older versions of rust<commit_after>use platform::drivers::vga;
use platform::io;

#[no_mangle]
pub fn kmain() -> int {
  io::write("olar");
  0
}

<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]

use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{self, AsyncRead, AsyncReadExt, ReadBuf};
use tokio_test::assert_ok;

#[tokio::test]
async fn take() {
    let mut buf = [0; 6];
    let rd: &[u8] = b"hello world";

    let mut rd = rd.take(4);
    let n = assert_ok!(rd.read(&mut buf).await);
    assert_eq!(n, 4);
    assert_eq!(&buf, &b"hell\0\0"[..]);
}

struct BadReader;

impl AsyncRead for BadReader {
    fn poll_read(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        read_buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let vec = vec![0; 10];

        let mut buf = ReadBuf::new(vec.leak());
        buf.put_slice(&[123; 10]);
        *read_buf = buf;

        Poll::Ready(Ok(()))
    }
}

#[tokio::test]
#[should_panic]
async fn bad_reader_fails() {
    let mut buf = Vec::with_capacity(10);

    BadReader.take(10).read_buf(&mut buf).await.unwrap();
}
<commit_msg>io: add test for take bug (#4443)<commit_after>#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]

use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{self, AsyncRead, AsyncReadExt, ReadBuf};
use tokio_test::assert_ok;

#[tokio::test]
async fn take() {
    let mut buf = [0; 6];
    let rd: &[u8] = b"hello world";

    let mut rd = rd.take(4);
    let n = assert_ok!(rd.read(&mut buf).await);
    assert_eq!(n, 4);
    assert_eq!(&buf, &b"hell\0\0"[..]);
}

#[tokio::test]
async fn issue_4435() {
    let mut buf = [0; 8];
    let rd: &[u8] = b"hello world";

    let rd = rd.take(4);
    tokio::pin!(rd);

    let mut read_buf = ReadBuf::new(&mut buf);
    read_buf.put_slice(b"AB");

    futures::future::poll_fn(|cx| rd.as_mut().poll_read(cx, &mut read_buf))
        .await
        .unwrap();
    assert_eq!(&buf, &b"ABhell\0\0"[..]);
}

struct BadReader;

impl AsyncRead for BadReader {
    fn poll_read(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        read_buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let vec = vec![0; 10];

        let mut buf = ReadBuf::new(vec.leak());
        buf.put_slice(&[123; 10]);
        *read_buf = buf;

        Poll::Ready(Ok(()))
    }
}

#[tokio::test]
#[should_panic]
async fn bad_reader_fails() {
    let mut buf = Vec::with_capacity(10);

    BadReader.take(10).read_buf(&mut buf).await.unwrap();
}
<|endoftext|>


<commit_before>//! The APNs response types

/// The response data from APNs.
#[derive(Debug)]
pub struct Response {
    /// If the notification was not successful, has the body content from APNs.
    pub error: Option<ErrorBody>,

    /// Is the value defined in the `NotificationOptions` or a new Uuid
    /// generated by APNs.
    pub apns_id: Option<String>,

    /// The HTTP response code.
    ///
    /// * 200 Success
    /// * 400 Bad request
    /// * 403 There was an error with the certificate or with the provider authentication token
    /// * 405 The request used a bad `:method` value. Only `POST` requests are supported.
    /// * 410 The device token is no longer active for the topic.
    /// * 413 The notification payload was too large.
    /// * 429 The server received too many requests for the same device token.
    /// * 500 Internal server error.
    /// * 503 The server is shutting down and unavailable.
    pub code: u16,
}

/// The response body from APNs. Only available for errors.
#[derive(Deserialize, Debug, PartialEq)]
pub struct ErrorBody {
    /// The error indicating the reason for the failure.
    pub reason: ErrorReason,

    /// If the value of the `ErrorReason` is `Unregistered`, the value of this
    /// key is the last time at which APNs confirmed that the device token was
    /// no longer valid for the topic.
    ///
    /// Stop pushing notifications until the device registers a token with a
    /// later timestamp with your provider.
    pub timestamp: Option<u64>,
}

/// A description what went wrong with the push notification.
#[derive(Deserialize, Debug, PartialEq)]
pub enum ErrorReason {
    /// The collapse identifier exceeds the maximum allowed size.
    BadCollapseId,

    /// The specified device token was bad. Verify that the request contains a
    /// valid token and that the token matches the environment.
    BadDeviceToken,

    /// The `apns_expiration` in `NotificationOptions` is bad.
    BadExpirationDate,

    /// The `apns_id` in `NotificationOptions` is bad.
    BadMessageId,

    /// The `apns_priority` in `NotificationOptions` is bad.
    BadPriority,

    /// The `apns_topic` in `NotificationOptions` is bad.
    BadTopic,

    /// The device token does not match the specified topic.
    DeviceTokenNotForTopic,

    /// One or more headers were repeated.
    DuplicateHeaders,

    /// Idle time out.
    IdleTimeout,

    /// The device token is not specified in the payload.
    MissingDeviceToken,

    /// The `apns_topic` of the `NotificationOptions` was not specified and was required.
    /// The `apns_topic` header is mandatory when the client is connected using the
    /// `CertificateConnector` and the included PKCS12 file includes multiple topics,
    /// or when using the `TokenConnector`.
    MissingTopic,

    /// The message payload was empty.
    PayloadEmpty,

    /// Pushing to this topic is not allowed.
    TopicDisallowed,

    /// The certificate was bad.
    BadCertificate,

    /// The client certificate was for the wrong environment.
    BadCertificateEnvironment,

    /// The provider token is stale and a new token should be generated.
    ExpiredProviderToken,

    /// The specified action is not allowed.
    Forbidden,

    /// The provider token is not valid or the token signature could not be verified.
    InvalidProviderToken,

    /// No provider certificate was used to connect to APNs and Authorization
    /// header was missing or no provider token was specified.
    MissingProviderToken,

    /// The request path value is bad.
    BadPath,

    /// The request method was not `POST`.
    MethodNotAllowed,

    /// The device token is inactive for the specified topic. You should stop sending
    /// notifications to this token.
    Unregistered,

    /// The message payload was too large (4096 bytes)
    PayloadTooLarge,

    /// The provider token is being updated too often.
    TooManyProviderTokenUpdates,

    /// Too many requests were made consecutively to the same device token.
    TooManyRequests,

    /// An internal server error occurred.
    InternalServerError,

    /// The service is unavailable.
    ServiceUnavailable,

    /// The server is shutting down.
    Shutdown,
}

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

    #[test]
    fn test_error_response_parsing() {
        let errors = vec![
            (ErrorReason::BadCollapseId, "BadCollapseId", None),
            (ErrorReason::BadDeviceToken, "BadDeviceToken", None),
            (ErrorReason::BadExpirationDate, "BadExpirationDate", None),
            (ErrorReason::BadMessageId, "BadMessageId", None),
            (ErrorReason::BadPriority, "BadPriority", None),
            (ErrorReason::BadTopic, "BadTopic", None),
            (
                ErrorReason::DeviceTokenNotForTopic,
                "DeviceTokenNotForTopic",
                None,
            ),
            (ErrorReason::DuplicateHeaders, "DuplicateHeaders", None),
            (ErrorReason::IdleTimeout, "IdleTimeout", None),
            (ErrorReason::MissingDeviceToken, "MissingDeviceToken", None),
            (ErrorReason::MissingTopic, "MissingTopic", None),
            (ErrorReason::PayloadEmpty, "PayloadEmpty", None),
            (ErrorReason::TopicDisallowed, "TopicDisallowed", None),
            (ErrorReason::BadCertificate, "BadCertificate", None),
            (
                ErrorReason::BadCertificateEnvironment,
                "BadCertificateEnvironment",
                None,
            ),
            (
                ErrorReason::ExpiredProviderToken,
                "ExpiredProviderToken",
                None,
            ),
            (ErrorReason::Forbidden, "Forbidden", None),
            (
                ErrorReason::InvalidProviderToken,
                "InvalidProviderToken",
                None,
            ),
            (
                ErrorReason::MissingProviderToken,
                "MissingProviderToken",
                None,
            ),
            (ErrorReason::BadPath, "BadPath", None),
            (ErrorReason::MethodNotAllowed, "MethodNotAllowed", None),
            (
                ErrorReason::Unregistered,
                "Unregistered",
                Some(1508249865488u64),
            ),
            (ErrorReason::PayloadTooLarge, "PayloadTooLarge", None),
            (
                ErrorReason::TooManyProviderTokenUpdates,
                "TooManyProviderTokenUpdates",
                None,
            ),
            (ErrorReason::TooManyRequests, "TooManyRequests", None),
            (
                ErrorReason::InternalServerError,
                "InternalServerError",
                None,
            ),
            (ErrorReason::ServiceUnavailable, "ServiceUnavailable", None),
            (ErrorReason::Shutdown, "Shutdown", None),
        ];

        for error in errors.into_iter() {
            let response_data = match error.2 {
                None => json!({"reason": error.1}),
                Some(ts) => json!({"reason": error.1, "timestamp": ts}),
            };

            let response_string = serde_json::to_string(&response_data).unwrap();

            let response_body: ErrorBody = serde_json::from_str(&response_string).unwrap();

            let expected_body = match error.2 {
                None => ErrorBody {
                    reason: error.0,
                    timestamp: None,
                },
                Some(ts) => ErrorBody {
                    reason: error.0,
                    timestamp: Some(ts),
                },
            };

            assert_eq!(expected_body, response_body);
        }
    }
}
<commit_msg>Implement fmt::Display for ErrorReason<commit_after>//! The APNs response types

use std::fmt;

/// The response data from APNs.
#[derive(Debug)]
pub struct Response {
    /// If the notification was not successful, has the body content from APNs.
    pub error: Option<ErrorBody>,

    /// Is the value defined in the `NotificationOptions` or a new Uuid
    /// generated by APNs.
    pub apns_id: Option<String>,

    /// The HTTP response code.
    ///
    /// * 200 Success
    /// * 400 Bad request
    /// * 403 There was an error with the certificate or with the provider authentication token
    /// * 405 The request used a bad `:method` value. Only `POST` requests are supported.
    /// * 410 The device token is no longer active for the topic.
    /// * 413 The notification payload was too large.
    /// * 429 The server received too many requests for the same device token.
    /// * 500 Internal server error.
    /// * 503 The server is shutting down and unavailable.
    pub code: u16,
}

/// The response body from APNs. Only available for errors.
#[derive(Deserialize, Debug, PartialEq)]
pub struct ErrorBody {
    /// The error indicating the reason for the failure.
    pub reason: ErrorReason,

    /// If the value of the `ErrorReason` is `Unregistered`, the value of this
    /// key is the last time at which APNs confirmed that the device token was
    /// no longer valid for the topic.
    ///
    /// Stop pushing notifications until the device registers a token with a
    /// later timestamp with your provider.
    pub timestamp: Option<u64>,
}

/// A description what went wrong with the push notification.
#[derive(Deserialize, Debug, PartialEq)]
pub enum ErrorReason {
    /// The collapse identifier exceeds the maximum allowed size.
    BadCollapseId,

    /// The specified device token was bad. Verify that the request contains a
    /// valid token and that the token matches the environment.
    BadDeviceToken,

    /// The `apns_expiration` in `NotificationOptions` is bad.
    BadExpirationDate,

    /// The `apns_id` in `NotificationOptions` is bad.
    BadMessageId,

    /// The `apns_priority` in `NotificationOptions` is bad.
    BadPriority,

    /// The `apns_topic` in `NotificationOptions` is bad.
    BadTopic,

    /// The device token does not match the specified topic.
    DeviceTokenNotForTopic,

    /// One or more headers were repeated.
    DuplicateHeaders,

    /// Idle time out.
    IdleTimeout,

    /// The device token is not specified in the payload.
    MissingDeviceToken,

    /// The `apns_topic` of the `NotificationOptions` was not specified and was required.
    /// The `apns_topic` header is mandatory when the client is connected using the
    /// `CertificateConnector` and the included PKCS12 file includes multiple topics,
    /// or when using the `TokenConnector`.
    MissingTopic,

    /// The message payload was empty.
    PayloadEmpty,

    /// Pushing to this topic is not allowed.
    TopicDisallowed,

    /// The certificate was bad.
    BadCertificate,

    /// The client certificate was for the wrong environment.
    BadCertificateEnvironment,

    /// The provider token is stale and a new token should be generated.
    ExpiredProviderToken,

    /// The specified action is not allowed.
    Forbidden,

    /// The provider token is not valid or the token signature could not be verified.
    InvalidProviderToken,

    /// No provider certificate was used to connect to APNs and Authorization
    /// header was missing or no provider token was specified.
    MissingProviderToken,

    /// The request path value is bad.
    BadPath,

    /// The request method was not `POST`.
    MethodNotAllowed,

    /// The device token is inactive for the specified topic. You should stop sending
    /// notifications to this token.
    Unregistered,

    /// The message payload was too large (4096 bytes)
    PayloadTooLarge,

    /// The provider token is being updated too often.
    TooManyProviderTokenUpdates,

    /// Too many requests were made consecutively to the same device token.
    TooManyRequests,

    /// An internal server error occurred.
    InternalServerError,

    /// The service is unavailable.
    ServiceUnavailable,

    /// The server is shutting down.
    Shutdown,
}

impl fmt::Display for ErrorReason {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            ErrorReason::BadCollapseId => "The collapse identifier exceeds the maximum allowed size.",
            ErrorReason::BadDeviceToken => "The specified device token was bad. Verify that the request contains a valid token and that the token matches the environment.",
            ErrorReason::BadExpirationDate => "The `apns_expiration` in `NotificationOptions` is bad.",
            ErrorReason::BadMessageId => "The `apns_id` in `NotificationOptions` is bad.",
            ErrorReason::BadPriority => "The `apns_priority` in `NotificationOptions` is bad.",
            ErrorReason::BadTopic => "The `apns_topic` in `NotificationOptions` is bad.",
            ErrorReason::DeviceTokenNotForTopic => "The device token does not match the specified topic.",
            ErrorReason::DuplicateHeaders => "One or more headers were repeated.",
            ErrorReason::IdleTimeout => "Idle time out.",
            ErrorReason::MissingDeviceToken => "The device token is not specified in the payload.",
            ErrorReason::MissingTopic => "The `apns_topic` of the `NotificationOptions` was not specified and was required. The `apns_topic` header is mandatory when the client is connected using the `CertificateConnector` and the included PKCS12 file includes multiple topics, or when using the `TokenConnector`.",
            ErrorReason::PayloadEmpty => "The message payload was empty.",
            ErrorReason::TopicDisallowed => "Pushing to this topic is not allowed.",
            ErrorReason::BadCertificate => "The certificate was bad.",
            ErrorReason::BadCertificateEnvironment => "The client certificate was for the wrong environment.",
            ErrorReason::ExpiredProviderToken => "The provider token is stale and a new token should be generated.",
            ErrorReason::Forbidden => "The specified action is not allowed.",
            ErrorReason::InvalidProviderToken => "The provider token is not valid or the token signature could not be verified.",
            ErrorReason::MissingProviderToken => "No provider certificate was used to connect to APNs and Authorization header was missing or no provider token was specified.",
            ErrorReason::BadPath => "The request path value is bad.",
            ErrorReason::MethodNotAllowed => "The request method was not `POST`.",
            ErrorReason::Unregistered => "The device token is inactive for the specified topic. You should stop sending notifications to this token.",
            ErrorReason::PayloadTooLarge => "The message payload was too large (4096 bytes)",
            ErrorReason::TooManyProviderTokenUpdates => "The provider token is being updated too often.",
            ErrorReason::TooManyRequests => "Too many requests were made consecutively to the same device token.",
            ErrorReason::InternalServerError => "An internal server error occurred.",
            ErrorReason::ServiceUnavailable => "The service is unavailable.",
            ErrorReason::Shutdown => "The server is shutting down.",
        };

        f.write_str(s)
    }
}

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

    #[test]
    fn test_error_response_parsing() {
        let errors = vec![
            (ErrorReason::BadCollapseId, "BadCollapseId", None),
            (ErrorReason::BadDeviceToken, "BadDeviceToken", None),
            (ErrorReason::BadExpirationDate, "BadExpirationDate", None),
            (ErrorReason::BadMessageId, "BadMessageId", None),
            (ErrorReason::BadPriority, "BadPriority", None),
            (ErrorReason::BadTopic, "BadTopic", None),
            (
                ErrorReason::DeviceTokenNotForTopic,
                "DeviceTokenNotForTopic",
                None,
            ),
            (ErrorReason::DuplicateHeaders, "DuplicateHeaders", None),
            (ErrorReason::IdleTimeout, "IdleTimeout", None),
            (ErrorReason::MissingDeviceToken, "MissingDeviceToken", None),
            (ErrorReason::MissingTopic, "MissingTopic", None),
            (ErrorReason::PayloadEmpty, "PayloadEmpty", None),
            (ErrorReason::TopicDisallowed, "TopicDisallowed", None),
            (ErrorReason::BadCertificate, "BadCertificate", None),
            (
                ErrorReason::BadCertificateEnvironment,
                "BadCertificateEnvironment",
                None,
            ),
            (
                ErrorReason::ExpiredProviderToken,
                "ExpiredProviderToken",
                None,
            ),
            (ErrorReason::Forbidden, "Forbidden", None),
            (
                ErrorReason::InvalidProviderToken,
                "InvalidProviderToken",
                None,
            ),
            (
                ErrorReason::MissingProviderToken,
                "MissingProviderToken",
                None,
            ),
            (ErrorReason::BadPath, "BadPath", None),
            (ErrorReason::MethodNotAllowed, "MethodNotAllowed", None),
            (
                ErrorReason::Unregistered,
                "Unregistered",
                Some(1508249865488u64),
            ),
            (ErrorReason::PayloadTooLarge, "PayloadTooLarge", None),
            (
                ErrorReason::TooManyProviderTokenUpdates,
                "TooManyProviderTokenUpdates",
                None,
            ),
            (ErrorReason::TooManyRequests, "TooManyRequests", None),
            (
                ErrorReason::InternalServerError,
                "InternalServerError",
                None,
            ),
            (ErrorReason::ServiceUnavailable, "ServiceUnavailable", None),
            (ErrorReason::Shutdown, "Shutdown", None),
        ];

        for error in errors.into_iter() {
            let response_data = match error.2 {
                None => json!({"reason": error.1}),
                Some(ts) => json!({"reason": error.1, "timestamp": ts}),
            };

            let response_string = serde_json::to_string(&response_data).unwrap();

            let response_body: ErrorBody = serde_json::from_str(&response_string).unwrap();

            let expected_body = match error.2 {
                None => ErrorBody {
                    reason: error.0,
                    timestamp: None,
                },
                Some(ts) => ErrorBody {
                    reason: error.0,
                    timestamp: Some(ts),
                },
            };

            assert_eq!(expected_body, response_body);
        }
    }
}
<|endoftext|>