<commit_before>extern crate libc;

use api::ErrorCode;
use errors::ToErrorCode;
use commands::{Command, CommandExecutor};
use commands::signus::SignusCommand;
use utils::cstring::CStringUtils;

use self::libc::c_char;

/// Creates keys (signing and encryption keys) for a new
/// DID (owned by the caller of the library).
/// Identity's DID must be either explicitly provided, or taken as the first 16 bit of verkey.
/// Saves the Identity DID with keys in a secured Wallet, so that it can be used to sign
/// and encrypt transactions.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// did_json: Identity information as json. Example:
/// {
///     "did": string, (optional;
///             if not provided and cid param is false then the first 16 bit of the verkey will be used as a new DID;
///             if not provided and cid is true then the full verkey will be used as a new DID;
///             if provided, then keys will be replaced - key rotation use case)
///     "seed": string, (optional; if not provide then a random one will be created)
///     "crypto_type": string, (optional; if not set then ed25519 curve is used;
///               currently only 'ed25519' value is supported for this field)
///     "cid": string, (optional; if not set then false is used;)
/// }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// DID, verkey (for verification of signature) and public_key (for decryption)
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_create_and_store_my_did(command_handle: i32,
                                              wallet_handle: i32,
                                              did_json: *const c_char,
                                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                   did: *const c_char,
                                                                   verkey: *const c_char,
                                                                   pk: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(did_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::CreateAndStoreMyDid(
            wallet_handle,
            did_json,
            Box::new(move |result| {
                let (err, did, verkey, pk) = result_to_err_code_3!(result, String::new(), String::new(), String::new());
                let did = CStringUtils::string_to_cstring(did);
                let verkey = CStringUtils::string_to_cstring(verkey);
                let pk = CStringUtils::string_to_cstring(pk);
                cb(command_handle, err, did.as_ptr(), verkey.as_ptr(), pk.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Generated new keys (signing and encryption keys) for an existing
/// DID (owned by the caller of the library).
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// identity_json: Identity information as json. Example:
/// {
///     "seed": string, (optional; if not provide then a random one will be created)
///     "crypto_type": string, (optional; if not set then ed25519 curve is used;
///               currently only 'ed25519' value is supported for this field)
/// }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// verkey (for verification of signature) and public_key (for decryption)
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_replace_keys(command_handle: i32,
                                   wallet_handle: i32,
                                   did: *const c_char,
                                   identity_json: *const c_char,
                                   cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                        verkey: *const c_char,
                                                        pk: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(identity_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::ReplaceKeys(
            wallet_handle,
            identity_json,
            did,
            Box::new(move |result| {
                let (err, verkey, pk) = result_to_err_code_2!(result, String::new(), String::new());
                let verkey = CStringUtils::string_to_cstring(verkey);
                let pk = CStringUtils::string_to_cstring(pk);
                cb(command_handle, err, verkey.as_ptr(), pk.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Saves their DID for a pairwise connection in a secured Wallet,
/// so that it can be used to verify transaction.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// identity_json: Identity information as json. Example:
///     {
///        "did": string, (required)
///        "verkey": string (optional, if only pk is provided),
///        "pk": string (optional, if only verification key is provided),
///        "crypto_type": string, (optional; if not set then ed25519 curve is used;
///               currently only 'ed25519' value is supported for this field)
///     }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// None
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_store_their_did(command_handle: i32,
                                      wallet_handle: i32,
                                      identity_json: *const c_char,
                                      cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode)>) -> ErrorCode {
    check_useful_c_str!(identity_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::StoreTheirDid(
            wallet_handle,
            identity_json,
            Box::new(move |result| {
                let err = result_to_err_code!(result);
                cb(command_handle, err)
            })
        )));

    result_to_err_code!(result)
}

/// Signs a message by a signing key associated with my DID. The DID with a signing key
/// must be already created and stored in a secured wallet (see create_and_store_my_identity)
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// did: signing DID
/// msg: a message to be signed
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// a signature string
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_sign(command_handle: i32,
                           wallet_handle: i32,
                           did: *const c_char,
                           msg: *const c_char,
                           cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                signature: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(msg, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::Sign(
            wallet_handle,
            did,
            msg,
            Box::new(move |result| {
                let (err, signed_msg) = result_to_err_code_1!(result, String::new());
                let signed_msg = CStringUtils::string_to_cstring(signed_msg);
                cb(command_handle, err, signed_msg.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Verify a signature created by a key associated with a DID.
/// If a secure wallet doesn't contain a verkey associated with the given DID,
/// then verkey is read from the Ledger.
/// Otherwise either an existing verkey from wallet is used (see wallet_store_their_identity),
/// or it checks the Ledger (according to freshness settings set during initialization)
/// whether verkey is still the same and updates verkey for the DID if needed.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// pool_handle: pool handle.
/// did: DID that signed the message
/// msg: message
/// signature: a signature to be verified
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// valid: true - if signature is valid, false - otherwise
///
/// #Errors
/// Common*
/// Wallet*
/// Ledger*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_verify_signature(command_handle: i32,
                                       wallet_handle: i32,
                                       pool_handle: i32,
                                       did: *const c_char,
                                       signed_msg: *const c_char,
                                       cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                            valid: bool)>) -> ErrorCode {
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(signed_msg, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::VerifySignature(
            wallet_handle,
            pool_handle,
            did,
            signed_msg,
            Box::new(move |result| {
                let (err, valid) = result_to_err_code_1!(result, false);
                cb(command_handle, err, valid)
            })
        )));

    result_to_err_code!(result)
}

/// Encrypts a message by a public key associated with a DID.
/// If a secure wallet doesn't contain a public key associated with the given DID,
/// then the public key is read from the Ledger.
/// Otherwise either an existing public key from wallet is used (see wallet_store_their_identity),
/// or it checks the Ledger (according to freshness settings set during initialization)
/// whether public key is still the same and updates public key for the DID if needed.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// my_did: encrypting DID
/// did: encrypting DID
/// msg: a message to be signed
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// an encrypted message and nonce
///
/// #Errors
/// Common*
/// Wallet*
/// Ledger*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_encrypt(command_handle: i32,
                              wallet_handle: i32,
                              pool_handle: i32,
                              my_did: *const c_char,
                              did: *const c_char,
                              msg: *const c_char,
                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                   encrypted_msg: *const c_char,
                                                   nonce: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(my_did, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam5);
    check_useful_c_str!(msg, ErrorCode::CommonInvalidParam6);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::Encrypt(
            wallet_handle,
            pool_handle,
            my_did,
            did,
            msg,
            Box::new(move |result| {
                let (err, encrypted_msg, nonce) = result_to_err_code_2!(result, String::new(), String::new());
                let encrypted_msg = CStringUtils::string_to_cstring(encrypted_msg);
                let nonce = CStringUtils::string_to_cstring(nonce);
                cb(command_handle, err, encrypted_msg.as_ptr(), nonce.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Decrypts a message encrypted by a public key associated with my DID.
/// The DID with a secret key must be already created and
/// stored in a secured wallet (see wallet_create_and_store_my_identity)
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// my_did: DID
/// did: DID that signed the message
/// encrypted_msg: encrypted message
/// nonce: nonce that encrypted message
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// decrypted message
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_decrypt(command_handle: i32,
                              wallet_handle: i32,
                              my_did: *const c_char,
                              did: *const c_char,
                              encrypted_msg: *const c_char,
                              nonce: *const c_char,
                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                   decrypted_msg: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(my_did, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam5);
    check_useful_c_str!(encrypted_msg, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(nonce, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::Decrypt(
            wallet_handle,
            did,
            my_did,
            encrypted_msg,
            nonce,
            Box::new(move |result| {
                let (err, decrypted_msg) = result_to_err_code_1!(result, String::new());
                let decrypted_msg = CStringUtils::string_to_cstring(decrypted_msg);
                cb(command_handle, err, decrypted_msg.as_ptr())
            })
        )));

    result_to_err_code!(result)
}<commit_msg>Fix comment about CID field type in did_json for sovrin_create_and_store_my_did.<commit_after>extern crate libc;

use api::ErrorCode;
use errors::ToErrorCode;
use commands::{Command, CommandExecutor};
use commands::signus::SignusCommand;
use utils::cstring::CStringUtils;

use self::libc::c_char;

/// Creates keys (signing and encryption keys) for a new
/// DID (owned by the caller of the library).
/// Identity's DID must be either explicitly provided, or taken as the first 16 bit of verkey.
/// Saves the Identity DID with keys in a secured Wallet, so that it can be used to sign
/// and encrypt transactions.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// did_json: Identity information as json. Example:
/// {
///     "did": string, (optional;
///             if not provided and cid param is false then the first 16 bit of the verkey will be used as a new DID;
///             if not provided and cid is true then the full verkey will be used as a new DID;
///             if provided, then keys will be replaced - key rotation use case)
///     "seed": string, (optional; if not provide then a random one will be created)
///     "crypto_type": string, (optional; if not set then ed25519 curve is used;
///               currently only 'ed25519' value is supported for this field)
///     "cid": bool, (optional; if not set then false is used;)
/// }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// DID, verkey (for verification of signature) and public_key (for decryption)
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_create_and_store_my_did(command_handle: i32,
                                              wallet_handle: i32,
                                              did_json: *const c_char,
                                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                   did: *const c_char,
                                                                   verkey: *const c_char,
                                                                   pk: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(did_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::CreateAndStoreMyDid(
            wallet_handle,
            did_json,
            Box::new(move |result| {
                let (err, did, verkey, pk) = result_to_err_code_3!(result, String::new(), String::new(), String::new());
                let did = CStringUtils::string_to_cstring(did);
                let verkey = CStringUtils::string_to_cstring(verkey);
                let pk = CStringUtils::string_to_cstring(pk);
                cb(command_handle, err, did.as_ptr(), verkey.as_ptr(), pk.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Generated new keys (signing and encryption keys) for an existing
/// DID (owned by the caller of the library).
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// identity_json: Identity information as json. Example:
/// {
///     "seed": string, (optional; if not provide then a random one will be created)
///     "crypto_type": string, (optional; if not set then ed25519 curve is used;
///               currently only 'ed25519' value is supported for this field)
/// }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// verkey (for verification of signature) and public_key (for decryption)
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_replace_keys(command_handle: i32,
                                   wallet_handle: i32,
                                   did: *const c_char,
                                   identity_json: *const c_char,
                                   cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                        verkey: *const c_char,
                                                        pk: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(identity_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::ReplaceKeys(
            wallet_handle,
            identity_json,
            did,
            Box::new(move |result| {
                let (err, verkey, pk) = result_to_err_code_2!(result, String::new(), String::new());
                let verkey = CStringUtils::string_to_cstring(verkey);
                let pk = CStringUtils::string_to_cstring(pk);
                cb(command_handle, err, verkey.as_ptr(), pk.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Saves their DID for a pairwise connection in a secured Wallet,
/// so that it can be used to verify transaction.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// identity_json: Identity information as json. Example:
///     {
///        "did": string, (required)
///        "verkey": string (optional, if only pk is provided),
///        "pk": string (optional, if only verification key is provided),
///        "crypto_type": string, (optional; if not set then ed25519 curve is used;
///               currently only 'ed25519' value is supported for this field)
///     }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// None
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_store_their_did(command_handle: i32,
                                      wallet_handle: i32,
                                      identity_json: *const c_char,
                                      cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode)>) -> ErrorCode {
    check_useful_c_str!(identity_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::StoreTheirDid(
            wallet_handle,
            identity_json,
            Box::new(move |result| {
                let err = result_to_err_code!(result);
                cb(command_handle, err)
            })
        )));

    result_to_err_code!(result)
}

/// Signs a message by a signing key associated with my DID. The DID with a signing key
/// must be already created and stored in a secured wallet (see create_and_store_my_identity)
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// did: signing DID
/// msg: a message to be signed
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// a signature string
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_sign(command_handle: i32,
                           wallet_handle: i32,
                           did: *const c_char,
                           msg: *const c_char,
                           cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                signature: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(msg, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::Sign(
            wallet_handle,
            did,
            msg,
            Box::new(move |result| {
                let (err, signed_msg) = result_to_err_code_1!(result, String::new());
                let signed_msg = CStringUtils::string_to_cstring(signed_msg);
                cb(command_handle, err, signed_msg.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Verify a signature created by a key associated with a DID.
/// If a secure wallet doesn't contain a verkey associated with the given DID,
/// then verkey is read from the Ledger.
/// Otherwise either an existing verkey from wallet is used (see wallet_store_their_identity),
/// or it checks the Ledger (according to freshness settings set during initialization)
/// whether verkey is still the same and updates verkey for the DID if needed.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// pool_handle: pool handle.
/// did: DID that signed the message
/// msg: message
/// signature: a signature to be verified
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// valid: true - if signature is valid, false - otherwise
///
/// #Errors
/// Common*
/// Wallet*
/// Ledger*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_verify_signature(command_handle: i32,
                                       wallet_handle: i32,
                                       pool_handle: i32,
                                       did: *const c_char,
                                       signed_msg: *const c_char,
                                       cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                            valid: bool)>) -> ErrorCode {
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(signed_msg, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::VerifySignature(
            wallet_handle,
            pool_handle,
            did,
            signed_msg,
            Box::new(move |result| {
                let (err, valid) = result_to_err_code_1!(result, false);
                cb(command_handle, err, valid)
            })
        )));

    result_to_err_code!(result)
}

/// Encrypts a message by a public key associated with a DID.
/// If a secure wallet doesn't contain a public key associated with the given DID,
/// then the public key is read from the Ledger.
/// Otherwise either an existing public key from wallet is used (see wallet_store_their_identity),
/// or it checks the Ledger (according to freshness settings set during initialization)
/// whether public key is still the same and updates public key for the DID if needed.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// my_did: encrypting DID
/// did: encrypting DID
/// msg: a message to be signed
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// an encrypted message and nonce
///
/// #Errors
/// Common*
/// Wallet*
/// Ledger*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_encrypt(command_handle: i32,
                              wallet_handle: i32,
                              pool_handle: i32,
                              my_did: *const c_char,
                              did: *const c_char,
                              msg: *const c_char,
                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                   encrypted_msg: *const c_char,
                                                   nonce: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(my_did, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam5);
    check_useful_c_str!(msg, ErrorCode::CommonInvalidParam6);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::Encrypt(
            wallet_handle,
            pool_handle,
            my_did,
            did,
            msg,
            Box::new(move |result| {
                let (err, encrypted_msg, nonce) = result_to_err_code_2!(result, String::new(), String::new());
                let encrypted_msg = CStringUtils::string_to_cstring(encrypted_msg);
                let nonce = CStringUtils::string_to_cstring(nonce);
                cb(command_handle, err, encrypted_msg.as_ptr(), nonce.as_ptr())
            })
        )));

    result_to_err_code!(result)
}

/// Decrypts a message encrypted by a public key associated with my DID.
/// The DID with a secret key must be already created and
/// stored in a secured wallet (see wallet_create_and_store_my_identity)
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// my_did: DID
/// did: DID that signed the message
/// encrypted_msg: encrypted message
/// nonce: nonce that encrypted message
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// decrypted message
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub  extern fn sovrin_decrypt(command_handle: i32,
                              wallet_handle: i32,
                              my_did: *const c_char,
                              did: *const c_char,
                              encrypted_msg: *const c_char,
                              nonce: *const c_char,
                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                   decrypted_msg: *const c_char)>) -> ErrorCode {
    check_useful_c_str!(my_did, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(did, ErrorCode::CommonInvalidParam5);
    check_useful_c_str!(encrypted_msg, ErrorCode::CommonInvalidParam4);
    check_useful_c_str!(nonce, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    let result = CommandExecutor::instance()
        .send(Command::Signus(SignusCommand::Decrypt(
            wallet_handle,
            did,
            my_did,
            encrypted_msg,
            nonce,
            Box::new(move |result| {
                let (err, decrypted_msg) = result_to_err_code_1!(result, String::new());
                let decrypted_msg = CStringUtils::string_to_cstring(decrypted_msg);
                cb(command_handle, err, decrypted_msg.as_ptr())
            })
        )));

    result_to_err_code!(result)
}<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

/// Command line argument parser error types
#[derive(PartialEq, Debug)]
pub enum ClapErrorType {
    /// Error occurs when some possible values were set, but clap found unexpected value
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug").index(1)
    ///         .possible_value("fast")
    ///         .possible_value("slow"))
    ///     .get_matches_from_safe(vec!["", "other"]);
    /// ```
    InvalidValue,
    /// Error occurs when clap found unexpected flag or option
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::from_usage("-f, --flag 'some flag'"))
    ///     .get_matches_from_safe(vec!["", "--other"]);
    /// ```
    InvalidArgument,
    /// Error occurs when clap found unexpected subcommand
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// let result = App::new("myprog")
    ///     .subcommand(SubCommand::with_name("conifg")
    ///         .about("Used for configuration")
    ///         .arg(Arg::with_name("config_file")
    ///             .help("The configuration file to use")
    ///             .index(1)))
    ///     .get_matches_from_safe(vec!["", "other"]);
    /// ```
    InvalidSubcommand,
    /// Error occurs when option does not allow empty values but some was found
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///          .empty_values(false))
    ///     .arg(Arg::with_name("color"))
    ///     .get_matches_from_safe(vec!["", "--debug", "--color"]);
    /// ```
    EmptyValue,
    /// Parser inner error
    OptionError,
    /// Parser inner error
    ArgumentError,
    /// Parser inner error
    ValueError,
    /// Error occurs when argument got more values then were expected
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug").index(1)
    ///         .max_values(2))
    ///     .get_matches_from_safe(vec!["", "too", "much", "values"]);
    /// ```
    TooMuchValues,
    /// Error occurs when argument got less values then were expected
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug").index(1)
    ///         .min_values(3))
    ///     .get_matches_from_safe(vec!["", "too", "few"]);
    /// ```
    TooFewValues,
    /// Error occurs when clap find two ore more conflicting arguments
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///         .conflicts_with("color"))
    ///     .get_matches_from_safe(vec!["", "--debug", "--color"]);
    /// ```
    ArgumentConflict,
    /// Error occurs when one or more required arguments missing
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///         .required(true))
    ///     .get_matches_from_safe(vec![""]);
    /// ```
    MissingRequiredArgument,
    /// Error occurs when required subcommand missing
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, AppSettings, SubCommand};
    /// let result = App::new("myprog")
    ///     .setting(AppSettings::SubcommandRequired)
    ///     .subcommand(SubCommand::with_name("conifg")
    ///         .about("Used for configuration")
    ///         .arg(Arg::with_name("config_file")
    ///             .help("The configuration file to use")
    ///             .index(1)))
    ///     .get_matches_from_safe(vec![""]);
    /// ```
    MissingSubcommand,
    /// Error occurs when clap find argument while is was not expecting any
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App};
    /// let result = App::new("myprog")
    ///     .get_matches_from_safe(vec!["", "--arg"]);
    /// ```
    UnexpectedArgument,
    /// Error occurs when argument was used multiple times and was not set as multiple.
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///         .multiple(false))
    ///     .get_matches_from_safe(vec!["", "--debug", "--debug"]);
    /// ```
    UnexpectedMultipleUsage,
}

/// Command line argument parser error
#[derive(Debug)]
pub struct ClapError {
    /// Formated error message
    pub error: String,
    /// Command line argument parser error type
    pub error_type: ClapErrorType,
}

impl Error for ClapError {
    fn description(&self) -> &str {
        &*self.error
    }
}

impl fmt::Display for ClapError {
    fn fmt(&self,
           f: &mut fmt::Formatter)
           -> fmt::Result {
        write!(f, "{}", self.error)
    }
}
<commit_msg>feat(Errors): allows consumers to write to stderr and exit on error<commit_after>use std::process;
use std::error::Error;
use std::fmt;

/// Command line argument parser error types
#[derive(PartialEq, Debug)]
pub enum ClapErrorType {
    /// Error occurs when some possible values were set, but clap found unexpected value
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug").index(1)
    ///         .possible_value("fast")
    ///         .possible_value("slow"))
    ///     .get_matches_from_safe(vec!["", "other"]);
    /// ```
    InvalidValue,
    /// Error occurs when clap found unexpected flag or option
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::from_usage("-f, --flag 'some flag'"))
    ///     .get_matches_from_safe(vec!["", "--other"]);
    /// ```
    InvalidArgument,
    /// Error occurs when clap found unexpected subcommand
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, SubCommand};
    /// let result = App::new("myprog")
    ///     .subcommand(SubCommand::with_name("conifg")
    ///         .about("Used for configuration")
    ///         .arg(Arg::with_name("config_file")
    ///             .help("The configuration file to use")
    ///             .index(1)))
    ///     .get_matches_from_safe(vec!["", "other"]);
    /// ```
    InvalidSubcommand,
    /// Error occurs when option does not allow empty values but some was found
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///          .empty_values(false))
    ///     .arg(Arg::with_name("color"))
    ///     .get_matches_from_safe(vec!["", "--debug", "--color"]);
    /// ```
    EmptyValue,
    /// Parser inner error
    OptionError,
    /// Parser inner error
    ArgumentError,
    /// Parser inner error
    ValueError,
    /// Error occurs when argument got more values then were expected
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug").index(1)
    ///         .max_values(2))
    ///     .get_matches_from_safe(vec!["", "too", "much", "values"]);
    /// ```
    TooMuchValues,
    /// Error occurs when argument got less values then were expected
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug").index(1)
    ///         .min_values(3))
    ///     .get_matches_from_safe(vec!["", "too", "few"]);
    /// ```
    TooFewValues,
    /// Error occurs when clap find two ore more conflicting arguments
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///         .conflicts_with("color"))
    ///     .get_matches_from_safe(vec!["", "--debug", "--color"]);
    /// ```
    ArgumentConflict,
    /// Error occurs when one or more required arguments missing
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///         .required(true))
    ///     .get_matches_from_safe(vec![""]);
    /// ```
    MissingRequiredArgument,
    /// Error occurs when required subcommand missing
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, AppSettings, SubCommand};
    /// let result = App::new("myprog")
    ///     .setting(AppSettings::SubcommandRequired)
    ///     .subcommand(SubCommand::with_name("conifg")
    ///         .about("Used for configuration")
    ///         .arg(Arg::with_name("config_file")
    ///             .help("The configuration file to use")
    ///             .index(1)))
    ///     .get_matches_from_safe(vec![""]);
    /// ```
    MissingSubcommand,
    /// Occurs when no argument or subcommand has been supplied and
    /// `AppSettings::ArgRequiredElseHelp` was used
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg, AppSettings, SubCommand};
    /// let result = App::new("myprog")
    ///     .setting(AppSettings::ArgRequiredElseHelp)
    ///     .subcommand(SubCommand::with_name("conifg")
    ///         .about("Used for configuration")
    ///         .arg(Arg::with_name("config_file")
    ///             .help("The configuration file to use")
    ///             .index(1)))
    ///     .get_matches_from_safe(vec![""]);
    /// ```
    MissingArgumentOrSubcommand,
    /// Error occurs when clap find argument while is was not expecting any
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App};
    /// let result = App::new("myprog")
    ///     .get_matches_from_safe(vec!["", "--arg"]);
    /// ```
    UnexpectedArgument,
    /// Error occurs when argument was used multiple times and was not set as multiple.
    ///
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use clap::{App, Arg};
    /// let result = App::new("myprog")
    ///     .arg(Arg::with_name("debug")
    ///         .multiple(false))
    ///     .get_matches_from_safe(vec!["", "--debug", "--debug"]);
    /// ```
    UnexpectedMultipleUsage,
}

/// Command line argument parser error
#[derive(Debug)]
pub struct ClapError {
    /// Formated error message
    pub error: String,
    /// Command line argument parser error type
    pub error_type: ClapErrorType,
}

impl ClapError {
    /// Prints the error to `stderr` and exits with a status of `1`
    pub fn exit(&self) -> ! {
        wlnerr!("{}", self.error);
        process::exit(1);
    }
}

impl Error for ClapError {
    fn description(&self) -> &str {
        &*self.error
    }
}

impl fmt::Display for ClapError {
    fn fmt(&self,
           f: &mut fmt::Formatter)
           -> fmt::Result {
        write!(f, "{}", self.error)
    }
}
<|endoftext|>


<commit_before>use nom::character::complete::{multispace0, multispace1};
use std::{fmt, str};

use column::Column;
use common::{
    as_alias, column_identifier_no_alias, integer_literal, type_identifier, Literal, SqlType,
};

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticOperator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticBase {
    Column(Column),
    Scalar(Literal),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ArithmeticExpression {
    pub op: ArithmeticOperator,
    pub left: ArithmeticBase,
    pub right: ArithmeticBase,
    pub alias: Option<String>,
}

impl ArithmeticExpression {
    pub fn new(
        op: ArithmeticOperator,
        left: ArithmeticBase,
        right: ArithmeticBase,
        alias: Option<String>,
    ) -> Self {
        Self {
            op,
            left,
            right,
            alias,
        }
    }
}

impl fmt::Display for ArithmeticOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticOperator::Add => write!(f, "+"),
            ArithmeticOperator::Subtract => write!(f, "-"),
            ArithmeticOperator::Multiply => write!(f, "*"),
            ArithmeticOperator::Divide => write!(f, "/"),
        }
    }
}

impl fmt::Display for ArithmeticBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticBase::Column(ref col) => write!(f, "{}", col),
            ArithmeticBase::Scalar(ref lit) => write!(f, "{}", lit.to_string()),
        }
    }
}

impl fmt::Display for ArithmeticExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.alias {
            Some(ref alias) => write!(f, "{} {} {} AS {}", self.left, self.op, self.right, alias),
            None => write!(f, "{} {} {}", self.left, self.op, self.right),
        }
    }
}

named!(pub arithmetic_cast<&[u8], (ArithmeticBase, Option<SqlType>)>,
    alt!(
        do_parse!(
            tag_no_case!("cast") >>
            multispace0 >>
            tag!("(") >>
            multispace0 >>
            // TODO(malte): should be arbitrary expr
            v: arithmetic_base >>
            multispace1 >>
            tag_no_case!("as") >>
            multispace1 >>
            _sign: opt!(terminated!(tag_no_case!("signed"), multispace1)) >>
            typ: type_identifier >>
            multispace0 >>
            tag!(")") >>
            (v, Some(typ))
        ) |
        map!(arithmetic_base, |v| (v, None))
    )
);

// Parse standard math operators.
// TODO(malte): this doesn't currently observe operator precedence.
named!(pub arithmetic_operator<&[u8], ArithmeticOperator>,
    alt!(
          map!(tag!("+"), |_| ArithmeticOperator::Add)
        | map!(tag!("-"), |_| ArithmeticOperator::Subtract)
        | map!(tag!("*"), |_| ArithmeticOperator::Multiply)
        | map!(tag!("/"), |_| ArithmeticOperator::Divide)
    )
);

// Base case for nested arithmetic expressions: column name or literal.
named!(pub arithmetic_base<&[u8], ArithmeticBase>,
    alt!(
          map!(integer_literal, |il| ArithmeticBase::Scalar(il))
        | map!(column_identifier_no_alias, |ci| ArithmeticBase::Column(ci))
    )
);

// Parse simple arithmetic expressions combining literals, and columns and literals.
// TODO(malte): this doesn't currently support nested expressions.
named!(pub arithmetic_expression<&[u8], ArithmeticExpression>,
    do_parse!(
        left: arithmetic_cast >>
        multispace0 >>
        op: arithmetic_operator >>
        multispace0 >>
        right: arithmetic_cast >>
        alias: opt!(as_alias) >>
        (ArithmeticExpression {
            op: op,
            // TODO(malte): discards casts
            left: left.0,
            right: right.0,
            alias: match alias {
                None => None,
                Some(a) => Some(String::from(a)),
            },
        })
    )
);

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

    #[test]
    fn it_parses_arithmetic_expressions() {
        use super::ArithmeticBase::Column as ABColumn;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticOperator::*;
        use column::{FunctionArguments, FunctionExpression};

        let lit_ae = [
            "5 + 42",
            "5+42",
            "5 * 42",
            "5 - 42",
            "5 / 42",
            "2 * 10 AS twenty ",
        ];

        // N.B. trailing space in "5 + foo " is required because `sql_identifier`'s keyword
        // detection requires a follow-up character (in practice, there always is one because we
        // use semicolon-terminated queries).
        let col_lit_ae = [
            "foo+5",
            "foo + 5",
            "5 + foo ",
            "foo * bar AS foobar",
            "MAX(foo)-3333",
        ];

        let expected_lit_ae = [
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Multiply, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Divide, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(
                Multiply,
                Scalar(2.into()),
                Scalar(10.into()),
                Some(String::from("twenty")),
            ),
        ];
        let expected_col_lit_ae = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                Some(String::from("foobar")),
            ),
            ArithmeticExpression::new(
                Subtract,
                ABColumn(Column {
                    name: String::from("max(foo)"),
                    alias: None,
                    table: None,
                    function: Some(Box::new(FunctionExpression::Max(
                        FunctionArguments::Column("foo".into()),
                    ))),
                }),
                Scalar(3333.into()),
                None,
            ),
        ];

        for (i, e) in lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_lit_ae[i]);
        }

        for (i, e) in col_lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_col_lit_ae[i]);
        }
    }

    #[test]
    fn it_displays_arithmetic_expressions() {
        use super::ArithmeticBase::Column as ABColumn;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticOperator::*;

        let expressions = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                None,
            ),
            ArithmeticExpression::new(Divide, Scalar(10.into()), Scalar(2.into()), None),
            ArithmeticExpression::new(
                Add,
                Scalar(10.into()),
                Scalar(2.into()),
                Some(String::from("bob")),
            ),
        ];

        let expected_strings = ["foo + 5", "5 - foo", "foo * bar", "10 / 2", "10 + 2 AS bob"];
        for (i, e) in expressions.iter().enumerate() {
            assert_eq!(expected_strings[i], format!("{}", e));
        }
    }

    #[test]
    fn it_parses_arithmetic_casts() {
        use super::ArithmeticBase::Column as ABColumn;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticOperator::*;

        let exprs = [
            "CAST(`t`.`foo` AS signed int) + CAST(`t`.`bar` AS signed int) ",
            "CAST(5 AS bigint) - foo ",
            "CAST(5 AS bigint) - foo AS 5_minus_foo",
        ];

        // XXX(malte): currently discards the cast and type information!
        let expected = [
            ArithmeticExpression::new(
                Add,
                ABColumn(Column::from("t.foo")),
                ABColumn(Column::from("t.bar")),
                None,
            ),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Subtract,
                Scalar(5.into()),
                ABColumn("foo".into()),
                Some("5_minus_foo".into()),
            ),
        ];

        for (i, e) in exprs.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok(), "{} failed to parse", e);
            assert_eq!(res.unwrap().1, expected[i]);
        }
    }
}
<commit_msg>Update `arithmetic.rs` to use nom v5 functions<commit_after>use nom::character::complete::{multispace0, multispace1};
use std::{fmt, str};

use column::Column;
use common::FieldValueExpression::Arithmetic;
use common::{
    as_alias, column_identifier_no_alias, integer_literal, type_identifier, Literal, SqlType,
};
use nom::branch::alt;
use nom::bytes::complete::{tag, tag_no_case};
use nom::combinator::{map, opt};
use nom::sequence::{terminated, tuple};
use nom::IResult;

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticOperator {
    Add,
    Subtract,
    Multiply,
    Divide,
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ArithmeticBase {
    Column(Column),
    Scalar(Literal),
}

#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ArithmeticExpression {
    pub op: ArithmeticOperator,
    pub left: ArithmeticBase,
    pub right: ArithmeticBase,
    pub alias: Option<String>,
}

impl ArithmeticExpression {
    pub fn new(
        op: ArithmeticOperator,
        left: ArithmeticBase,
        right: ArithmeticBase,
        alias: Option<String>,
    ) -> Self {
        Self {
            op,
            left,
            right,
            alias,
        }
    }
}

impl fmt::Display for ArithmeticOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticOperator::Add => write!(f, "+"),
            ArithmeticOperator::Subtract => write!(f, "-"),
            ArithmeticOperator::Multiply => write!(f, "*"),
            ArithmeticOperator::Divide => write!(f, "/"),
        }
    }
}

impl fmt::Display for ArithmeticBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ArithmeticBase::Column(ref col) => write!(f, "{}", col),
            ArithmeticBase::Scalar(ref lit) => write!(f, "{}", lit.to_string()),
        }
    }
}

impl fmt::Display for ArithmeticExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.alias {
            Some(ref alias) => write!(f, "{} {} {} AS {}", self.left, self.op, self.right, alias),
            None => write!(f, "{} {} {}", self.left, self.op, self.right),
        }
    }
}

fn arithmetic_cast_helper(i: &[u8]) -> IResult<&[u8], (ArithmeticBase, Option<SqlType>)> {
    let (remaining_input, (_, _, _, _, a_base, _, _, _, _sign, sql_type, _, _)) = tuple((
        tag_no_case("cast"),
        multispace0,
        tag("("),
        multispace0,
        // TODO(malte): should be arbitrary expr
        arithmetic_base,
        multispace1,
        tag_no_case("as"),
        multispace1,
        opt(terminated(tag_no_case("signed"), multispace1)),
        type_identifier,
        multispace0,
        tag(")"),
    ))(i)?;

    Ok((remaining_input, (a_base, Some(sql_type))))
}

pub fn arithmetic_cast(i: &[u8]) -> IResult<&[u8], (ArithmeticBase, Option<SqlType>)> {
    alt((arithmetic_cast_helper, map(arithmetic_base, |v| (v, None))))(i)
}

// Parse standard math operators.
// TODO(malte): this doesn't currently observe operator precedence.
pub fn arithmetic_operator(i: &[u8]) -> IResult<&[u8], ArithmeticOperator> {
    alt((
        map(tag("+"), |_| ArithmeticOperator::Add),
        map(tag("-"), |_| ArithmeticOperator::Subtract),
        map(tag("*"), |_| ArithmeticOperator::Multiply),
        map(tag("/"), |_| ArithmeticOperator::Divide),
    ))(i)
}

// Base case for nested arithmetic expressions: column name or literal.
pub fn arithmetic_base(i: &[u8]) -> IResult<&[u8], ArithmeticBase> {
    alt((
        map(integer_literal, |il| ArithmeticBase::Scalar(il)),
        map(column_identifier_no_alias, |ci| ArithmeticBase::Column(ci)),
    ))(i)
}

// Parse simple arithmetic expressions combining literals, and columns and literals.
// TODO(malte): this doesn't currently support nested expressions.
pub fn arithmetic_expression(i: &[u8]) -> IResult<&[u8], ArithmeticExpression> {
    let (remaining_input, (left, _, op, _, right, opt_alias)) = tuple((
        arithmetic_cast,
        multispace0,
        arithmetic_operator,
        multispace0,
        arithmetic_cast,
        opt(as_alias),
    ))(i)?;

    let alias = match opt_alias {
        None => None,
        Some(a) => Some(String::from(a)),
    };

    Ok((
        remaining_input,
        ArithmeticExpression {
            left: left.0,
            right: right.0,
            op,
            alias,
        },
    ))
}

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

    #[test]
    fn it_parses_arithmetic_expressions() {
        use super::ArithmeticBase::Column as ABColumn;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticOperator::*;
        use column::{FunctionArguments, FunctionExpression};

        let lit_ae = [
            "5 + 42",
            "5+42",
            "5 * 42",
            "5 - 42",
            "5 / 42",
            "2 * 10 AS twenty ",
        ];

        // N.B. trailing space in "5 + foo " is required because `sql_identifier`'s keyword
        // detection requires a follow-up character (in practice, there always is one because we
        // use semicolon-terminated queries).
        let col_lit_ae = [
            "foo+5",
            "foo + 5",
            "5 + foo ",
            "foo * bar AS foobar",
            "MAX(foo)-3333",
        ];

        let expected_lit_ae = [
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Multiply, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(Divide, Scalar(5.into()), Scalar(42.into()), None),
            ArithmeticExpression::new(
                Multiply,
                Scalar(2.into()),
                Scalar(10.into()),
                Some(String::from("twenty")),
            ),
        ];
        let expected_col_lit_ae = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Add, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                Some(String::from("foobar")),
            ),
            ArithmeticExpression::new(
                Subtract,
                ABColumn(Column {
                    name: String::from("max(foo)"),
                    alias: None,
                    table: None,
                    function: Some(Box::new(FunctionExpression::Max(
                        FunctionArguments::Column("foo".into()),
                    ))),
                }),
                Scalar(3333.into()),
                None,
            ),
        ];

        for (i, e) in lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_lit_ae[i]);
        }

        for (i, e) in col_lit_ae.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok());
            assert_eq!(res.unwrap().1, expected_col_lit_ae[i]);
        }
    }

    #[test]
    fn it_displays_arithmetic_expressions() {
        use super::ArithmeticBase::Column as ABColumn;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticOperator::*;

        let expressions = [
            ArithmeticExpression::new(Add, ABColumn("foo".into()), Scalar(5.into()), None),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Multiply,
                ABColumn("foo".into()),
                ABColumn("bar".into()),
                None,
            ),
            ArithmeticExpression::new(Divide, Scalar(10.into()), Scalar(2.into()), None),
            ArithmeticExpression::new(
                Add,
                Scalar(10.into()),
                Scalar(2.into()),
                Some(String::from("bob")),
            ),
        ];

        let expected_strings = ["foo + 5", "5 - foo", "foo * bar", "10 / 2", "10 + 2 AS bob"];
        for (i, e) in expressions.iter().enumerate() {
            assert_eq!(expected_strings[i], format!("{}", e));
        }
    }

    #[test]
    fn it_parses_arithmetic_casts() {
        use super::ArithmeticBase::Column as ABColumn;
        use super::ArithmeticBase::Scalar;
        use super::ArithmeticOperator::*;

        let exprs = [
            "CAST(`t`.`foo` AS signed int) + CAST(`t`.`bar` AS signed int) ",
            "CAST(5 AS bigint) - foo ",
            "CAST(5 AS bigint) - foo AS 5_minus_foo",
        ];

        // XXX(malte): currently discards the cast and type information!
        let expected = [
            ArithmeticExpression::new(
                Add,
                ABColumn(Column::from("t.foo")),
                ABColumn(Column::from("t.bar")),
                None,
            ),
            ArithmeticExpression::new(Subtract, Scalar(5.into()), ABColumn("foo".into()), None),
            ArithmeticExpression::new(
                Subtract,
                Scalar(5.into()),
                ABColumn("foo".into()),
                Some("5_minus_foo".into()),
            ),
        ];

        for (i, e) in exprs.iter().enumerate() {
            let res = arithmetic_expression(e.as_bytes());
            assert!(res.is_ok(), "{} failed to parse", e);
            assert_eq!(res.unwrap().1, expected[i]);
        }
    }
}
<|endoftext|>


<commit_before>use url::Url;
use hyper::{self, Client};
use rustc_serialize::json::{self, Json, Object};

use errors::WeChatError;

pub struct WeChatClient {
    pub appid: String,
    pub secret: String,
    pub access_token: String,
}

impl WeChatClient {
    pub fn new(appid: &str, secret: &str) -> WeChatClient {
        WeChatClient {
            appid: appid.to_owned(),
            secret: secret.to_owned(),
            access_token: "".to_owned(),
        }
    }

    pub fn with_access_token(appid: &str, secret: &str, access_token: &str) -> WeChatClient {
        WeChatClient {
            appid: appid.to_owned(),
            secret: secret.to_owned(),
            access_token: access_token.to_owned(),
        }
    }

    pub fn post(&self, url: &str, params: Vec<(&str, &str)>, data: &Object) -> Result<Json, WeChatError> {
        let mut http_url = Url::parse(url).unwrap();
        http_url.set_query_from_pairs(params.into_iter());
        let body = match json::encode(data) {
            Ok(text) => text,
            Err(_) => "".to_owned(),
        };
        let mut client = Client::new();
        let mut res = match client.post(http_url).body(&body).send() {
            Ok(_res) => _res,
            Err(_) => { return Err(WeChatError::ClientError { errcode: -1, errmsg: "".to_owned() }); }
        };
        if res.status != hyper::Ok {
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Request status error".to_owned() })
        }
        let obj = match Json::from_reader(&mut res) {
            Ok(decoded) => { decoded },
            Err(_) => { return Err(WeChatError::ClientError { errcode: -3, errmsg: "Json decode error".to_owned() }); }
        };
        Ok(obj)
    }

    pub fn get(&self, url: &str, params: Vec<(&str, &str)>) -> Result<Json, WeChatError> {
        let mut http_url = Url::parse(url).unwrap();
        http_url.set_query_from_pairs(params.into_iter());
        let mut client = Client::new();
        let mut res = match client.post(http_url).send() {
            Ok(_res) => _res,
            Err(_) => { return Err(WeChatError::ClientError { errcode: -1, errmsg: "".to_owned() }); }
        };
        if res.status != hyper::Ok {
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Request status error".to_owned() })
        }
        let obj = match Json::from_reader(&mut res) {
            Ok(decoded) => { decoded },
            Err(_) => { return Err(WeChatError::ClientError { errcode: -3, errmsg: "Json decode error".to_owned() }); }
        };
        Ok(obj)
    }
}<commit_msg>Append access_token in querystring if possible<commit_after>use url::Url;
use hyper::{self, Client};
use rustc_serialize::json::{self, Json, Object};

use errors::WeChatError;

pub struct WeChatClient {
    pub appid: String,
    pub secret: String,
    pub access_token: String,
}

impl WeChatClient {
    pub fn new(appid: &str, secret: &str) -> WeChatClient {
        WeChatClient {
            appid: appid.to_owned(),
            secret: secret.to_owned(),
            access_token: "".to_owned(),
        }
    }

    pub fn with_access_token(appid: &str, secret: &str, access_token: &str) -> WeChatClient {
        WeChatClient {
            appid: appid.to_owned(),
            secret: secret.to_owned(),
            access_token: access_token.to_owned(),
        }
    }

    pub fn post(&self, url: &str, params: Vec<(&str, &str)>, data: &Object) -> Result<Json, WeChatError> {
        let mut querys = params.clone();
        let mut http_url = Url::parse(url).unwrap();
        if !self.access_token.is_empty() {
            querys.push(("access_token", &self.access_token));
        }
        http_url.set_query_from_pairs(querys.into_iter());
        let body = match json::encode(data) {
            Ok(text) => text,
            Err(_) => "".to_owned(),
        };
        let mut client = Client::new();
        let mut res = match client.post(http_url).body(&body).send() {
            Ok(_res) => _res,
            Err(_) => { return Err(WeChatError::ClientError { errcode: -1, errmsg: "".to_owned() }); }
        };
        if res.status != hyper::Ok {
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Request status error".to_owned() })
        }
        let obj = match Json::from_reader(&mut res) {
            Ok(decoded) => { decoded },
            Err(_) => { return Err(WeChatError::ClientError { errcode: -3, errmsg: "Json decode error".to_owned() }); }
        };
        Ok(obj)
    }

    pub fn get(&self, url: &str, params: Vec<(&str, &str)>) -> Result<Json, WeChatError> {
        let mut querys = params.clone();
        let mut http_url = Url::parse(url).unwrap();
        if !self.access_token.is_empty() {
            querys.push(("access_token", &self.access_token));
        }
        http_url.set_query_from_pairs(querys.into_iter());
        let mut client = Client::new();
        let mut res = match client.post(http_url).send() {
            Ok(_res) => _res,
            Err(_) => { return Err(WeChatError::ClientError { errcode: -1, errmsg: "".to_owned() }); }
        };
        if res.status != hyper::Ok {
            return Err(WeChatError::ClientError { errcode: -2, errmsg: "Request status error".to_owned() })
        }
        let obj = match Json::from_reader(&mut res) {
            Ok(decoded) => { decoded },
            Err(_) => { return Err(WeChatError::ClientError { errcode: -3, errmsg: "Json decode error".to_owned() }); }
        };
        Ok(obj)
    }
}<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! The client-side abstraction for multipart requests. Enabled with the `client` feature.
//!
//! Use this when sending POST requests with files to a server.
use mime::Mime;

use std::borrow::Cow;
use std::fs::File;
use std::io;
use std::io::prelude::*;

use std::path::Path;

#[cfg(feature = "hyper")]
pub mod hyper;

pub mod lazy;

mod sized;

pub use self::sized::SizedRequest;

const BOUNDARY_LEN: usize = 16;

macro_rules! map_self {
    ($selff:expr, $try:expr) => (
        match $try {
            Ok(_) => Ok($selff),
            Err(err) => Err(err.into()),
        }
    )
}

/// The entry point of the client-side multipart API.
///
/// Though they perform I/O, the `.write_*()` methods do not return `io::Result<_>` in order to
/// facilitate method chaining. Upon the first error, all subsequent API calls will be no-ops until
/// `.send()` is called, at which point the error will be reported.
pub struct Multipart<S> {
    writer: MultipartWriter<'static, S>,
}

impl Multipart<()> {
    /// Create a new `Multipart` to wrap a request.
    ///
    /// ## Returns Error
    /// If `req.open_stream()` returns an error.
    pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Stream>, R::Error> {
        let (boundary, stream) = open_stream(req, None)?;

        Ok(Multipart {
            writer: MultipartWriter::new(stream, boundary),
        })
    }
}

impl<S: HttpStream> Multipart<S> {
    /// Write a text field to this multipart request.
    /// `name` and `val` can be either owned `String` or `&str`.
    ///
    /// ## Errors
    /// If something went wrong with the HTTP stream.
    pub fn write_text<N: AsRef<str>, V: AsRef<str>>(&mut self, name: N, val: V) -> Result<&mut Self, S::Error> {
        map_self!(self, self.writer.write_text(name.as_ref(), val.as_ref()))
    }

    /// Open a file pointed to by `path` and write its contents to the multipart request,
    /// supplying its filename and guessing its `Content-Type` from its extension.
    ///
    /// If you want to set these values manually, or use another type that implements `Read`,
    /// use `.write_stream()`.
    ///
    /// `name` can be either `String` or `&str`, and `path` can be `PathBuf` or `&Path`.
    ///
    /// ## Errors
    /// If there was a problem opening the file (was a directory or didn't exist),
    /// or if something went wrong with the HTTP stream.
    pub fn write_file<N: AsRef<str>, P: AsRef<Path>>(&mut self, name: N, path: P) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();
        let path = path.as_ref();

        map_self!(self, self.writer.write_file(name, path))
    }

    /// Write a byte stream to the multipart request as a file field, supplying `filename` if given,
    /// and `content_type` if given or `"application/octet-stream"` if not.
    ///
    /// `name` can be either `String` or `&str`, and `read` can take the `Read` by-value or
    /// with an `&mut` borrow.
    ///
    /// ## Warning
    /// The given `Read` **must** be able to read to EOF (end of file/no more data), meaning
    /// `Read::read()` returns `Ok(0)`. If it never returns EOF it will be read to infinity
    /// and the request will never be completed.
    ///
    /// When using `SizedRequest` this also can cause out-of-control memory usage as the
    /// multipart data has to be written to an in-memory buffer so its size can be calculated.
    ///
    /// Use `Read::take()` if you wish to send data from a `Read`
    /// that will never return EOF otherwise.
    ///
    /// ## Errors
    /// If the reader returned an error, or if something went wrong with the HTTP stream.
    // RFC: How to format this declaration?
    pub fn write_stream<N: AsRef<str>, St: Read>(
        &mut self, name: N, stream: &mut St, filename: Option<&str>, content_type: Option<Mime>
    ) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();

        map_self!(self, self.writer.write_stream(stream, name, filename, content_type))
    }

    /// Finalize the request and return the response from the server, or the last error if set.
    pub fn send(self) -> Result<S::Response, S::Error> {
        self.writer.finish().map_err(io::Error::into).and_then(|body| body.finish())
    }
}

impl<R: HttpRequest> Multipart<SizedRequest<R>>
where <R::Stream as HttpStream>::Error: From<R::Error> {
    /// Create a new `Multipart` using the `SizedRequest` wrapper around `req`.
    pub fn from_request_sized(req: R) -> Result<Self, R::Error> {
        Multipart::from_request(SizedRequest::from_request(req))
    }
}

/// A trait describing an HTTP request that can be used to send multipart data.
pub trait HttpRequest {
    /// The HTTP stream type that can be opend by this request, to which the multipart data will be
    /// written.
    type Stream: HttpStream;
    /// The error type for this request.
    /// Must be compatible with `io::Error` as well as `Self::HttpStream::Error`
    type Error: From<io::Error> + Into<<Self::Stream as HttpStream>::Error>;

    /// Set the `Content-Type` header to `multipart/form-data` and supply the `boundary` value.
    /// If `content_len` is given, set the `Content-Length` header to its value.
    ///
    /// Return `true` if any and all sanity checks passed and the stream is ready to be opened,
    /// or `false` otherwise.
    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool;

    /// Open the request stream and return it or any error otherwise.
    fn open_stream(self) -> Result<Self::Stream, Self::Error>;
}

/// A trait describing an open HTTP stream that can be written to.
pub trait HttpStream: Write {
    /// The request type that opened this stream.
    type Request: HttpRequest;
    /// The response type that will be returned after the request is completed.
    type Response;
    /// The error type for this stream.
    /// Must be compatible with `io::Error` as well as `Self::Request::Error`.
    type Error: From<io::Error> + From<<Self::Request as HttpRequest>::Error>;

    /// Finalize and close the stream and return the response object, or any error otherwise.
    fn finish(self) -> Result<Self::Response, Self::Error>;
}

impl HttpRequest for () {
    type Stream = io::Sink;
    type Error = io::Error;

    fn apply_headers(&mut self, _: &str, _: Option<u64>) -> bool { true }
    fn open_stream(self) -> Result<Self::Stream, Self::Error> { Ok(io::sink()) }
}

impl HttpStream for io::Sink {
    type Request = ();
    type Response = ();
    type Error = io::Error;

    fn finish(self) -> Result<Self::Response, Self::Error> { Ok(()) }
}

fn gen_boundary() -> String {
    ::random_alphanumeric(BOUNDARY_LEN)
}

fn open_stream<R: HttpRequest>(mut req: R, content_len: Option<u64>) -> Result<(String, R::Stream), R::Error> {
    let boundary = gen_boundary();
    req.apply_headers(&boundary, content_len);
    req.open_stream().map(|stream| (boundary, stream))
}

struct MultipartWriter<'a, W> {
    inner: W,
    boundary: Cow<'a, str>,
    data_written: bool,
}

impl<'a, W: Write> MultipartWriter<'a, W> {
    fn new<B: Into<Cow<'a, str>>>(inner: W, boundary: B) -> Self {
        MultipartWriter {
            inner,
            boundary: boundary.into(),
            data_written: false,
        }
    }

    fn write_boundary(&mut self) -> io::Result<()> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        write!(self.inner, "--{}\r\n", self.boundary)
    }

    fn write_text(&mut self, name: &str, text: &str) -> io::Result<()> {
        chain_result! {
            self.write_field_headers(name, None, None),
            self.inner.write_all(text.as_bytes())
        }
    }

    fn write_file(&mut self, name: &str, path: &Path) -> io::Result<()> {
        let (content_type, filename) = mime_filename(path);
        let mut file = File::open(path)?;
        self.write_stream(&mut file, name, filename, Some(content_type))
    }

    fn write_stream<S: Read>(&mut self, stream: &mut S, name: &str, filename: Option<&str>, content_type: Option<Mime>) -> io::Result<()> {
        // This is necessary to make sure it is interpreted as a file on the server end.
        let content_type = Some(content_type.unwrap_or_else(::mime_guess::octet_stream));

        chain_result! {
            self.write_field_headers(name, filename, content_type),
            io::copy(stream, &mut self.inner),
            Ok(())
        }
    }

    fn write_field_headers(&mut self, name: &str, filename: Option<&str>, content_type: Option<Mime>)
    -> io::Result<()> {
        chain_result! {
            // Write the first boundary, or the boundary for the previous field.
            self.write_boundary(),
            { self.data_written = true; Ok(()) },
            write!(self.inner, "Content-Disposition: form-data; name=\"{}\"", name),
            filename.map(|filename| write!(self.inner, "; filename=\"{}\"", filename))
                .unwrap_or(Ok(())),
            content_type.map(|content_type| write!(self.inner, "\r\nContent-Type: {}", content_type))
                .unwrap_or(Ok(())),
            self.inner.write_all(b"\r\n\r\n")
        }
    }

    fn finish(mut self) -> io::Result<W> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        // always write the closing boundary, even for empty bodies
        write!(self.inner, "--{}--", self.boundary)?;
        Ok(self.inner)
    }
}

fn mime_filename(path: &Path) -> (Mime, Option<&str>) {
    let content_type = ::mime_guess::guess_mime_type(path);
    let filename = opt_filename(path);
    (content_type, filename)
}

fn opt_filename(path: &Path) -> Option<&str> {
    path.file_name().and_then(|filename| filename.to_str())
}
<commit_msg>tack on final \r\n<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! The client-side abstraction for multipart requests. Enabled with the `client` feature.
//!
//! Use this when sending POST requests with files to a server.
use mime::Mime;

use std::borrow::Cow;
use std::fs::File;
use std::io;
use std::io::prelude::*;

use std::path::Path;

#[cfg(feature = "hyper")]
pub mod hyper;

pub mod lazy;

mod sized;

pub use self::sized::SizedRequest;

const BOUNDARY_LEN: usize = 16;

macro_rules! map_self {
    ($selff:expr, $try:expr) => (
        match $try {
            Ok(_) => Ok($selff),
            Err(err) => Err(err.into()),
        }
    )
}

/// The entry point of the client-side multipart API.
///
/// Though they perform I/O, the `.write_*()` methods do not return `io::Result<_>` in order to
/// facilitate method chaining. Upon the first error, all subsequent API calls will be no-ops until
/// `.send()` is called, at which point the error will be reported.
pub struct Multipart<S> {
    writer: MultipartWriter<'static, S>,
}

impl Multipart<()> {
    /// Create a new `Multipart` to wrap a request.
    ///
    /// ## Returns Error
    /// If `req.open_stream()` returns an error.
    pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Stream>, R::Error> {
        let (boundary, stream) = open_stream(req, None)?;

        Ok(Multipart {
            writer: MultipartWriter::new(stream, boundary),
        })
    }
}

impl<S: HttpStream> Multipart<S> {
    /// Write a text field to this multipart request.
    /// `name` and `val` can be either owned `String` or `&str`.
    ///
    /// ## Errors
    /// If something went wrong with the HTTP stream.
    pub fn write_text<N: AsRef<str>, V: AsRef<str>>(&mut self, name: N, val: V) -> Result<&mut Self, S::Error> {
        map_self!(self, self.writer.write_text(name.as_ref(), val.as_ref()))
    }

    /// Open a file pointed to by `path` and write its contents to the multipart request,
    /// supplying its filename and guessing its `Content-Type` from its extension.
    ///
    /// If you want to set these values manually, or use another type that implements `Read`,
    /// use `.write_stream()`.
    ///
    /// `name` can be either `String` or `&str`, and `path` can be `PathBuf` or `&Path`.
    ///
    /// ## Errors
    /// If there was a problem opening the file (was a directory or didn't exist),
    /// or if something went wrong with the HTTP stream.
    pub fn write_file<N: AsRef<str>, P: AsRef<Path>>(&mut self, name: N, path: P) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();
        let path = path.as_ref();

        map_self!(self, self.writer.write_file(name, path))
    }

    /// Write a byte stream to the multipart request as a file field, supplying `filename` if given,
    /// and `content_type` if given or `"application/octet-stream"` if not.
    ///
    /// `name` can be either `String` or `&str`, and `read` can take the `Read` by-value or
    /// with an `&mut` borrow.
    ///
    /// ## Warning
    /// The given `Read` **must** be able to read to EOF (end of file/no more data), meaning
    /// `Read::read()` returns `Ok(0)`. If it never returns EOF it will be read to infinity
    /// and the request will never be completed.
    ///
    /// When using `SizedRequest` this also can cause out-of-control memory usage as the
    /// multipart data has to be written to an in-memory buffer so its size can be calculated.
    ///
    /// Use `Read::take()` if you wish to send data from a `Read`
    /// that will never return EOF otherwise.
    ///
    /// ## Errors
    /// If the reader returned an error, or if something went wrong with the HTTP stream.
    // RFC: How to format this declaration?
    pub fn write_stream<N: AsRef<str>, St: Read>(
        &mut self, name: N, stream: &mut St, filename: Option<&str>, content_type: Option<Mime>
    ) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();

        map_self!(self, self.writer.write_stream(stream, name, filename, content_type))
    }

    /// Finalize the request and return the response from the server, or the last error if set.
    pub fn send(self) -> Result<S::Response, S::Error> {
        self.writer.finish().map_err(io::Error::into).and_then(|body| body.finish())
    }
}

impl<R: HttpRequest> Multipart<SizedRequest<R>>
where <R::Stream as HttpStream>::Error: From<R::Error> {
    /// Create a new `Multipart` using the `SizedRequest` wrapper around `req`.
    pub fn from_request_sized(req: R) -> Result<Self, R::Error> {
        Multipart::from_request(SizedRequest::from_request(req))
    }
}

/// A trait describing an HTTP request that can be used to send multipart data.
pub trait HttpRequest {
    /// The HTTP stream type that can be opend by this request, to which the multipart data will be
    /// written.
    type Stream: HttpStream;
    /// The error type for this request.
    /// Must be compatible with `io::Error` as well as `Self::HttpStream::Error`
    type Error: From<io::Error> + Into<<Self::Stream as HttpStream>::Error>;

    /// Set the `Content-Type` header to `multipart/form-data` and supply the `boundary` value.
    /// If `content_len` is given, set the `Content-Length` header to its value.
    ///
    /// Return `true` if any and all sanity checks passed and the stream is ready to be opened,
    /// or `false` otherwise.
    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool;

    /// Open the request stream and return it or any error otherwise.
    fn open_stream(self) -> Result<Self::Stream, Self::Error>;
}

/// A trait describing an open HTTP stream that can be written to.
pub trait HttpStream: Write {
    /// The request type that opened this stream.
    type Request: HttpRequest;
    /// The response type that will be returned after the request is completed.
    type Response;
    /// The error type for this stream.
    /// Must be compatible with `io::Error` as well as `Self::Request::Error`.
    type Error: From<io::Error> + From<<Self::Request as HttpRequest>::Error>;

    /// Finalize and close the stream and return the response object, or any error otherwise.
    fn finish(self) -> Result<Self::Response, Self::Error>;
}

impl HttpRequest for () {
    type Stream = io::Sink;
    type Error = io::Error;

    fn apply_headers(&mut self, _: &str, _: Option<u64>) -> bool { true }
    fn open_stream(self) -> Result<Self::Stream, Self::Error> { Ok(io::sink()) }
}

impl HttpStream for io::Sink {
    type Request = ();
    type Response = ();
    type Error = io::Error;

    fn finish(self) -> Result<Self::Response, Self::Error> { Ok(()) }
}

fn gen_boundary() -> String {
    ::random_alphanumeric(BOUNDARY_LEN)
}

fn open_stream<R: HttpRequest>(mut req: R, content_len: Option<u64>) -> Result<(String, R::Stream), R::Error> {
    let boundary = gen_boundary();
    req.apply_headers(&boundary, content_len);
    req.open_stream().map(|stream| (boundary, stream))
}

struct MultipartWriter<'a, W> {
    inner: W,
    boundary: Cow<'a, str>,
    data_written: bool,
}

impl<'a, W: Write> MultipartWriter<'a, W> {
    fn new<B: Into<Cow<'a, str>>>(inner: W, boundary: B) -> Self {
        MultipartWriter {
            inner,
            boundary: boundary.into(),
            data_written: false,
        }
    }

    fn write_boundary(&mut self) -> io::Result<()> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        write!(self.inner, "--{}\r\n", self.boundary)
    }

    fn write_text(&mut self, name: &str, text: &str) -> io::Result<()> {
        chain_result! {
            self.write_field_headers(name, None, None),
            self.inner.write_all(text.as_bytes())
        }
    }

    fn write_file(&mut self, name: &str, path: &Path) -> io::Result<()> {
        let (content_type, filename) = mime_filename(path);
        let mut file = File::open(path)?;
        self.write_stream(&mut file, name, filename, Some(content_type))
    }

    fn write_stream<S: Read>(&mut self, stream: &mut S, name: &str, filename: Option<&str>, content_type: Option<Mime>) -> io::Result<()> {
        // This is necessary to make sure it is interpreted as a file on the server end.
        let content_type = Some(content_type.unwrap_or_else(::mime_guess::octet_stream));

        chain_result! {
            self.write_field_headers(name, filename, content_type),
            io::copy(stream, &mut self.inner),
            Ok(())
        }
    }

    fn write_field_headers(&mut self, name: &str, filename: Option<&str>, content_type: Option<Mime>)
    -> io::Result<()> {
        chain_result! {
            // Write the first boundary, or the boundary for the previous field.
            self.write_boundary(),
            { self.data_written = true; Ok(()) },
            write!(self.inner, "Content-Disposition: form-data; name=\"{}\"", name),
            filename.map(|filename| write!(self.inner, "; filename=\"{}\"", filename))
                .unwrap_or(Ok(())),
            content_type.map(|content_type| write!(self.inner, "\r\nContent-Type: {}", content_type))
                .unwrap_or(Ok(())),
            self.inner.write_all(b"\r\n\r\n")
        }
    }

    fn finish(mut self) -> io::Result<W> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        // always write the closing boundary, even for empty bodies
        write!(self.inner, "--{}--\r\n", self.boundary)?;
        Ok(self.inner)
    }
}

fn mime_filename(path: &Path) -> (Mime, Option<&str>) {
    let content_type = ::mime_guess::guess_mime_type(path);
    let filename = opt_filename(path);
    (content_type, filename)
}

fn opt_filename(path: &Path) -> Option<&str> {
    path.file_name().and_then(|filename| filename.to_str())
}
<|endoftext|>