<commit_before>use std::convert::identity;

use futures::{future, stream, Future, Stream};
use log::{error, warn};
use rusoto_core::Region;
use rusoto_sqs::{
    DeleteMessageBatchRequest, DeleteMessageBatchRequestEntry, Message, ReceiveMessageRequest,
    Sqs as _, SqsClient,
};

pub fn sqs_receiver(
    queue_url: String,
    queue_region: Region,
) -> impl Stream<Item = Message, Error = ()> {
    // set up receiver client and receive request template
    let receive_client = SqsClient::new(queue_region.clone());
    let receive_request = ReceiveMessageRequest {
        queue_url: queue_url.clone(),
        wait_time_seconds: Some(10),
        max_number_of_messages: Some(10),
        ..Default::default()
    };
    // set up deleter client and delete request template
    let delete_client = SqsClient::new(queue_region.clone());
    let delete_request = DeleteMessageBatchRequest {
        queue_url: queue_url.clone(),
        ..Default::default()
    };

    // repeatedly poll for messages
    stream::unfold((), move |()| {
        Some(
            receive_client
                .receive_message(receive_request.clone())
                .map(|receive_result| (receive_result, ())),
        )
    })
    // log the errors and skip the errors
    .map_err(|e| error!("failed to receive message: {}", e))
    .then(|result| future::ok(result.ok()))
    .filter_map(identity)
    // delete messages from the queue
    .and_then(
        move |receive_result| -> Box<dyn Future<Item = Vec<Message>, Error = ()> + Send> {
            let messages = receive_result.messages.unwrap_or_else(Vec::new);

            if messages.len() > 0 {
                // prepare delete request
                let delete_request = DeleteMessageBatchRequest {
                    entries: messages
                        .iter()
                        .filter_map(|message| message.receipt_handle.clone())
                        .enumerate()
                        .map(|(index, receipt_handle)| DeleteMessageBatchRequestEntry {
                            id: index.to_string(),
                            receipt_handle,
                        })
                        .collect(),
                    ..delete_request.clone()
                };

                // send delete request
                Box::new(delete_client.delete_message_batch(delete_request).then(
                    |delete_request_result| {
                        // log errors, if any
                        match delete_request_result {
                            Ok(ref delete_result) if delete_result.failed.len() > 0 => {
                                warn!("failed to delete some messages: {:?}", delete_result.failed);
                            }
                            Ok(_) => (),
                            Err(e) => {
                                error!("message delete request failed: {}", e);
                            }
                        }

                        // forward messages
                        future::ok(messages)
                    },
                ))
            } else {
                // timeout, no messages received
                Box::new(future::ok(messages))
            }
        },
    )
    // flatten messages to return one by one
    .map(|messages| stream::iter_ok(messages))
    .flatten()
}
<commit_msg>replace box with either<commit_after>use std::convert::identity;

use futures::{future, stream, Future, Stream};
use log::{error, warn};
use rusoto_core::Region;
use rusoto_sqs::{
    DeleteMessageBatchRequest, DeleteMessageBatchRequestEntry, Message, ReceiveMessageRequest,
    Sqs as _, SqsClient,
};

pub fn sqs_receiver(
    queue_url: String,
    queue_region: Region,
) -> impl Stream<Item = Message, Error = ()> {
    // set up receiver client and receive request template
    let receive_client = SqsClient::new(queue_region.clone());
    let receive_request = ReceiveMessageRequest {
        queue_url: queue_url.clone(),
        wait_time_seconds: Some(10),
        max_number_of_messages: Some(10),
        ..Default::default()
    };
    // set up deleter client and delete request template
    let delete_client = SqsClient::new(queue_region.clone());
    let delete_request = DeleteMessageBatchRequest {
        queue_url: queue_url.clone(),
        ..Default::default()
    };

    // repeatedly poll for messages
    stream::unfold((), move |()| {
        Some(
            receive_client
                .receive_message(receive_request.clone())
                .map(|receive_result| (receive_result, ())),
        )
    })
    // log the errors and skip the errors
    .map_err(|e| error!("failed to receive message: {}", e))
    .then(|result| future::ok(result.ok()))
    .filter_map(identity)
    // delete messages from the queue
    .and_then(move |receive_result| {
        let messages = receive_result.messages.unwrap_or_else(Vec::new);

        if messages.len() > 0 {
            // prepare delete request
            let delete_request = DeleteMessageBatchRequest {
                entries: messages
                    .iter()
                    .filter_map(|message| message.receipt_handle.clone())
                    .enumerate()
                    .map(|(index, receipt_handle)| DeleteMessageBatchRequestEntry {
                        id: index.to_string(),
                        receipt_handle,
                    })
                    .collect(),
                ..delete_request.clone()
            };

            // send delete request
            future::Either::A(delete_client.delete_message_batch(delete_request).then(
                |delete_request_result| {
                    // log errors, if any
                    match delete_request_result {
                        Ok(ref delete_result) if delete_result.failed.len() > 0 => {
                            warn!("failed to delete some messages: {:?}", delete_result.failed);
                        }
                        Ok(_) => (),
                        Err(e) => {
                            error!("message delete request failed: {}", e);
                        }
                    }

                    // forward messages
                    future::ok(messages)
                },
            ))
        } else {
            // timeout, no messages received
            future::Either::B(future::ok(messages))
        }
    })
    // flatten messages to return one by one
    .map(|messages| stream::iter_ok(messages))
    .flatten()
}
<|endoftext|>


<commit_before>use super::*;
use wtools::error::BasicError;
use wca::command::Command;
use wca::instruction::Instruction;
use wca::string::parse_request::OpType::Primitive;

//

fn commands_form() -> std::collections::HashMap< String, Command >
{
  let help_command : Command = wca::CommandOptions::default()
  .hint( "Get help." )
  .long_hint( "Get help for command [command]" )
  .phrase( ".help" )
  .routine( &| _i : &Instruction | { println!( "this is help" ); Ok( () ) } )
  .form();
  let list_command : Command = wca::CommandOptions::default()
  .hint( "Get list." )
  .long_hint( "Get list of" )
  .phrase( ".list" )
  .subject_hint( "some subject" )
  .routine( &| _i : &Instruction | { println!( "this is list" ); Ok( () ) } )
  .form();
  let err_command : Command = wca::CommandOptions::default()
  .hint( "Error." )
  .long_hint( "Throw error" )
  .phrase( ".error" )
  .routine( &| _i : &Instruction | { Err( BasicError::new( "err" ) ) } )
  .form();

  let commands : std::collections::HashMap< String, Command > = std::collections::HashMap::from
  ([
    ( ".help".to_string(), help_command ),
    ( ".list".to_string(), list_command ),
    ( ".error".to_string(), err_command ),
  ]);
  commands
}

tests_impls!
{
  fn basic()
  {
    let ca = wca::commands_aggregator()
    .form();
    a_id!( ca.base_path, None );
    a_id!( ca.command_prefix, "".to_string() );
    a_id!( ca.delimeter, vec![ ".".to_string(), " ".to_string() ] );
    a_id!( ca.command_explicit_delimeter, ";".to_string() );
    a_id!( ca.command_implicit_delimeter, " ".to_string() );
    a_id!( ca.commands_explicit_delimiting, true );
    a_id!( ca.commands_implicit_delimiting, false );
    a_id!( ca.properties_map_parsing, false );
    a_id!( ca.several_values, true );
    a_id!( ca.with_help, true );
    a_id!( ca.changing_exit_code, true );
    a_id!( ca.commands, std::collections::HashMap::new() );
  }

  fn instruction_perform_basic()
  {
    /* no commands in aggregator */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .form();
    let got = ca.instruction_perform( ".help" );
    a_id!( got, Ok( () ) );

    /* command returns Ok */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.instruction_perform( ".help" );
    a_id!( got, Ok( () ) );

    /* command returns Err */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.instruction_perform( ".error" );
    a_id!( got, Err( BasicError::new( "err" ) ) );
  }

  //

  fn instructions_parse_basic()
  {
    let ca = wca::commands_aggregator()
    .form();

    /* */

    /* empty program */
    let got = ca.instructions_parse( "" );
    a_id!( got, vec![] );

    /* */

    /* single command without subject and map */
    let got = ca.instructions_parse( ".help" );
    let instruction = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction ] );

    /* single command with subject */
    let got = ca.instructions_parse( ".help command" );
    let instruction = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction ] );

    /* single command with subject and map */
    let got = ca.instructions_parse( ".help command v:3" );
    let instruction = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "3".to_string() ) ) ]),
    };
    a_id!( got, vec![ instruction ] );

    /* */

    /* two commands without subject and map, explicit delimeter */
    let got = ca.instructions_parse( ".help ; .version" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject, explicit delimeter */
    let got = ca.instructions_parse( ".help command ; .version delta" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject and map, explicit delimeter */
    let got = ca.instructions_parse( ".help command v:3 ; .version delta n:5" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "3".to_string() ) ) ]),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::from([ ( "n".to_string(), Primitive( "5".to_string() ) ) ]),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* */

    /* two commands without subject and map, implicit delimeter */
    let got = ca.instructions_parse( ".help .version" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject, implicit delimeter */
    let got = ca.instructions_parse( ".help command .version delta" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject and map, implicit delimeter */
    let got = ca.instructions_parse( ".help command v:3 .version delta n:5" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "3".to_string() ) ) ]),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::from([ ( "n".to_string(), Primitive( "5".to_string() ) ) ]),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );
  }
}

//

tests_index!
{
  basic,
  instruction_perform_basic,
  instructions_parse_basic,
}

<commit_msg>Write test routine `program_perform_basic`<commit_after>use super::*;
use wtools::error::BasicError;
use wca::command::Command;
use wca::instruction::Instruction;
use wca::string::parse_request::OpType::Primitive;

//

fn commands_form() -> std::collections::HashMap< String, Command >
{
  let help_command : Command = wca::CommandOptions::default()
  .hint( "Get help." )
  .long_hint( "Get help for command [command]" )
  .phrase( ".help" )
  .routine( &| _i : &Instruction | { println!( "this is help" ); Ok( () ) } )
  .form();
  let list_command : Command = wca::CommandOptions::default()
  .hint( "Get list." )
  .long_hint( "Get list of" )
  .phrase( ".list" )
  .subject_hint( "some subject" )
  .routine( &| _i : &Instruction | { println!( "this is list" ); Ok( () ) } )
  .form();
  let err_command : Command = wca::CommandOptions::default()
  .hint( "Error." )
  .long_hint( "Throw error" )
  .phrase( ".error" )
  .routine( &| _i : &Instruction | { Err( BasicError::new( "err" ) ) } )
  .form();

  let commands : std::collections::HashMap< String, Command > = std::collections::HashMap::from
  ([
    ( ".help".to_string(), help_command ),
    ( ".list".to_string(), list_command ),
    ( ".error".to_string(), err_command ),
  ]);
  commands
}

tests_impls!
{
  fn basic()
  {
    let ca = wca::commands_aggregator()
    .form();
    a_id!( ca.base_path, None );
    a_id!( ca.command_prefix, "".to_string() );
    a_id!( ca.delimeter, vec![ ".".to_string(), " ".to_string() ] );
    a_id!( ca.command_explicit_delimeter, ";".to_string() );
    a_id!( ca.command_implicit_delimeter, " ".to_string() );
    a_id!( ca.commands_explicit_delimiting, true );
    a_id!( ca.commands_implicit_delimiting, false );
    a_id!( ca.properties_map_parsing, false );
    a_id!( ca.several_values, true );
    a_id!( ca.with_help, true );
    a_id!( ca.changing_exit_code, true );
    a_id!( ca.commands, std::collections::HashMap::new() );
  }

  //

  fn program_perform_basic()
  {
    /* single command, returns Ok */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.program_perform( ".help" );
    a_id!( got, Ok( () ) );

    /* single command, returns Err */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.program_perform( ".error" );
    a_id!( got, Err( BasicError::new( "err" ) ) );

    /* */

    /* two commands, explicit delimeter, returns Ok */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.program_perform( ".help ; .list" );
    a_id!( got, Ok( () ) );

    /* two commands, explicit delimeter, second command returns Err */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.program_perform( ".list ; .error" );
    a_id!( got, Err( BasicError::new( "err" ) ) );

    /* */

    /* two commands, implicit delimeter, returns Ok */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.program_perform( ".help .list" );
    a_id!( got, Ok( () ) );

    /* two commands, implicit delimeter, second command returns Err */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.program_perform( ".list .error" );
    a_id!( got, Err( BasicError::new( "err" ) ) );
  }

  //

  fn instruction_perform_basic()
  {
    /* no commands in aggregator */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .form();
    let got = ca.instruction_perform( ".help" );
    a_id!( got, Ok( () ) );

    /* command returns Ok */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.instruction_perform( ".help" );
    a_id!( got, Ok( () ) );

    /* command returns Err */
    let ca = wca::commands_aggregator()
    .changing_exit_code( false )
    .commands().replace( commands_form() ).end()
    .form();
    let got = ca.instruction_perform( ".error" );
    a_id!( got, Err( BasicError::new( "err" ) ) );
  }

  //

  fn instructions_parse_basic()
  {
    let ca = wca::commands_aggregator()
    .form();

    /* */

    /* empty program */
    let got = ca.instructions_parse( "" );
    a_id!( got, vec![] );

    /* */

    /* single command without subject and map */
    let got = ca.instructions_parse( ".help" );
    let instruction = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction ] );

    /* single command with subject */
    let got = ca.instructions_parse( ".help command" );
    let instruction = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction ] );

    /* single command with subject and map */
    let got = ca.instructions_parse( ".help command v:3" );
    let instruction = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "3".to_string() ) ) ]),
    };
    a_id!( got, vec![ instruction ] );

    /* */

    /* two commands without subject and map, explicit delimeter */
    let got = ca.instructions_parse( ".help ; .version" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject, explicit delimeter */
    let got = ca.instructions_parse( ".help command ; .version delta" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject and map, explicit delimeter */
    let got = ca.instructions_parse( ".help command v:3 ; .version delta n:5" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "3".to_string() ) ) ]),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::from([ ( "n".to_string(), Primitive( "5".to_string() ) ) ]),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* */

    /* two commands without subject and map, implicit delimeter */
    let got = ca.instructions_parse( ".help .version" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject, implicit delimeter */
    let got = ca.instructions_parse( ".help command .version delta" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::new(),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::new(),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );

    /* two commands with subject and map, implicit delimeter */
    let got = ca.instructions_parse( ".help command v:3 .version delta n:5" );
    let instruction1 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".help".to_string(),
      subject : "command".to_string(),
      properties_map : HashMap::from([ ( "v".to_string(), Primitive( "3".to_string() ) ) ]),
    };
    let instruction2 = wca::instruction::Instruction
    {
      err : None,
      command_name : ".version".to_string(),
      subject : "delta".to_string(),
      properties_map : HashMap::from([ ( "n".to_string(), Primitive( "5".to_string() ) ) ]),
    };
    a_id!( got, vec![ instruction1, instruction2 ] );
  }
}

//

tests_index!
{
  basic,
  program_perform_basic,
  instruction_perform_basic,
  instructions_parse_basic,
}

<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use ::model::*;

#[cfg(feature="cache")]
use ::client::{CACHE, rest};
#[cfg(feature="cache")]
use ::internal::prelude::*;
#[cfg(feature="cache")]
use ::utils::builder::EditMember;
#[cfg(feature="cache")]
use ::utils::Colour;

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: Option<GuildId>,
    /// Timestamp representing the date when the member joined.
    pub joined_at: String,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with="deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        let guild_id = self.find_guild()?;

        match rest::add_member_role(guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        let guild_id = self.find_guild()?;
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match rest::edit_member(guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            }
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] role.
    ///
    /// # Errors
    ///
    /// Returns a [`ClientError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature="cache")]
    pub fn ban(&self, delete_message_days: u8) -> Result<()> {
        rest::ban_user(self.find_guild()?.0, self.user.read().unwrap().id.0, delete_message_days)
    }

    /// Determines the member's colour.
    #[cfg(feature="cache")]
    pub fn colour(&self) -> Option<Colour> {
        let guild_id = match self.find_guild() {
            Ok(guild_id) => guild_id,
            Err(_) => return None,
        };

        let cache = CACHE.read().unwrap();
        let guild = match cache.guilds.get(&guild_id) {
            Some(guild) => guild.read().unwrap(),
            None => return None,
        };

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles.iter().find(|r| r.colour.0 != default.0).map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick.as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!("{}#{}", self.display_name(), self.user.read().unwrap().discriminator)
    }

    /// Edits the member with the given data. See [`Context::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Context::edit_member`]: ../client/struct.Context.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature="cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let guild_id = self.find_guild()?;
        let map = f(EditMember::default()).0;

        rest::edit_member(guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Finds the Id of the [`Guild`] that the member is in.
    ///
    /// Returns the value of [`Member::guild_id`] if present. Otherwise searches
    /// the [`Cache`] for the Id.
    ///
    /// # Errors
    ///
    /// Returns a [`ClientError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`Cache`]: ../ext/cache/struct.Cache.html
    /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
    /// [`Guild`]: struct.Guild.html
    /// [`Member::guild_id`]: struct.Member.html#structfield.guild_id
    #[cfg(feature="cache")]
    pub fn find_guild(&self) -> Result<GuildId> {
        if let Some(guild_id) = self.guild_id {
            return Ok(guild_id);
        }

        for guild in CACHE.read().unwrap().guilds.values() {
            let guild = guild.read().unwrap();

            let predicate = guild.members
                .values()
                .any(|m| m.joined_at == self.joined_at && m.user.read().unwrap().id == self.user.read().unwrap().id);

            if predicate {
                return Ok(guild.id);
            }
        }

        Err(Error::Client(ClientError::GuildNotFound))
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        let guild_id = self.find_guild()?;

        match rest::remove_member_role(guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        let guild_id = self.find_guild()?;
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match rest::edit_member(guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature="cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        CACHE.read().unwrap()
            .guilds
            .values()
            .find(|guild| guild
                .read()
                .unwrap()
                .members
                .values()
                .any(|m| m.user.read().unwrap().id == self.user.read().unwrap().id && m.joined_at == *self.joined_at))
            .map(|guild| guild
                .read()
                .unwrap()
                .roles
                .values()
                .filter(|role| self.roles.contains(&role.id))
                .cloned()
                .collect())
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature="cache")]
    pub fn unban(&self) -> Result<()> {
        rest::remove_ban(self.find_guild()?.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<commit_msg>Add missing Member::kick shortcut<commit_after>use std::borrow::Cow;
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use ::model::*;

#[cfg(feature="cache")]
use ::client::{CACHE, rest};
#[cfg(feature="cache")]
use ::internal::prelude::*;
#[cfg(feature="cache")]
use ::utils::builder::EditMember;
#[cfg(feature="cache")]
use ::utils::Colour;

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: Option<GuildId>,
    /// Timestamp representing the date when the member joined.
    pub joined_at: String,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with="deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        let guild_id = self.find_guild()?;

        match rest::add_member_role(guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        let guild_id = self.find_guild()?;
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match rest::edit_member(guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            }
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ClientError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature="cache")]
    pub fn ban(&self, delete_message_days: u8) -> Result<()> {
        rest::ban_user(self.find_guild()?.0, self.user.read().unwrap().id.0, delete_message_days)
    }

    /// Determines the member's colour.
    #[cfg(feature="cache")]
    pub fn colour(&self) -> Option<Colour> {
        let guild_id = match self.find_guild() {
            Ok(guild_id) => guild_id,
            Err(_) => return None,
        };

        let cache = CACHE.read().unwrap();
        let guild = match cache.guilds.get(&guild_id) {
            Some(guild) => guild.read().unwrap(),
            None => return None,
        };

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles.iter().find(|r| r.colour.0 != default.0).map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick.as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!("{}#{}", self.display_name(), self.user.read().unwrap().discriminator)
    }

    /// Edits the member with the given data. See [`Context::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Context::edit_member`]: ../client/struct.Context.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature="cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let guild_id = self.find_guild()?;
        let map = f(EditMember::default()).0;

        rest::edit_member(guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Finds the Id of the [`Guild`] that the member is in.
    ///
    /// Returns the value of [`Member::guild_id`] if present. Otherwise searches
    /// the [`Cache`] for the Id.
    ///
    /// # Errors
    ///
    /// Returns a [`ClientError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`Cache`]: ../ext/cache/struct.Cache.html
    /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
    /// [`Guild`]: struct.Guild.html
    /// [`Member::guild_id`]: struct.Member.html#structfield.guild_id
    #[cfg(feature="cache")]
    pub fn find_guild(&self) -> Result<GuildId> {
        if let Some(guild_id) = self.guild_id {
            return Ok(guild_id);
        }

        for guild in CACHE.read().unwrap().guilds.values() {
            let guild = guild.read().unwrap();

            let predicate = guild.members
                .values()
                .any(|m| m.joined_at == self.joined_at && m.user.read().unwrap().id == self.user.read().unwrap().id);

            if predicate {
                return Ok(guild.id);
            }
        }

        Err(Error::Client(ClientError::GuildNotFound))
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Client(ClientError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Client(ClientError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ClientError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        let guild_id;

        #[cfg(feature="cache")]
        {
            guild_id = self.find_guild()?;
            let req = permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        #[cfg(not(feature="cache"))]
        {
            guild_id = self.guild_id.ok_or_else(|| Error::Client(ClientError::GuildNotFound))?;
        }

        guild_id.kick(self.user.read().unwrap().id)
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        let guild_id = self.find_guild()?;

        match rest::remove_member_role(guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature="cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        let guild_id = self.find_guild()?;
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match rest::edit_member(guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature="cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        CACHE.read().unwrap()
            .guilds
            .values()
            .find(|guild| guild
                .read()
                .unwrap()
                .members
                .values()
                .any(|m| m.user.read().unwrap().id == self.user.read().unwrap().id && m.joined_at == *self.joined_at))
            .map(|guild| guild
                .read()
                .unwrap()
                .roles
                .values()
                .filter(|role| self.roles.contains(&role.id))
                .cloned()
                .collect())
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature="cache")]
    pub fn unban(&self) -> Result<()> {
        rest::remove_ban(self.find_guild()?.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<|endoftext|>


<commit_before>#[link(name = "simplify", vers = "0.0.5")];
extern mod extra;
use extra::json::*;
use extra::treemap::TreeSet;
use std::vec;
pub struct Point {
	x: float,
	y: float
}
impl ToJson for Point {
    fn to_json(&self) -> Json { List(~[self.x.to_json(),self.y.to_json()]) }
}
impl Eq for Point {
    fn eq(&self, other: &Point) -> bool { other.x == self.x && other.y == self.y }
    fn ne(&self, other: &Point) -> bool { other.x != self.x || other.y != self.y }
}
impl Sub<Point,Point> for Point {
    #[inline]
    fn sub(&self, other: &Point) -> Point { Point {x:self.x-other.x,y:self.y-other.y} }
}
impl Add<Point,Point> for Point {
    #[inline]
    fn add(&self, other: &Point) -> Point { Point { x:self.x+other.x,y:self.y+other.y }}
}
impl Mul<Point,Point> for Point {
    #[inline]
    fn mul(&self, other: &Point) -> Point { Point { x:self.x*other.x,y:self.y*other.y }}
}

impl Point {
    fn sum(self) -> float { self.x+self.y }
    fn sqsum(self) -> float { self.x * self.x + self.y * self.y}
    fn sub(self, other: float) -> Point { Point { x:self.x - other , y:self.y - other }}
    fn mul(self, other: float) -> Point { Point { x:self.x * other, y:self.y * other }}
    fn add(self, other: float) -> Point {  Point {x:self.x + other, y:self.y + other }}
}
struct Pair(uint,uint);
impl Pair {
fn first(self)-> uint {
        match self {
            Pair(l,_)=>l
        }
    }
    fn last(self)-> uint {
        match self {
            Pair(_,l)=>l
        }
    }
}
fn calcStuff(p:Point,p1:Point,d1:Point)->float {
	let top : float = ((p - p1) * d1).sum();
	let bottom : float =  d1.sqsum();
	match bottom{
		0.0=>0.0,
		_=>top/bottom
	}
}
fn getSquareSegmentDistance(p: Point, p1: Point, p2: Point) -> float {
	let d1 : Point = p2-p1;
	let d2 : Point = match d1{
		Point {x:0.0,_} | Point {y:0.0,_}=> {p1}
		_=>{
			let t : float = calcStuff(p,p1,d1);
			match t {
				tt if tt>1.0=>p2,
				tt if tt>0.0=> d1.mul(tt)+p1,
				_=>p1
			}
		}
	};
	let d4 : Point = p-d2;
	d4.sqsum()
}

fn simplifyRadialDistance(points:~[Point], sqTolerance:float) -> ~[Point]{
    let mut it = points.iter();
    it.next();
	let mut prevPoint : Point = points[0u];
	let mut newPoints : ~[Point] = ~[prevPoint];
	let &last = points.last();
	for &point in it{
	    if (point - prevPoint).sqsum() > sqTolerance {
			newPoints.push(point);
			prevPoint = point;
		}
	}
	if (prevPoint!= last) {
		newPoints.push(last);
	}
	newPoints
}

fn simplifyDouglasPeucker(points : ~[Point], tolerance : float) -> ~[Point]{
	let len : uint = points.len();
	let mut markers = TreeSet::new();
	let mut pair = Pair(0u,len-1u);
	let mut stack : ~[Pair] = ~[];
	markers.insert(0u);
	markers.insert(len-1u);
	let mut index : uint = 0;

	loop{
			    let first = pair.first();
	    let last = pair.last();
		let mut maxSqDist : float = 0.0f;
		let mut i : uint = first + 1u;
		while (i < last) {

			let sqDist :float  = getSquareSegmentDistance(
				points[i],
				points[first],
				points[last]
			);
			if (sqDist > maxSqDist) {
				index = i;
				maxSqDist = sqDist;
			}
			i += 1;
		}
		if (maxSqDist > tolerance) {
			markers.insert(index);
			stack.push(Pair(first,index));
			stack.push(Pair(index,last));
		}
		match stack.pop_opt() {
		    Some(p)=>{
		        pair = p;
		    }
		    None=>break
		}
	};
    vec::from_fn(markers.len(),|k| points[k])
}

pub fn simplify(points : ~[Point], sqTolerance : float, hq:bool) -> ~[Point]{
	let tolerance : float = sqTolerance*sqTolerance;
	let pts:~[Point]=match hq {
		true=>points,
		_=>simplifyRadialDistance(points,tolerance)
	};
	simplifyDouglasPeucker(pts,tolerance)
}
<commit_msg>use pairs<commit_after>#[link(name = "simplify", vers = "0.0.5")];
extern mod extra;
use extra::json::*;
use extra::treemap::TreeSet;
use std::vec;
pub struct Point {
	x: float,
	y: float
}
impl ToJson for Point {
    fn to_json(&self) -> Json { List(~[self.x.to_json(),self.y.to_json()]) }
}
impl Eq for Point {
    fn eq(&self, other: &Point) -> bool { other.x == self.x && other.y == self.y }
    fn ne(&self, other: &Point) -> bool { other.x != self.x || other.y != self.y }
}
impl Sub<Point,Point> for Point {
    #[inline]
    fn sub(&self, other: &Point) -> Point { Point {x:self.x-other.x,y:self.y-other.y} }
}
impl Add<Point,Point> for Point {
    #[inline]
    fn add(&self, other: &Point) -> Point { Point { x:self.x+other.x,y:self.y+other.y }}
}
impl Mul<Point,Point> for Point {
    #[inline]
    fn mul(&self, other: &Point) -> Point { Point { x:self.x*other.x,y:self.y*other.y }}
}

impl Point {
    fn sum(self) -> float { self.x+self.y }
    fn sqsum(self) -> float { self.x * self.x + self.y * self.y}
    fn sub(self, other: float) -> Point { Point { x:self.x - other , y:self.y - other }}
    fn mul(self, other: float) -> Point { Point { x:self.x * other, y:self.y * other }}
    fn add(self, other: float) -> Point {  Point {x:self.x + other, y:self.y + other }}
}
struct Pair(uint,uint);
enum Opt<T,U>{
    OK(T,T,U),
    NotOK
}
impl Pair {
fn first(self)-> uint {
        match self {
            Pair(l,_)=>l
        }
    }
    fn last(self)-> uint {
        match self {
            Pair(_,l)=>l
        }
    }
}
fn calcStuff(p:Point,p1:Point,d1:Point)->float {
	let top : float = ((p - p1) * d1).sum();
	let bottom : float =  d1.sqsum();
	match bottom{
		0.0=>0.0,
		_=>top/bottom
	}
}
fn getSquareSegmentDistance(p: Point, p1: Point, p2: Point) -> float {
	let d1 : Point = p2-p1;
	let d2 : Point = match d1{
		Point {x:0.0,_} | Point {y:0.0,_}=> {p1}
		_=>{
			let t : float = calcStuff(p,p1,d1);
			match t {
				tt if tt>1.0=>p2,
				tt if tt>0.0=> d1.mul(tt)+p1,
				_=>p1
			}
		}
	};
	let d4 : Point = p-d2;
	d4.sqsum()
}

fn simplifyRadialDistance(points:~[Point], sqTolerance:float) -> ~[Point]{
    let mut it = points.iter();
    it.next();
	let mut prevPoint : Point = points[0u];
	let mut newPoints : ~[Point] = ~[prevPoint];
	let &last = points.last();
	for &point in it{
	    if (point - prevPoint).sqsum() > sqTolerance {
			newPoints.push(point);
			prevPoint = point;
		}
	}
	if (prevPoint!= last) {
		newPoints.push(last);
	}
	newPoints
}

fn simplifyDouglasPeucker(points : ~[Point], tolerance : float) -> ~[Point]{
	let len : uint = points.len();
	let mut markers = TreeSet::new();
	let mut stack : ~[Pair] = ~[];
	markers.insert(0u);
	markers.insert(len-1u);
	let mut first = 0u;
    let mut last = len-1u;
	loop{
	   let mut index : uint = 0;
		let mut maxSqDist : float = 0.0f;
		let mut i : uint = first + 1u;
		while (i < last) {

			let sqDist :float  = getSquareSegmentDistance(
				points[i],
				points[first],
				points[last]
			);
			if (sqDist > maxSqDist) {
				index = i;
				maxSqDist = sqDist;
			}
			i += 1;
		}
		if maxSqDist > tolerance {
			  markers.insert(index);
			    stack.push(Pair(first,index));
			    stack.push(Pair(index,last));
		}
			match stack.pop_opt() {
		    Some(Pair(f,l))=> {
		        first = f;
		        last = l;
		    }
		    None=>break
		};
        };
    vec::from_fn(markers.len(),|k| points[k])
}

pub fn simplify(points : ~[Point], sqTolerance : float, hq:bool) -> ~[Point]{
	let tolerance : float = sqTolerance*sqTolerance;
	let pts:~[Point]=match hq {
		true=>points,
		_=>simplifyRadialDistance(points,tolerance)
	};
	simplifyDouglasPeucker(pts,tolerance)
}
<|endoftext|>


<commit_before>use command_line_parser::CommandLineParser;
use std::collections::vec_deque::VecDeque;
use std::str::FromStr;

impl CommandLineParser for bool {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let arg = match args.pop_front() {
            Some(arg) => {
                arg
            },
            None => {
                panic!("Error popping arg queue in bool CommandLineParser. Queue is probably empty.");
            },
        };

        let result = match bool::from_str(arg.as_ref()) {
            Ok(result) => {
                result
            },
            Err(err) => {
                panic!("Error parsing arg in bool CommandLineParser: {}", err);
            },
        };

        result
    }
}

impl CommandLineParser for usize {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let arg = match args.pop_front() {
            Some(arg) => {
                arg
            },
            None => {
                panic!("Error popping arg queue in u8 CommandLineParser. Queue is probably empty.");
            },
        };

        let result = match usize::from_str(arg.as_ref()) {
            Ok(result) => {
                result
            },
            Err(err) => {
                panic!("Error parsing arg in u8 CommandLineParser: {}", err);
            },
        };

        result
    }
}

impl CommandLineParser for String {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let arg = match args.pop_front() {
            Some(arg) => {
                arg
            },
            None => {
                panic!("Error popping arg queue in bool CommandLineParser. Queue is probably empty.");
            },
        };

        arg
    }
}

impl <T> CommandLineParser for Vec<T>
    where T: CommandLineParser {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let len = usize::parse(args);
        (0..len).into_iter()
                .map(
                    |_| {
                        T::parse(args)
                    }
                )
                .collect()
    }
}

impl <T0, T1> CommandLineParser for (T0, T1)
    where T0: CommandLineParser,
          T1: CommandLineParser {
    fn parse(args: &mut VecDeque<String>) -> Self {
        (T0::parse(args), T1::parse(args))
    }
}
<commit_msg>Add path buf parser.<commit_after>use command_line_parser::CommandLineParser;
use std::collections::vec_deque::VecDeque;
use std::path::PathBuf;
use std::str::FromStr;

impl CommandLineParser for bool {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let arg = match args.pop_front() {
            Some(arg) => {
                arg
            },
            None => {
                panic!("Error popping arg queue in bool CommandLineParser. Queue is probably empty.");
            },
        };

        let result = match bool::from_str(arg.as_ref()) {
            Ok(result) => {
                result
            },
            Err(err) => {
                panic!("Error parsing arg in bool CommandLineParser: {}", err);
            },
        };

        result
    }
}

impl CommandLineParser for usize {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let arg = match args.pop_front() {
            Some(arg) => {
                arg
            },
            None => {
                panic!("Error popping arg queue in u8 CommandLineParser. Queue is probably empty.");
            },
        };

        let result = match usize::from_str(arg.as_ref()) {
            Ok(result) => {
                result
            },
            Err(err) => {
                panic!("Error parsing arg in u8 CommandLineParser: {}", err);
            },
        };

        result
    }
}

impl CommandLineParser for String {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let arg = match args.pop_front() {
            Some(arg) => {
                arg
            },
            None => {
                panic!("Error popping arg queue in bool CommandLineParser. Queue is probably empty.");
            },
        };

        arg
    }
}

impl <T> CommandLineParser for Vec<T>
    where T: CommandLineParser {
    fn parse(args: &mut VecDeque<String>) -> Self {
        let len = usize::parse(args);
        (0..len).into_iter()
                .map(
                    |_| {
                        T::parse(args)
                    }
                )
                .collect()
    }
}

impl CommandLineParser for PathBuf {
    fn parse(args: &mut VecDeque<String>) -> Self {
        match args.pop_front() {
            Some(arg) => {
                let mut result = PathBuf::new();
                result.push(arg);
                result
            },
            None => {
                panic!("Error popping arg queue in bool CommandLineParser. Queue is probably empty.");
            },
        }
    }
}

impl <T0, T1> CommandLineParser for (T0, T1)
    where T0: CommandLineParser,
          T1: CommandLineParser {
    fn parse(args: &mut VecDeque<String>) -> Self {
        (T0::parse(args), T1::parse(args))
    }
}
<|endoftext|>


<commit_before>use std::{
    io,
    mem,
    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
    os::unix::io::{AsRawFd, RawFd},
    pin::Pin,
    task::{self, Poll},
};

use cfg_if::cfg_if;
use log::error;
use pin_project::pin_project;
use tokio::{
    io::{AsyncRead, AsyncWrite, ReadBuf},
    net::{TcpSocket, TcpStream as TokioTcpStream, UdpSocket},
};
use tokio_tfo::TfoStream;

use crate::net::{
    sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect},
    AddrFamily,
    ConnectOpts,
};

/// A `TcpStream` that supports TFO (TCP Fast Open)
#[pin_project(project = TcpStreamProj)]
pub enum TcpStream {
    Standard(#[pin] TokioTcpStream),
    FastOpen(#[pin] TfoStream),
}

impl TcpStream {
    pub async fn connect(addr: SocketAddr, opts: &ConnectOpts) -> io::Result<TcpStream> {
        let socket = match addr {
            SocketAddr::V4(..) => TcpSocket::new_v4()?,
            SocketAddr::V6(..) => TcpSocket::new_v6()?,
        };

        // Any traffic to localhost should not be protected
        // This is a workaround for VPNService
        #[cfg(target_os = "android")]
        if !addr.ip().is_loopback() {
            use std::time::Duration;
            use tokio::time;

            if let Some(ref path) = opts.vpn_protect_path {
                // RPC calls to `VpnService.protect()`
                // Timeout in 3 seconds like shadowsocks-libev
                match time::timeout(Duration::from_secs(3), vpn_protect(path, socket.as_raw_fd())).await {
                    Ok(Ok(..)) => {}
                    Ok(Err(err)) => return Err(err),
                    Err(..) => return Err(io::Error::new(ErrorKind::TimedOut, "protect() timeout")),
                }
            }
        }

        // Set SO_MARK for mark-based routing on Linux (since 2.6.25)
        // NOTE: This will require CAP_NET_ADMIN capability (root in most cases)
        if let Some(mark) = opts.fwmark {
            let ret = unsafe {
                libc::setsockopt(
                    socket.as_raw_fd(),
                    libc::SOL_SOCKET,
                    libc::SO_MARK,
                    &mark as *const _ as *const _,
                    mem::size_of_val(&mark) as libc::socklen_t,
                )
            };
            if ret != 0 {
                let err = io::Error::last_os_error();
                error!("set SO_MARK error: {}", err);
                return Err(err);
            }
        }

        // Set SO_BINDTODEVICE for binding to a specific interface
        if let Some(ref iface) = opts.bind_interface {
            set_bindtodevice(&socket, iface)?;
        }

        set_common_sockopt_for_connect(addr, &socket, opts)?;

        if !opts.tcp.fastopen {
            // If TFO is not enabled, it just works like a normal TcpStream
            let stream = socket.connect(addr).await?;
            set_common_sockopt_after_connect(&stream, opts)?;

            return Ok(TcpStream::Standard(stream));
        }

        let stream = TfoStream::connect_with_socket(socket, addr).await?;
        set_common_sockopt_after_connect(&stream, opts)?;

        Ok(TcpStream::FastOpen(stream))
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            TcpStream::Standard(ref s) => s.local_addr(),
            TcpStream::FastOpen(ref s) => s.local_addr(),
        }
    }

    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            TcpStream::Standard(ref s) => s.peer_addr(),
            TcpStream::FastOpen(ref s) => s.peer_addr(),
        }
    }

    pub fn nodelay(&self) -> io::Result<bool> {
        match *self {
            TcpStream::Standard(ref s) => s.nodelay(),
            TcpStream::FastOpen(ref s) => s.nodelay(),
        }
    }

    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        match *self {
            TcpStream::Standard(ref s) => s.set_nodelay(nodelay),
            TcpStream::FastOpen(ref s) => s.set_nodelay(nodelay),
        }
    }
}

impl AsRawFd for TcpStream {
    fn as_raw_fd(&self) -> RawFd {
        match *self {
            TcpStream::Standard(ref s) => s.as_raw_fd(),
            TcpStream::FastOpen(ref s) => s.as_raw_fd(),
        }
    }
}

impl AsyncRead for TcpStream {
    fn poll_read(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_read(cx, buf),
            TcpStreamProj::FastOpen(s) => s.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for TcpStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_write(cx, buf),
            TcpStreamProj::FastOpen(s) => s.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_flush(cx),
            TcpStreamProj::FastOpen(s) => s.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_shutdown(cx),
            TcpStreamProj::FastOpen(s) => s.poll_shutdown(cx),
        }
    }
}

/// Enable `TCP_FASTOPEN`
///
/// `TCP_FASTOPEN` was supported since Linux 3.7
pub fn set_tcp_fastopen<S: AsRawFd>(socket: &S) -> io::Result<()> {
    // https://lwn.net/Articles/508865/
    //
    // The option value, qlen, specifies this server's limit on the size of the queue of TFO requests that have
    // not yet completed the three-way handshake (see the remarks on prevention of resource-exhaustion attacks above).
    //
    // It was recommended to be `5` in this document.
    //
    // But since mio's TcpListener sets backlogs to 1024, it would be nice to have 1024 slots for handshaking TFO requests.
    let queue: libc::c_int = 1024;

    unsafe {
        let ret = libc::setsockopt(
            socket.as_raw_fd(),
            libc::IPPROTO_TCP,
            libc::TCP_FASTOPEN,
            &queue as *const _ as *const libc::c_void,
            mem::size_of_val(&queue) as libc::socklen_t,
        );

        if ret != 0 {
            let err = io::Error::last_os_error();
            error!("set TCP_FASTOPEN error: {}", err);
            return Err(err);
        }
    }

    Ok(())
}

/// Create a `UdpSocket` for connecting to `addr`
pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> io::Result<UdpSocket> {
    let bind_addr = match (af, config.bind_local_addr) {
        (AddrFamily::Ipv4, Some(IpAddr::V4(ip))) => SocketAddr::new(ip.into(), 0),
        (AddrFamily::Ipv6, Some(IpAddr::V6(ip))) => SocketAddr::new(ip.into(), 0),
        (AddrFamily::Ipv4, ..) => SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0),
        (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
    };

    let socket = UdpSocket::bind(bind_addr).await?;

    // Any traffic except localhost should be protected
    // This is a workaround for VPNService
    #[cfg(target_os = "android")]
    {
        use std::time::Duration;
        use tokio::time;

        if let Some(ref path) = config.vpn_protect_path {
            // RPC calls to `VpnService.protect()`
            // Timeout in 3 seconds like shadowsocks-libev
            match time::timeout(Duration::from_secs(3), vpn_protect(path, socket.as_raw_fd())).await {
                Ok(Ok(..)) => {}
                Ok(Err(err)) => return Err(err),
                Err(..) => return Err(io::Error::new(ErrorKind::TimedOut, "protect() timeout")),
            }
        }
    }

    // Set SO_MARK for mark-based routing on Linux (since 2.6.25)
    // NOTE: This will require CAP_NET_ADMIN capability (root in most cases)
    if let Some(mark) = config.fwmark {
        let ret = unsafe {
            libc::setsockopt(
                socket.as_raw_fd(),
                libc::SOL_SOCKET,
                libc::SO_MARK,
                &mark as *const _ as *const _,
                mem::size_of_val(&mark) as libc::socklen_t,
            )
        };
        if ret != 0 {
            let err = io::Error::last_os_error();
            error!("set SO_MARK error: {}", err);
            return Err(err);
        }
    }

    // Set SO_BINDTODEVICE for binding to a specific interface
    if let Some(ref iface) = config.bind_interface {
        set_bindtodevice(&socket, iface)?;
    }

    Ok(socket)
}

fn set_bindtodevice<S: AsRawFd>(socket: &S, iface: &str) -> io::Result<()> {
    let iface_bytes = iface.as_bytes();

    unsafe {
        let ret = libc::setsockopt(
            socket.as_raw_fd(),
            libc::SOL_SOCKET,
            libc::SO_BINDTODEVICE,
            iface_bytes.as_ptr() as *const _ as *const libc::c_void,
            iface_bytes.len() as libc::socklen_t,
        );

        if ret != 0 {
            let err = io::Error::last_os_error();
            error!("set SO_BINDTODEVICE error: {}", err);
            return Err(err);
        }
    }

    Ok(())
}

cfg_if! {
    if #[cfg(target_os = "android")] {
        use std::path::Path;
        use std::os::unix::io::RawFd;

        use super::uds::UnixStream;

        /// This is a RPC for Android to `protect()` socket for connecting to remote servers
        ///
        /// https://developer.android.com/reference/android/net/VpnService#protect(java.net.Socket)
        ///
        /// More detail could be found in [shadowsocks-android](https://github.com/shadowsocks/shadowsocks-android) project.
        async fn vpn_protect<P: AsRef<Path>>(protect_path: P, fd: RawFd) -> io::Result<()> {
            use tokio::io::AsyncReadExt;

            let mut stream = UnixStream::connect(protect_path).await?;

            // send fds
            let dummy: [u8; 1] = [1];
            let fds: [RawFd; 1] = [fd];
            stream.send_with_fd(&dummy, &fds).await?;

            // receive the return value
            let mut response = [0; 1];
            stream.read_exact(&mut response).await?;

            if response[0] == 0xFF {
                return Err(io::Error::new(ErrorKind::Other, "protect() failed"));
            }

            Ok(())
        }
    }
}
<commit_msg>fix build on Android<commit_after>use std::{
    io,
    mem,
    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
    os::unix::io::{AsRawFd, RawFd},
    pin::Pin,
    task::{self, Poll},
};
#[cfg(target_os = "android")]
use std::io::ErrorKind;

use cfg_if::cfg_if;
use log::error;
use pin_project::pin_project;
use tokio::{
    io::{AsyncRead, AsyncWrite, ReadBuf},
    net::{TcpSocket, TcpStream as TokioTcpStream, UdpSocket},
};
use tokio_tfo::TfoStream;

use crate::net::{
    sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect},
    AddrFamily,
    ConnectOpts,
};

/// A `TcpStream` that supports TFO (TCP Fast Open)
#[pin_project(project = TcpStreamProj)]
pub enum TcpStream {
    Standard(#[pin] TokioTcpStream),
    FastOpen(#[pin] TfoStream),
}

impl TcpStream {
    pub async fn connect(addr: SocketAddr, opts: &ConnectOpts) -> io::Result<TcpStream> {
        let socket = match addr {
            SocketAddr::V4(..) => TcpSocket::new_v4()?,
            SocketAddr::V6(..) => TcpSocket::new_v6()?,
        };

        // Any traffic to localhost should not be protected
        // This is a workaround for VPNService
        #[cfg(target_os = "android")]
        if !addr.ip().is_loopback() {
            use std::time::Duration;
            use tokio::time;

            if let Some(ref path) = opts.vpn_protect_path {
                // RPC calls to `VpnService.protect()`
                // Timeout in 3 seconds like shadowsocks-libev
                match time::timeout(Duration::from_secs(3), vpn_protect(path, socket.as_raw_fd())).await {
                    Ok(Ok(..)) => {}
                    Ok(Err(err)) => return Err(err),
                    Err(..) => return Err(io::Error::new(ErrorKind::TimedOut, "protect() timeout")),
                }
            }
        }

        // Set SO_MARK for mark-based routing on Linux (since 2.6.25)
        // NOTE: This will require CAP_NET_ADMIN capability (root in most cases)
        if let Some(mark) = opts.fwmark {
            let ret = unsafe {
                libc::setsockopt(
                    socket.as_raw_fd(),
                    libc::SOL_SOCKET,
                    libc::SO_MARK,
                    &mark as *const _ as *const _,
                    mem::size_of_val(&mark) as libc::socklen_t,
                )
            };
            if ret != 0 {
                let err = io::Error::last_os_error();
                error!("set SO_MARK error: {}", err);
                return Err(err);
            }
        }

        // Set SO_BINDTODEVICE for binding to a specific interface
        if let Some(ref iface) = opts.bind_interface {
            set_bindtodevice(&socket, iface)?;
        }

        set_common_sockopt_for_connect(addr, &socket, opts)?;

        if !opts.tcp.fastopen {
            // If TFO is not enabled, it just works like a normal TcpStream
            let stream = socket.connect(addr).await?;
            set_common_sockopt_after_connect(&stream, opts)?;

            return Ok(TcpStream::Standard(stream));
        }

        let stream = TfoStream::connect_with_socket(socket, addr).await?;
        set_common_sockopt_after_connect(&stream, opts)?;

        Ok(TcpStream::FastOpen(stream))
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            TcpStream::Standard(ref s) => s.local_addr(),
            TcpStream::FastOpen(ref s) => s.local_addr(),
        }
    }

    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            TcpStream::Standard(ref s) => s.peer_addr(),
            TcpStream::FastOpen(ref s) => s.peer_addr(),
        }
    }

    pub fn nodelay(&self) -> io::Result<bool> {
        match *self {
            TcpStream::Standard(ref s) => s.nodelay(),
            TcpStream::FastOpen(ref s) => s.nodelay(),
        }
    }

    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        match *self {
            TcpStream::Standard(ref s) => s.set_nodelay(nodelay),
            TcpStream::FastOpen(ref s) => s.set_nodelay(nodelay),
        }
    }
}

impl AsRawFd for TcpStream {
    fn as_raw_fd(&self) -> RawFd {
        match *self {
            TcpStream::Standard(ref s) => s.as_raw_fd(),
            TcpStream::FastOpen(ref s) => s.as_raw_fd(),
        }
    }
}

impl AsyncRead for TcpStream {
    fn poll_read(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_read(cx, buf),
            TcpStreamProj::FastOpen(s) => s.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for TcpStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_write(cx, buf),
            TcpStreamProj::FastOpen(s) => s.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_flush(cx),
            TcpStreamProj::FastOpen(s) => s.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            TcpStreamProj::Standard(s) => s.poll_shutdown(cx),
            TcpStreamProj::FastOpen(s) => s.poll_shutdown(cx),
        }
    }
}

/// Enable `TCP_FASTOPEN`
///
/// `TCP_FASTOPEN` was supported since Linux 3.7
pub fn set_tcp_fastopen<S: AsRawFd>(socket: &S) -> io::Result<()> {
    // https://lwn.net/Articles/508865/
    //
    // The option value, qlen, specifies this server's limit on the size of the queue of TFO requests that have
    // not yet completed the three-way handshake (see the remarks on prevention of resource-exhaustion attacks above).
    //
    // It was recommended to be `5` in this document.
    //
    // But since mio's TcpListener sets backlogs to 1024, it would be nice to have 1024 slots for handshaking TFO requests.
    let queue: libc::c_int = 1024;

    unsafe {
        let ret = libc::setsockopt(
            socket.as_raw_fd(),
            libc::IPPROTO_TCP,
            libc::TCP_FASTOPEN,
            &queue as *const _ as *const libc::c_void,
            mem::size_of_val(&queue) as libc::socklen_t,
        );

        if ret != 0 {
            let err = io::Error::last_os_error();
            error!("set TCP_FASTOPEN error: {}", err);
            return Err(err);
        }
    }

    Ok(())
}

/// Create a `UdpSocket` for connecting to `addr`
pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> io::Result<UdpSocket> {
    let bind_addr = match (af, config.bind_local_addr) {
        (AddrFamily::Ipv4, Some(IpAddr::V4(ip))) => SocketAddr::new(ip.into(), 0),
        (AddrFamily::Ipv6, Some(IpAddr::V6(ip))) => SocketAddr::new(ip.into(), 0),
        (AddrFamily::Ipv4, ..) => SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0),
        (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0),
    };

    let socket = UdpSocket::bind(bind_addr).await?;

    // Any traffic except localhost should be protected
    // This is a workaround for VPNService
    #[cfg(target_os = "android")]
    {
        use std::time::Duration;
        use tokio::time;

        if let Some(ref path) = config.vpn_protect_path {
            // RPC calls to `VpnService.protect()`
            // Timeout in 3 seconds like shadowsocks-libev
            match time::timeout(Duration::from_secs(3), vpn_protect(path, socket.as_raw_fd())).await {
                Ok(Ok(..)) => {}
                Ok(Err(err)) => return Err(err),
                Err(..) => return Err(io::Error::new(ErrorKind::TimedOut, "protect() timeout")),
            }
        }
    }

    // Set SO_MARK for mark-based routing on Linux (since 2.6.25)
    // NOTE: This will require CAP_NET_ADMIN capability (root in most cases)
    if let Some(mark) = config.fwmark {
        let ret = unsafe {
            libc::setsockopt(
                socket.as_raw_fd(),
                libc::SOL_SOCKET,
                libc::SO_MARK,
                &mark as *const _ as *const _,
                mem::size_of_val(&mark) as libc::socklen_t,
            )
        };
        if ret != 0 {
            let err = io::Error::last_os_error();
            error!("set SO_MARK error: {}", err);
            return Err(err);
        }
    }

    // Set SO_BINDTODEVICE for binding to a specific interface
    if let Some(ref iface) = config.bind_interface {
        set_bindtodevice(&socket, iface)?;
    }

    Ok(socket)
}

fn set_bindtodevice<S: AsRawFd>(socket: &S, iface: &str) -> io::Result<()> {
    let iface_bytes = iface.as_bytes();

    unsafe {
        let ret = libc::setsockopt(
            socket.as_raw_fd(),
            libc::SOL_SOCKET,
            libc::SO_BINDTODEVICE,
            iface_bytes.as_ptr() as *const _ as *const libc::c_void,
            iface_bytes.len() as libc::socklen_t,
        );

        if ret != 0 {
            let err = io::Error::last_os_error();
            error!("set SO_BINDTODEVICE error: {}", err);
            return Err(err);
        }
    }

    Ok(())
}

cfg_if! {
    if #[cfg(target_os = "android")] {
        use std::path::Path;

        use super::uds::UnixStream;

        /// This is a RPC for Android to `protect()` socket for connecting to remote servers
        ///
        /// https://developer.android.com/reference/android/net/VpnService#protect(java.net.Socket)
        ///
        /// More detail could be found in [shadowsocks-android](https://github.com/shadowsocks/shadowsocks-android) project.
        async fn vpn_protect<P: AsRef<Path>>(protect_path: P, fd: RawFd) -> io::Result<()> {
            use tokio::io::AsyncReadExt;

            let mut stream = UnixStream::connect(protect_path).await?;

            // send fds
            let dummy: [u8; 1] = [1];
            let fds: [RawFd; 1] = [fd];
            stream.send_with_fd(&dummy, &fds).await?;

            // receive the return value
            let mut response = [0; 1];
            stream.read_exact(&mut response).await?;

            if response[0] == 0xFF {
                return Err(io::Error::new(ErrorKind::Other, "protect() failed"));
            }

            Ok(())
        }
    }
}
<|endoftext|>


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

pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
             _symaddr: *mut libc::c_void) -> io::Result<()> {
    use sys::backtrace::{output};
    use intrinsics;
    #[repr(C)]
    struct Dl_info {
        dli_fname: *const libc::c_char,
        dli_fbase: *mut libc::c_void,
        dli_sname: *const libc::c_char,
        dli_saddr: *mut libc::c_void,
    }
    extern {
        fn dladdr(addr: *const libc::c_void,
                  info: *mut Dl_info) -> libc::c_int;
    }

    let mut info: Dl_info = unsafe { intrinsics::init() };
    if unsafe { dladdr(addr, &mut info) == 0 } {
        output(w, idx,addr, None)
    } else {
        output(w, idx, addr, Some(unsafe {
            CStr::from_ptr(info.dli_sname).to_bytes()
        }))
    }
}
<commit_msg>Add missing imports to `dladdr.rs` for Mac.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use io;
use io::prelude::*;
use libc;

pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
             _symaddr: *mut libc::c_void) -> io::Result<()> {
    use sys::backtrace::{output};
    use intrinsics;
    use ffi::CStr;

    #[repr(C)]
    struct Dl_info {
        dli_fname: *const libc::c_char,
        dli_fbase: *mut libc::c_void,
        dli_sname: *const libc::c_char,
        dli_saddr: *mut libc::c_void,
    }
    extern {
        fn dladdr(addr: *const libc::c_void,
                  info: *mut Dl_info) -> libc::c_int;
    }

    let mut info: Dl_info = unsafe { intrinsics::init() };
    if unsafe { dladdr(addr, &mut info) == 0 } {
        output(w, idx,addr, None)
    } else {
        output(w, idx, addr, Some(unsafe {
            CStr::from_ptr(info.dli_sname).to_bytes()
        }))
    }
}
<|endoftext|>


<commit_before>//! `Properties70` node and its children.

use std::fmt;
use fnv::{FnvHashSet, FnvHashMap};
use parser::binary::{Parser, ParserSource, Event, Attributes};
use parser::binary::{Attribute, PrimitiveAttribute};
use loader::binary::simple::{Result, Error};

/// A type of map from property name to value of the specific type.
pub type PropertyMap<T> = FnvHashMap<String, PropertyValue<T>>;

/// Struct to store `Properties70` node data.
#[derive(Default, Clone, PartialEq)]
pub struct Properties70 {
    /// Properties without values.
    values_empty: FnvHashSet<String>,
    /// Values with `i64`, `i32`, or `i16` type.
    values_i64: PropertyMap<i64>,
    /// Values with `f64` or `f32` type.
    values_f64: PropertyMap<f64>,
    /// Values with `[f64; 2]` type.
    values_f64_2: PropertyMap<[f64; 2]>,
    /// Values with `[f64; 3]` type.
    values_f64_3: PropertyMap<[f64; 3]>,
    /// Values with `[f64; 4]` type.
    values_f64_4: PropertyMap<[f64; 4]>,
    /// Values with `[[f64; 4]; 4]` type.
    values_f64_4x4: PropertyMap<[[f64; 4]; 4]>,
    /// Values with `String` type.
    values_string: PropertyMap<String>,
    /// Values with `Vec<u8>` type (called "blob").
    values_binary: PropertyMap<Vec<u8>>,
}

impl Properties70 {
    /// Creates a new `Properties70`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Loads a node from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(parser: P) -> Result<Self> {
        load_properties70(parser)
    }
}

impl fmt::Debug for Properties70 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut format = f.debug_struct("Properties70");
        macro_rules! show {
            ($field:ident) => {
                if !self.$field.is_empty() {
                    format.field(stringify!($field), &self.$field);
                }
            }
        }
        show!(values_empty);
        show!(values_i64);
        show!(values_f64);
        show!(values_f64_2);
        show!(values_f64_3);
        show!(values_f64_4);
        show!(values_f64_4x4);
        show!(values_string);
        show!(values_binary);
        format.finish()
    }
}

/// A type of property value and its metadata.
///
/// Type, label, and flags will be ignored currently.
#[derive(Debug, Clone, PartialEq)]
pub struct PropertyValue<T>(T);

impl<T> PropertyValue<T> {
    /// Creates a new `PropertyValue` with the given value.
    pub fn new(v: T) -> Self {
        PropertyValue(v)
    }

    /// Returns the value.
    pub fn value(&self) -> &T {
        &self.0
    }

    /// Returns the value with the ownership.
    pub fn take_value(self) -> T {
        self.0
    }
}

impl<T> From<T> for PropertyValue<T> {
    fn from(v: T) -> Self {
        PropertyValue::new(v)
    }
}

/// Loads a `Properties70` node.
fn load_properties70<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Properties70> {
    let mut props = Properties70::new();

    loop {
        try_get_node_attrs!(parser, |name: &str, attrs| if name == "P" {
            load_property(&mut props, attrs)
        } else {
            warn!("Expected `P` node but got `{}` in `Properties70`", name);
            Err(Error::UnexpectedNode(name.to_owned()))
        });
        parser.skip_current_node()?;
    }
    Ok(props)
}

/// Loads a `P` node in `Properties70`.
fn load_property<R: ParserSource>(
    props: &mut Properties70,
    mut attrs: Attributes<R>
) -> Result<()> {
    use parser::binary::utils::AttributeValues;

    // `type_name`, `label`, `flags` are `String`s, but ignore here because they are currently
    // unused.
    let (name, _type_name, _label, _flags) =
        <(String, (), (), ())>::from_attributes(&mut attrs)?
            .ok_or_else(|| Error::InvalidAttribute("P".to_owned()))?;

    if attrs.rest_attributes() == 0 {
        // Empty attribute.
        props.values_empty.insert(name);
        return Ok(());
    }

    // From multiple attributes, only `[f64]` property can be created.
    // Actually, there are property nodes with name=`filmboxTypeID` seems to have values
    // `5i16, 5i16, 5i16`. However, it seems that it can be regarded as single `5i16`.
    let first: f64 = match attrs.next_attribute()? {
        None => {
            props.values_empty.insert(name);
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::I16(val))) => {
            props.values_i64.insert(name, (val as i64).into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::I32(val))) => {
            props.values_i64.insert(name, (val as i64).into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::I64(val))) => {
            props.values_i64.insert(name, val.into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::F32(val))) => {
            props.values_f64.insert(name, (val as f64).into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::F64(val))) => val,
        Some(Attribute::Special(attr)) => {
            use parser::binary::SpecialAttributeType;

            let value_type = attr.value_type();
            let vec = attr.into_vec()?;
            match value_type {
                SpecialAttributeType::String => {
                    match String::from_utf8(vec) {
                        Ok(val) => {
                            props.values_string.insert(name, val.into());
                        },
                        Err(err) => {
                            props.values_binary.insert(name, err.into_bytes().into());
                        },
                    }
                },
                SpecialAttributeType::Binary => {
                    props.values_binary.insert(name, vec.into());
                },
            }
            return Ok(());
        },
        _ => return Err(Error::InvalidAttribute("P".into())),
    };

    load_property_rest_f64s(props, attrs, name, first)
}

/// Loads rest `f64` values of a `P` node in `Properties70`.
fn load_property_rest_f64s<R: ParserSource>(
    props: &mut Properties70,
    mut attrs: Attributes<R>,
    name: String,
    first: f64
) -> Result<()> {
    let invalid_attr = || Error::InvalidAttribute("P".into());

    match attrs.rest_attributes() {
        0 => {
            props.values_f64.insert(name, first.into());
            Ok(())
        },
        1 => {
            let second = attrs.convert_into()?.ok_or_else(invalid_attr)?;
            props.values_f64_2.insert(name, [first, second].into());
            Ok(())
        },
        2 => {
            let second = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let third = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            props.values_f64_3.insert(name, [first, second, third].into());
            Ok(())
        },
        3 => {
            let second = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let third = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let fourth = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            props.values_f64_4.insert(name, [first, second, third, fourth].into());
            Ok(())
        },
        15 => {
            let second = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let third = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let fourth = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let vec1 = [first, second, third, fourth];
            let vec2 = {
                let t: (f64, f64, f64, f64) = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
                [t.0, t.1, t.2, t.3]
            };
            let vec3 = {
                let t: (f64, f64, f64, f64) = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
                [t.0, t.1, t.2, t.3]
            };
            let vec4 = {
                let t: (f64, f64, f64, f64) = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
                [t.0, t.1, t.2, t.3]
            };
            props.values_f64_4x4.insert(name, [vec1, vec2, vec3, vec4].into());
            Ok(())
        },
        n => {
            error!("Supported length of node property with f64 values are 1, 2, 3, 4 and 16, but \
                    got {}",
                   n + 1);
            Err(Error::InvalidAttribute("P".into()))
        },
    }
}
<commit_msg>Make all fields of `Properties70` public<commit_after>//! `Properties70` node and its children.

use std::fmt;
use fnv::{FnvHashSet, FnvHashMap};
use parser::binary::{Parser, ParserSource, Event, Attributes};
use parser::binary::{Attribute, PrimitiveAttribute};
use loader::binary::simple::{Result, Error};

/// A type of map from property name to value of the specific type.
pub type PropertyMap<T> = FnvHashMap<String, PropertyValue<T>>;

/// Struct to store `Properties70` node data.
#[derive(Default, Clone, PartialEq)]
pub struct Properties70 {
    /// Properties without values.
    pub values_empty: FnvHashSet<String>,
    /// Values with `i64`, `i32`, or `i16` type.
    pub values_i64: PropertyMap<i64>,
    /// Values with `f64` or `f32` type.
    pub values_f64: PropertyMap<f64>,
    /// Values with `[f64; 2]` type.
    pub values_f64_2: PropertyMap<[f64; 2]>,
    /// Values with `[f64; 3]` type.
    pub values_f64_3: PropertyMap<[f64; 3]>,
    /// Values with `[f64; 4]` type.
    pub values_f64_4: PropertyMap<[f64; 4]>,
    /// Values with `[[f64; 4]; 4]` type.
    pub values_f64_4x4: PropertyMap<[[f64; 4]; 4]>,
    /// Values with `String` type.
    pub values_string: PropertyMap<String>,
    /// Values with `Vec<u8>` type (called "blob").
    pub values_binary: PropertyMap<Vec<u8>>,
}

impl Properties70 {
    /// Creates a new `Properties70`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Loads a node from the parser.
    pub fn load<R: ParserSource, P: Parser<R>>(parser: P) -> Result<Self> {
        load_properties70(parser)
    }
}

impl fmt::Debug for Properties70 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut format = f.debug_struct("Properties70");
        macro_rules! show {
            ($field:ident) => {
                if !self.$field.is_empty() {
                    format.field(stringify!($field), &self.$field);
                }
            }
        }
        show!(values_empty);
        show!(values_i64);
        show!(values_f64);
        show!(values_f64_2);
        show!(values_f64_3);
        show!(values_f64_4);
        show!(values_f64_4x4);
        show!(values_string);
        show!(values_binary);
        format.finish()
    }
}

/// A type of property value and its metadata.
///
/// Type, label, and flags will be ignored currently.
#[derive(Debug, Clone, PartialEq)]
pub struct PropertyValue<T>(T);

impl<T> PropertyValue<T> {
    /// Creates a new `PropertyValue` with the given value.
    pub fn new(v: T) -> Self {
        PropertyValue(v)
    }

    /// Returns the value.
    pub fn value(&self) -> &T {
        &self.0
    }

    /// Returns the value with the ownership.
    pub fn take_value(self) -> T {
        self.0
    }
}

impl<T> From<T> for PropertyValue<T> {
    fn from(v: T) -> Self {
        PropertyValue::new(v)
    }
}

/// Loads a `Properties70` node.
fn load_properties70<R: ParserSource, P: Parser<R>>(mut parser: P) -> Result<Properties70> {
    let mut props = Properties70::new();

    loop {
        try_get_node_attrs!(parser, |name: &str, attrs| if name == "P" {
            load_property(&mut props, attrs)
        } else {
            warn!("Expected `P` node but got `{}` in `Properties70`", name);
            Err(Error::UnexpectedNode(name.to_owned()))
        });
        parser.skip_current_node()?;
    }
    Ok(props)
}

/// Loads a `P` node in `Properties70`.
fn load_property<R: ParserSource>(
    props: &mut Properties70,
    mut attrs: Attributes<R>
) -> Result<()> {
    use parser::binary::utils::AttributeValues;

    // `type_name`, `label`, `flags` are `String`s, but ignore here because they are currently
    // unused.
    let (name, _type_name, _label, _flags) =
        <(String, (), (), ())>::from_attributes(&mut attrs)?
            .ok_or_else(|| Error::InvalidAttribute("P".to_owned()))?;

    if attrs.rest_attributes() == 0 {
        // Empty attribute.
        props.values_empty.insert(name);
        return Ok(());
    }

    // From multiple attributes, only `[f64]` property can be created.
    // Actually, there are property nodes with name=`filmboxTypeID` seems to have values
    // `5i16, 5i16, 5i16`. However, it seems that it can be regarded as single `5i16`.
    let first: f64 = match attrs.next_attribute()? {
        None => {
            props.values_empty.insert(name);
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::I16(val))) => {
            props.values_i64.insert(name, (val as i64).into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::I32(val))) => {
            props.values_i64.insert(name, (val as i64).into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::I64(val))) => {
            props.values_i64.insert(name, val.into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::F32(val))) => {
            props.values_f64.insert(name, (val as f64).into());
            return Ok(());
        },
        Some(Attribute::Primitive(PrimitiveAttribute::F64(val))) => val,
        Some(Attribute::Special(attr)) => {
            use parser::binary::SpecialAttributeType;

            let value_type = attr.value_type();
            let vec = attr.into_vec()?;
            match value_type {
                SpecialAttributeType::String => {
                    match String::from_utf8(vec) {
                        Ok(val) => {
                            props.values_string.insert(name, val.into());
                        },
                        Err(err) => {
                            props.values_binary.insert(name, err.into_bytes().into());
                        },
                    }
                },
                SpecialAttributeType::Binary => {
                    props.values_binary.insert(name, vec.into());
                },
            }
            return Ok(());
        },
        _ => return Err(Error::InvalidAttribute("P".into())),
    };

    load_property_rest_f64s(props, attrs, name, first)
}

/// Loads rest `f64` values of a `P` node in `Properties70`.
fn load_property_rest_f64s<R: ParserSource>(
    props: &mut Properties70,
    mut attrs: Attributes<R>,
    name: String,
    first: f64
) -> Result<()> {
    let invalid_attr = || Error::InvalidAttribute("P".into());

    match attrs.rest_attributes() {
        0 => {
            props.values_f64.insert(name, first.into());
            Ok(())
        },
        1 => {
            let second = attrs.convert_into()?.ok_or_else(invalid_attr)?;
            props.values_f64_2.insert(name, [first, second].into());
            Ok(())
        },
        2 => {
            let second = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let third = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            props.values_f64_3.insert(name, [first, second, third].into());
            Ok(())
        },
        3 => {
            let second = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let third = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let fourth = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            props.values_f64_4.insert(name, [first, second, third, fourth].into());
            Ok(())
        },
        15 => {
            let second = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let third = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let fourth = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
            let vec1 = [first, second, third, fourth];
            let vec2 = {
                let t: (f64, f64, f64, f64) = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
                [t.0, t.1, t.2, t.3]
            };
            let vec3 = {
                let t: (f64, f64, f64, f64) = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
                [t.0, t.1, t.2, t.3]
            };
            let vec4 = {
                let t: (f64, f64, f64, f64) = attrs.convert_into()?.ok_or_else(&invalid_attr)?;
                [t.0, t.1, t.2, t.3]
            };
            props.values_f64_4x4.insert(name, [vec1, vec2, vec3, vec4].into());
            Ok(())
        },
        n => {
            error!("Supported length of node property with f64 values are 1, 2, 3, 4 and 16, but \
                    got {}",
                   n + 1);
            Err(Error::InvalidAttribute("P".into()))
        },
    }
}
<|endoftext|>