<commit_before>extern crate byteorder;
extern crate chrono;
use std::io::Read;
use std::fs;
use std::path::Path;
use byteorder::{ByteOrder, BigEndian, LittleEndian, ReadBytesExt};
use std::collections::HashMap;
use chrono::*;
use super::fit_header::FitHeader;
use super::global_message_table::GlobalMessage;
use super::file_id_message::FileIdMessage;
use super::field_definition::FieldDefinition;
use super::fit_file::FitFile;

pub struct Decoder {
    pub file_name: String,
    pub fit_buf: Vec<u8>,
    //pub header: FitHeader,
    pub global_mesage_table: GlobalMessage,
    pub file_id_table: FileIdMessage,
    read_pos: u64,
}

impl Decoder {
    pub fn new(file_name: String) -> Decoder {
        return Decoder {
            file_name: file_name,
            fit_buf: Vec::new(),
            //header: FitHeader::default(),
            global_mesage_table: GlobalMessage::new(),
            file_id_table: FileIdMessage::new(),
            read_pos: 0,
        }
    }

    pub fn decode(&mut self) -> FitFile {
        let mut fit_file = FitFile::new();
        self.fit_buf = super::read_bin(&self.file_name);

        fit_file.header = self.decode_header();
        println!("{:?}", fit_file.header);
        self.decode_records();

        fit_file
    }

    fn decode_header(&mut self) -> FitHeader {
        let header = self.read_header();

        let header_size = header[0];

        let protocol_version = header[1];

        let protocol_profile_major = header[2];

        let protocol_profile_minor = header[3];

        let full_profile_version: u16 = (header[3] as u16) << 8 | (header[2] as u16);

        let record_size_in_bytes: u32 = (header[7] as u32) << 24 |
            (header[6] as u32) << 16 |
            (header[5] as u32) << 8 |
            (header[4] as u32);

        let mut fit_str = String::new();
        fit_str.push(header[8] as char);
        fit_str.push(header[9] as char);
        fit_str.push(header[10] as char);
        fit_str.push(header[11] as char);

        let crc: u16 = (header[13] as u16) << 8 | (header[12] as u16);

        let mut fit_header = FitHeader::default();
       fit_header.size = header_size;
       fit_header.protocol_version = protocol_version;
       fit_header.profile_version = full_profile_version;
       fit_header.fit_str = fit_str;
       fit_header.data_size = record_size_in_bytes;
       fit_header.crc = crc;

       //println!("{:?}", fit_header);

       fit_header
    }

    fn read_header(&mut self) -> Vec<u8> {
        //let word0 = self.fit_buf[0];
        //let word1 = self.fit_buf[1];

        let headerVec: Vec<u8> = self.fit_buf.iter().take(14).map(|b| *b).collect();
        self.read_pos += 14;

        return headerVec;
    }

    fn decode_records(&mut self) {
        let record_header = self.read_u8();
        self.read_u8(); // read and ignore a since the next byte is reserved
        println!("{:#b}", record_header);
        let arch = self.read_u8(); //TODO: Handle Endianess better
        println!("{:#b}", arch);

        let mut two_bytes = self.read_bytes(2);
        let global_message_number = LittleEndian::read_u16(&two_bytes);
        println!("Global Message Number: {}", global_message_number);

        let global_message = self.global_mesage_table.get(global_message_number);
        println!("Global Message: {}", global_message);

        let num_fields = self.read_u8();
        println!("Number of Fields: {}", num_fields);

        for f in 0..num_fields {
            let field_def_num = self.read_u8();
            let size = self.read_u8();
            let base_type = self.read_u8();

            let field_kind = self.file_id_table.get(field_def_num);

            println!("{}: {}  {}  {}", field_kind, field_def_num, size, base_type);
        }

        //TODO: Handle pos better
        let data_header = self.read_u8();
        println!("{:#b}", data_header);

        let mut four_bytes = self.read_bytes(4);
        let serial_number = LittleEndian::read_u32(&four_bytes);
        println!("Serial Number: {}", serial_number);

        four_bytes = self.read_bytes(4);
        let time_created = LittleEndian::read_u32(&four_bytes);
        println!("Time Created: {}", time_created);

        let d = UTC.ymd(1989, 12, 31);
        let sum = d + Duration::seconds(time_created as i64);
        println!("Date: {}", sum);

        two_bytes = self.read_bytes(2);
        let manufacturer = LittleEndian::read_u16(&two_bytes);
        println!("Manf: {}", manufacturer);

        two_bytes = self.read_bytes(2);
        let product = LittleEndian::read_u16(&two_bytes);
        println!("Product: {}", product);

        let t = self.read_byte();
        println!("Type: {}", t);
    }

    fn read_u8(&mut self) -> u8 {
        let byte = self.fit_buf[self.read_pos as usize];
        self.read_pos += 1;
        byte
    }

    fn read_byte(&mut self) -> u8{
        let byte = self.fit_buf[self.read_pos as usize];
        self.read_pos += 1;
        byte
    }

    fn read_bytes(&mut self, amount: u32) -> Vec<u8> {
        let mut result = Vec::new();
        for _ in 0..amount {
            let read0 = self.fit_buf[self.read_pos as usize];
            result.push(read0);
            self.read_pos += 1;
        }

        result
    }
}

/*fn read_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut file = fs::File::open(path).unwrap();
    let mut file_buf = Vec::new();
    file.read_to_end(&mut file_buf).unwrap();
    file_buf
}
*/
<commit_msg>Refactoring and organizing code<commit_after>extern crate byteorder;
extern crate chrono;
use std::io::Read;
use std::fs;
use std::path::Path;
use byteorder::{ByteOrder, BigEndian, LittleEndian, ReadBytesExt};
use std::collections::HashMap;
use chrono::*;
use super::fit_header::FitHeader;
use super::global_message_table::GlobalMessage;
use super::file_id_message::FileIdMessage;
use super::field_definition::FieldDefinition;
use super::fit_file::FitFile;
use super::record_content::RecordContent;

pub struct Decoder {
    pub file_name: String,
    pub fit_buf: Vec<u8>,
    //pub header: FitHeader,
    pub global_mesage_table: GlobalMessage,
    pub file_id_table: FileIdMessage,
    read_pos: u64,
}

impl Decoder {
    pub fn new(file_name: String) -> Decoder {
        return Decoder {
            file_name: file_name,
            fit_buf: Vec::new(),
            //header: FitHeader::default(),
            global_mesage_table: GlobalMessage::new(),
            file_id_table: FileIdMessage::new(),
            read_pos: 0,
        }
    }

    pub fn decode(&mut self) -> FitFile {
        let mut fit_file = FitFile::new();
        self.fit_buf = super::read_bin(&self.file_name);

        fit_file.header = self.decode_header();
        println!("{:?}", fit_file.header);
        let record_content = self.decode_records();
        fit_file.data = record_content;

        fit_file
    }

    fn decode_header(&mut self) -> FitHeader {
        let header = self.read_header();

        let header_size = header[0];

        let protocol_version = header[1];

        let protocol_profile_major = header[2];

        let protocol_profile_minor = header[3];

        let full_profile_version: u16 = (header[3] as u16) << 8 | (header[2] as u16);

        let record_size_in_bytes: u32 = (header[7] as u32) << 24 |
            (header[6] as u32) << 16 |
            (header[5] as u32) << 8 |
            (header[4] as u32);

        let mut fit_str = String::new();
        fit_str.push(header[8] as char);
        fit_str.push(header[9] as char);
        fit_str.push(header[10] as char);
        fit_str.push(header[11] as char);

        let crc: u16 = (header[13] as u16) << 8 | (header[12] as u16);

        let mut fit_header = FitHeader::default();
        fit_header.size = header_size;
        fit_header.protocol_version = protocol_version;
        fit_header.profile_version = full_profile_version;
        fit_header.fit_str = fit_str;
        fit_header.data_size = record_size_in_bytes;
        fit_header.crc = crc;

        //println!("{:?}", fit_header);

        fit_header
    }

    fn read_header(&mut self) -> Vec<u8> {
        //let word0 = self.fit_buf[0];
        //let word1 = self.fit_buf[1];

        let headerVec: Vec<u8> = self.fit_buf.iter().take(14).map(|b| *b).collect();
        self.read_pos += 14;

        return headerVec;
    }

    fn decode_records(&mut self) -> RecordContent {
        let mut record_content = RecordContent::new();
        let record_header = self.read_u8();
        self.read_u8(); // read and ignore a since the next byte is reserved
        println!("{:#b}", record_header);
        let arch = self.read_u8(); //TODO: Handle Endianess better
        println!("{:#b}", arch);

        let mut two_bytes = self.read_bytes(2);
        let global_message_number = LittleEndian::read_u16(&two_bytes);
        println!("Global Message Number: {}", global_message_number);

        let global_message = self.global_mesage_table.get(global_message_number);
        println!("Global Message: {}", global_message);

        let num_fields = self.read_u8();
        println!("Number of Fields: {}", num_fields);

        for f in 0..num_fields {
            let field_def_num = self.read_u8();
            let size = self.read_u8();
            let base_type = self.read_u8();

            let field_kind = self.file_id_table.get(field_def_num);

            println!("{}: {}  {}  {}", field_kind, field_def_num, size, base_type);
        }

        //TODO: Handle pos better
        let data_header = self.read_u8();
        println!("{:#b}", data_header);

        let mut four_bytes = self.read_bytes(4);
        let serial_number = LittleEndian::read_u32(&four_bytes);
        println!("Serial Number: {}", serial_number);

        four_bytes = self.read_bytes(4);
        let time_created = LittleEndian::read_u32(&four_bytes);
        println!("Time Created: {}", time_created);

        let d = UTC.ymd(1989, 12, 31);
        let sum = d + Duration::seconds(time_created as i64);
        println!("Date: {}", sum);

        two_bytes = self.read_bytes(2);
        let manufacturer = LittleEndian::read_u16(&two_bytes);
        println!("Manf: {}", manufacturer);

        two_bytes = self.read_bytes(2);
        let product = LittleEndian::read_u16(&two_bytes);
        println!("Product: {}", product);

        let t = self.read_byte();
        println!("Type: {}", t);

        record_content
    }

    fn read_u8(&mut self) -> u8 {
        let byte = self.fit_buf[self.read_pos as usize];
        self.read_pos += 1;
        byte
    }

    fn read_byte(&mut self) -> u8{
        let byte = self.fit_buf[self.read_pos as usize];
        self.read_pos += 1;
        byte
    }

    fn read_bytes(&mut self, amount: u32) -> Vec<u8> {
        let mut result = Vec::new();
        for _ in 0..amount {
            let read0 = self.fit_buf[self.read_pos as usize];
            result.push(read0);
            self.read_pos += 1;
        }

        result
    }
}

/*fn read_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
  let mut file = fs::File::open(path).unwrap();
  let mut file_buf = Vec::new();
  file.read_to_end(&mut file_buf).unwrap();
  file_buf
  }
  */
<|endoftext|>


<commit_before>//! Endpoints for getting and synchronizing events.

/// [GET /_matrix/client/r0/rooms/{roomId}/state](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state)
pub mod get_state_events {
    use ruma_identifiers::RoomId;
    use ruma_events::collections::only;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = Vec<only::StateEvent>;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/state",
                params.room_id
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/state".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype)
pub mod get_state_event_by_event_type {
    use ruma_identifiers::RoomId;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
        pub event_type: String
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = ::serde_json::Value;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/state/{}",
                params.room_id,
                params.event_type
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/state/:event_type".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-state-key)
pub mod get_state_event_by_state_key {
    use ruma_identifiers::RoomId;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
        pub event_type: String,
        pub state_key: String,
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = ::serde_json::Value;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/state/{}/{}",
                params.room_id,
                params.event_type,
                params.state_key
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/members](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-members)
pub mod get_member_events {
    use ruma_identifiers::RoomId;
    use ruma_events::room::member::MemberEvent;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub chunks: Vec<MemberEvent>
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/members",
                params.room_id,
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/members".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/messages](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages)
pub mod get_message_events {
    use ruma_identifiers::RoomId;
    use ruma_events::collections::only;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
        pub event_type: String
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum Direction {
        #[serde(rename="b")]
        Backward,
        #[serde(rename="f")]
        Forward
    }

    /// This API endpoint's query parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct QueryParams {
        pub from: String,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub to: Option<String>,
        pub dir: Direction,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub limit: Option<u64>
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub start: String,
        pub chunks: Vec<only::RoomEvent>,
        pub end: String
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = QueryParams;
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/messages",
                params.room_id,
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/messages".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/sync](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync)
pub mod sync_events {
    use ruma_events::collections::only;
    use ruma_identifiers::RoomId;

    use std::collections::HashMap;

    use r0::filter::FilterDefinition;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// Whether to set presence or not during sync.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum SetPresence {
        #[serde(rename="offline")]
        Offline
    }

    /// A filter represented either as its full JSON definition or the ID of a saved filter.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum Filter {
        /// A complete filter definition serialized to JSON.
        FilterDefinition(FilterDefinition),
        /// The ID of a filter saved on the server.
        FilterId(String),
    }

    /// This API endpoint's query parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct QueryParams {
        #[serde(skip_serializing_if = "Option::is_none")]
        pub filter: Option<Filter>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub since: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub full_state: Option<bool>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub set_presence: Option<SetPresence>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub timeout: Option<u64>
    }

    /// Updates to rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Rooms {
        pub leave: HashMap<RoomId, LeftRoom>,
        pub join: HashMap<RoomId, JoinedRoom>,
        pub invite: HashMap<RoomId, InvitedRoom>
    }

    /// Historical updates to left rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct LeftRoom {
        pub timeline: Timeline,
        pub state: State
    }

    /// Updates to joined rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct JoinedRoom {
        pub unread_notifications: UnreadNotificationsCount,
        pub timeline: Timeline,
        pub state: State,
        pub account_data: AccountData,
        pub ephemeral: Ephemeral
    }

    /// unread notifications count
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct UnreadNotificationsCount {
        pub highlight_count: u64,
        pub notification_count: u64
    }

    /// timeline
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Timeline {
        pub limited: bool,
        pub prev_batch: String,
        pub events: only::RoomEvent
    }

    /// state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct State {
        pub events: only::StateEvent
    }

    /// account data
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct AccountData {
        pub events: only::Event
    }

    /// ephemeral
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Ephemeral {
        pub events: only::Event
    }

    /// invited room updates
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InvitedRoom {
        pub invite_state: InviteState
    }

    /// invite state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InviteState {
        pub events: only::StateEvent
    }

    /// presence
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Presence {
        pub events: only::Event
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub next_batch: String,
        pub rooms: Rooms,
        pub presence: Presence
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = ();
        type QueryParams = QueryParams;
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(_params: Self::PathParams) -> String {
            "/_matrix/client/r0/sync".to_string()
        }

        fn router_path() -> String {
            "/_matrix/client/r0/sync".to_string()
        }
    }
}
<commit_msg>Use consistent wording for QueryParams docs.<commit_after>//! Endpoints for getting and synchronizing events.

/// [GET /_matrix/client/r0/rooms/{roomId}/state](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state)
pub mod get_state_events {
    use ruma_identifiers::RoomId;
    use ruma_events::collections::only;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = Vec<only::StateEvent>;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/state",
                params.room_id
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/state".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype)
pub mod get_state_event_by_event_type {
    use ruma_identifiers::RoomId;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
        pub event_type: String
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = ::serde_json::Value;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/state/{}",
                params.room_id,
                params.event_type
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/state/:event_type".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-state-key)
pub mod get_state_event_by_state_key {
    use ruma_identifiers::RoomId;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
        pub event_type: String,
        pub state_key: String,
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = ::serde_json::Value;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/state/{}/{}",
                params.room_id,
                params.event_type,
                params.state_key
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/state/:event_type/:state_key".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/members](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-members)
pub mod get_member_events {
    use ruma_identifiers::RoomId;
    use ruma_events::room::member::MemberEvent;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub chunks: Vec<MemberEvent>
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = ();
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/members",
                params.room_id,
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/members".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/rooms/{roomId}/messages](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages)
pub mod get_message_events {
    use ruma_identifiers::RoomId;
    use ruma_events::collections::only;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// This API endpoint's path parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct PathParams {
        pub room_id: RoomId,
        pub event_type: String
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum Direction {
        #[serde(rename="b")]
        Backward,
        #[serde(rename="f")]
        Forward
    }

    /// This API endpoint's query string parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct QueryParams {
        pub from: String,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub to: Option<String>,
        pub dir: Direction,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub limit: Option<u64>
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub start: String,
        pub chunks: Vec<only::RoomEvent>,
        pub end: String
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = PathParams;
        type QueryParams = QueryParams;
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(params: Self::PathParams) -> String {
            format!(
                "/_matrix/client/r0/rooms/{}/messages",
                params.room_id,
            )
        }

        fn router_path() -> String {
            "/_matrix/client/r0/rooms/:room_id/messages".to_string()
        }
    }
}

/// [GET /_matrix/client/r0/sync](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync)
pub mod sync_events {
    use ruma_events::collections::only;
    use ruma_identifiers::RoomId;

    use std::collections::HashMap;

    use r0::filter::FilterDefinition;

    /// Details about this API endpoint.
    pub struct Endpoint;

    /// Whether to set presence or not during sync.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum SetPresence {
        #[serde(rename="offline")]
        Offline
    }

    /// A filter represented either as its full JSON definition or the ID of a saved filter.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub enum Filter {
        /// A complete filter definition serialized to JSON.
        FilterDefinition(FilterDefinition),
        /// The ID of a filter saved on the server.
        FilterId(String),
    }

    /// This API endpoint's query string parameters.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct QueryParams {
        #[serde(skip_serializing_if = "Option::is_none")]
        pub filter: Option<Filter>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub since: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub full_state: Option<bool>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub set_presence: Option<SetPresence>,
        #[serde(skip_serializing_if = "Option::is_none")]
        pub timeout: Option<u64>
    }

    /// Updates to rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Rooms {
        pub leave: HashMap<RoomId, LeftRoom>,
        pub join: HashMap<RoomId, JoinedRoom>,
        pub invite: HashMap<RoomId, InvitedRoom>
    }

    /// Historical updates to left rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct LeftRoom {
        pub timeline: Timeline,
        pub state: State
    }

    /// Updates to joined rooms
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct JoinedRoom {
        pub unread_notifications: UnreadNotificationsCount,
        pub timeline: Timeline,
        pub state: State,
        pub account_data: AccountData,
        pub ephemeral: Ephemeral
    }

    /// unread notifications count
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct UnreadNotificationsCount {
        pub highlight_count: u64,
        pub notification_count: u64
    }

    /// timeline
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Timeline {
        pub limited: bool,
        pub prev_batch: String,
        pub events: only::RoomEvent
    }

    /// state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct State {
        pub events: only::StateEvent
    }

    /// account data
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct AccountData {
        pub events: only::Event
    }

    /// ephemeral
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Ephemeral {
        pub events: only::Event
    }

    /// invited room updates
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InvitedRoom {
        pub invite_state: InviteState
    }

    /// invite state
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct InviteState {
        pub events: only::StateEvent
    }

    /// presence
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Presence {
        pub events: only::Event
    }

    /// This API endpoint's reponse.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct Response {
        pub next_batch: String,
        pub rooms: Rooms,
        pub presence: Presence
    }

    impl ::Endpoint for Endpoint {
        type BodyParams = ();
        type PathParams = ();
        type QueryParams = QueryParams;
        type Response = Response;

        fn method() -> ::Method {
            ::Method::Get
        }

        fn request_path(_params: Self::PathParams) -> String {
            "/_matrix/client/r0/sync".to_string()
        }

        fn router_path() -> String {
            "/_matrix/client/r0/sync".to_string()
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::str;

#[derive(Debug)]
pub enum RedisResult {
    Array(Vec<RedisResult>),
    Bytes(Vec<u8>),
    String(String),
    Int(i64),
    Nil,
}

impl RedisResult {
    pub fn convert<T: From<RedisResult>>(self) -> T {
        self.into()
    }
}

impl fmt::Display for RedisResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RedisResult::Array(ref value) => write!(f, "{:?}", value),
            RedisResult::Bytes(ref value) => write!(f, "{:?}", value),
            RedisResult::String(ref value) => write!(f, "{:?}", value),
            RedisResult::Int(ref value) => write!(f, "{:?}", value),
            RedisResult::Nil => write!(f, "null"),
        }
    }
}

impl From<RedisResult> for String {
    fn from(result: RedisResult) -> String {
        match result {
            RedisResult::Array(_value) => "Array cannot be stringified".to_string(),
            RedisResult::Bytes(value) => str::from_utf8(&value).unwrap().to_string(),
            RedisResult::String(value) => value,
            RedisResult::Int(value) => value.to_string(),
            RedisResult::Nil => "null".to_string(),
        }
    }
}

impl From<RedisResult> for Vec<u8> {
    fn from(result: RedisResult) -> Vec<u8> {
        match result {
            RedisResult::Array(_value) => vec![],
            RedisResult::Bytes(value) => value,
            RedisResult::String(value) => value.into_bytes(),
            RedisResult::Int(value) => value.to_string().into_bytes(),
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for Vec<String> {
    fn from(result: RedisResult) -> Vec<String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = Vec::new();
                for res in value {
                    retval.push(res.convert::<String>());
                }
                retval
            },
            RedisResult::Bytes(_value) => vec![],
            RedisResult::String(value) => vec![value],
            RedisResult::Int(value) => vec![value.to_string()],
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for HashMap<String, String> {
    fn from(result: RedisResult) -> HashMap<String, String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = HashMap::new();
                let mut key = String::new();
                for (index, res) in value.into_iter().enumerate() {
                    if index % 2 == 0 {
                        key = res.convert::<String>();
                    } else {
                        retval.insert(key.to_string(), res.convert::<String>());
                    }
                }
                retval
            },
            _ => HashMap::new(),
        }
    }
}

impl From<RedisResult> for i64 {
    fn from(result: RedisResult) -> i64 {
        match result {
            RedisResult::Array(_value) => 0,
            RedisResult::Bytes(_value) => 0,
            RedisResult::String(_value) => 0,
            RedisResult::Int(value) => value,
            RedisResult::Nil => 0,
        }
    }
}

<commit_msg>completes implementation of the From trait for RedisResult<commit_after>use std::collections::HashMap;
use std::fmt;
use std::str;

#[derive(Debug)]
pub enum RedisResult {
    Array(Vec<RedisResult>),
    Bytes(Vec<u8>),
    String(String),
    Int(i64),
    Nil,
}

impl RedisResult {
    pub fn convert<T: From<RedisResult>>(self) -> T {
        self.into()
    }
}

impl fmt::Display for RedisResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RedisResult::Array(ref value) => write!(f, "{:?}", value),
            RedisResult::Bytes(ref value) => write!(f, "{:?}", value),
            RedisResult::String(ref value) => write!(f, "{:?}", value),
            RedisResult::Int(ref value) => write!(f, "{:?}", value),
            RedisResult::Nil => write!(f, "null"),
        }
    }
}

impl From<RedisResult> for String {
    fn from(result: RedisResult) -> String {
        match result {
            RedisResult::Array(value) => {
                let mut retval: String = "[".to_string();
                for res in value {
                    retval = retval + &res.convert::<String>() + &",".to_string();
                }
                retval = retval + &"]".to_string();
                retval
            },
            RedisResult::Bytes(value) => {
                let result = str::from_utf8(&value);
                match result {
                    Ok(str_value) => str_value.to_string(),
                    Err(err) => err.to_string(),
                }
            },
            RedisResult::String(value) => value,
            RedisResult::Int(value) => value.to_string(),
            RedisResult::Nil => "null".to_string(),
        }
    }
}

impl From<RedisResult> for Vec<u8> {
    fn from(result: RedisResult) -> Vec<u8> {
        match result {
            RedisResult::Array(value) => RedisResult::Array(value).convert::<String>().into_bytes(),
            RedisResult::Bytes(value) => value,
            RedisResult::String(value) => value.into_bytes(),
            RedisResult::Int(value) => value.to_string().into_bytes(),
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for Vec<String> {
    fn from(result: RedisResult) -> Vec<String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = Vec::new();
                for res in value {
                    retval.push(res.convert::<String>());
                }
                retval
            },
            RedisResult::Bytes(value) => {
                let result = str::from_utf8(&value);
                match result {
                    Ok(str_value) => vec![str_value.to_string()],
                    Err(err) => vec![err.to_string()],
                }
            },
            RedisResult::String(value) => vec![value],
            RedisResult::Int(value) => vec![value.to_string()],
            RedisResult::Nil => vec![],
        }
    }
}

impl From<RedisResult> for HashMap<String, String> {
    fn from(result: RedisResult) -> HashMap<String, String> {
        match result {
            RedisResult::Array(value) => {
                let mut retval = HashMap::new();
                let mut key = String::new();
                for (index, res) in value.into_iter().enumerate() {
                    if index % 2 == 0 {
                        key = res.convert::<String>();
                    } else {
                        retval.insert(key.to_string(), res.convert::<String>());
                    }
                }
                retval
            },
            RedisResult::Bytes(value) => {
                let str_value = RedisResult::Bytes(value).convert::<String>();
                let mut retval = HashMap::new();
                retval.insert("Stringified value".to_string(), str_value);
                retval
            },
            RedisResult::String(value) => {
                let mut retval = HashMap::new();
                retval.insert("Stringified value".to_string(), value);
                retval
            },
            RedisResult::Int(value) => {
                let str_value = RedisResult::Int(value).convert::<String>();
                let mut retval = HashMap::new();
                retval.insert("Stringified value".to_string(), str_value);
                retval
            },
            RedisResult::Nil => {
                let str_value = RedisResult::Nil.convert::<String>();
                let mut retval = HashMap::new();
                retval.insert("Stringified value".to_string(), str_value);
                retval
            },
        }
    }
}

impl From<RedisResult> for i64 {
    fn from(result: RedisResult) -> i64 {
        match result {
            RedisResult::Array(_value) => 0,
            RedisResult::Bytes(_value) => 0,
            RedisResult::String(_value) => 0,
            RedisResult::Int(value) => value,
            RedisResult::Nil => 0,
        }
    }
}

<|endoftext|>


<commit_before>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1])
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

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

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> libc::mode_t {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: libc::mode_t) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(file: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use super::{Direction, History};
    use config::Config;

    fn init() -> super::History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Fix warning on windows<commit_after>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1])
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

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

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> libc::mode_t {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: libc::mode_t) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(_: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use super::{Direction, History};
    use config::Config;

    fn init() -> super::History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_trait_method, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{MultiSpan, Span};

const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";

pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    check_needless_collect_direct_usage(expr, cx);
    check_needless_collect_indirect_usage(expr, cx);
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    if_chain! {
        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
        if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
        if let Some(generic_args) = chain_method.args;
        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
        if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
        then {
            let mut applicability = Applicability::MachineApplicable;
            let is_empty_sugg = "next().is_none()".to_string();
            let method_name = &*method.ident.name.as_str();
            let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                        is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                        is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
                        is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
                match method_name {
                    "len" => "count()".to_string(),
                    "is_empty" => is_empty_sugg,
                    "contains" => {
                        let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
                        let (arg, pred) = contains_arg
                            .strip_prefix('&')
                            .map_or(("&x", &*contains_arg), |s| ("x", s));
                        format!("any(|{}| x == {})", arg, pred)
                    }
                    _ => return,
                }
            }
            else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
                is_type_diagnostic_item(cx, ty, sym::hashmap_type) {
                match method_name {
                    "is_empty" => is_empty_sugg,
                    _ => return,
                }
            }
            else {
                return;
            };
            span_lint_and_sugg(
                cx,
                NEEDLESS_COLLECT,
                method0_span.with_hi(expr.span.hi()),
                NEEDLESS_COLLECT_MSG,
                "replace with",
                sugg,
                applicability,
            );
        }
    }
}

fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
        if let Some(ty) = ty {
            return Some(ty.hir_id);
        }

        if let Some(generic_args) = method_args {
            if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
                return Some(ty.hir_id);
            }
        }

        None
    }
    if let ExprKind::Block(block, _) = expr.kind {
        for stmt in block.stmts {
            if_chain! {
                if let StmtKind::Local(
                    Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
                    init: Some(init_expr), ty, .. }
                ) = stmt.kind;
                if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
                if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
                if let Some(hir_id) = get_hir_id(*ty, method_name.args);
                if let Some(ty) = cx.typeck_results().node_type_opt(hir_id);
                if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                    is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                    is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
                    is_type_diagnostic_item(cx, ty, sym::LinkedList);
                if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
                if let [iter_call] = &*iter_calls;
                then {
                    let mut used_count_visitor = UsedCountVisitor {
                        cx,
                        id: *pat_id,
                        count: 0,
                    };
                    walk_block(&mut used_count_visitor, block);
                    if used_count_visitor.count > 1 {
                        return;
                    }

                    // Suggest replacing iter_call with iter_replacement, and removing stmt
                    let mut span = MultiSpan::from_span(collect_span);
                    span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
                    span_lint_hir_and_then(
                        cx,
                        super::NEEDLESS_COLLECT,
                        init_expr.hir_id,
                        span,
                        NEEDLESS_COLLECT_MSG,
                        |diag| {
                            let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
                            diag.multipart_suggestion(
                                iter_call.get_suggestion_text(),
                                vec![
                                    (stmt.span, String::new()),
                                    (iter_call.span, iter_replacement)
                                ],
                                Applicability::MachineApplicable,// MaybeIncorrect,
                            );
                        },
                    );
                }
            }
        }
    }
}

struct IterFunction {
    func: IterFunctionKind,
    span: Span,
}
impl IterFunction {
    fn get_iter_method(&self, cx: &LateContext<'_>) -> String {
        match &self.func {
            IterFunctionKind::IntoIter => String::new(),
            IterFunctionKind::Len => String::from(".count()"),
            IterFunctionKind::IsEmpty => String::from(".next().is_none()"),
            IterFunctionKind::Contains(span) => {
                let s = snippet(cx, *span, "..");
                if let Some(stripped) = s.strip_prefix('&') {
                    format!(".any(|x| x == {})", stripped)
                } else {
                    format!(".any(|x| x == *{})", s)
                }
            },
        }
    }
    fn get_suggestion_text(&self) -> &'static str {
        match &self.func {
            IterFunctionKind::IntoIter => {
                "use the original Iterator instead of collecting it and then producing a new one"
            },
            IterFunctionKind::Len => {
                "take the original Iterator's count instead of collecting it and finding the length"
            },
            IterFunctionKind::IsEmpty => {
                "check if the original Iterator has anything instead of collecting it and seeing if it's empty"
            },
            IterFunctionKind::Contains(_) => {
                "check if the original Iterator contains an element instead of collecting then checking"
            },
        }
    }
}
enum IterFunctionKind {
    IntoIter,
    Len,
    IsEmpty,
    Contains(Span),
}

struct IterFunctionVisitor {
    uses: Vec<IterFunction>,
    seen_other: bool,
    target: Ident,
}
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
        // Check function calls on our collection
        if_chain! {
            if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0);
            if let &[name] = &path.segments;
            if name.ident == self.target;
            then {
                let len = sym!(len);
                let is_empty = sym!(is_empty);
                let contains = sym!(contains);
                match method_name.ident.name {
                    sym::into_iter => self.uses.push(
                        IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
                    ),
                    name if name == len => self.uses.push(
                        IterFunction { func: IterFunctionKind::Len, span: expr.span }
                    ),
                    name if name == is_empty => self.uses.push(
                        IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
                    ),
                    name if name == contains => self.uses.push(
                        IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
                    ),
                    _ => self.seen_other = true,
                }
                return
            }
        }
        // Check if the collection is used for anything else
        if_chain! {
            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr;
            if let &[name] = &path.segments;
            if name.ident == self.target;
            then {
                self.seen_other = true;
            } else {
                walk_expr(self, expr);
            }
        }
    }

    type Map = Map<'tcx>;
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

struct UsedCountVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    id: HirId,
    count: usize,
}

impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if path_to_local_id(expr, self.id) {
            self.count += 1;
        } else {
            walk_expr(self, expr);
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
    }
}

/// Detect the occurrences of calls to `iter` or `into_iter` for the
/// given identifier
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
    let mut visitor = IterFunctionVisitor {
        uses: Vec::new(),
        target: identifier,
        seen_other: false,
    };
    visitor.visit_block(block);
    if visitor.seen_other { None } else { Some(visitor.uses) }
}
<commit_msg>Fix needless_collect with binding shadowing<commit_after>use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_trait_method, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, PatKind, StmtKind, Ty};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_span::sym;
use rustc_span::{MultiSpan, Span};

const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";

pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    check_needless_collect_direct_usage(expr, cx);
    check_needless_collect_indirect_usage(expr, cx);
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    if_chain! {
        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
        if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
        if let Some(generic_args) = chain_method.args;
        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
        if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
        then {
            let mut applicability = Applicability::MachineApplicable;
            let is_empty_sugg = "next().is_none()".to_string();
            let method_name = &*method.ident.name.as_str();
            let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                        is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                        is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
                        is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
                match method_name {
                    "len" => "count()".to_string(),
                    "is_empty" => is_empty_sugg,
                    "contains" => {
                        let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
                        let (arg, pred) = contains_arg
                            .strip_prefix('&')
                            .map_or(("&x", &*contains_arg), |s| ("x", s));
                        format!("any(|{}| x == {})", arg, pred)
                    }
                    _ => return,
                }
            }
            else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
                is_type_diagnostic_item(cx, ty, sym::hashmap_type) {
                match method_name {
                    "is_empty" => is_empty_sugg,
                    _ => return,
                }
            }
            else {
                return;
            };
            span_lint_and_sugg(
                cx,
                NEEDLESS_COLLECT,
                method0_span.with_hi(expr.span.hi()),
                NEEDLESS_COLLECT_MSG,
                "replace with",
                sugg,
                applicability,
            );
        }
    }
}

fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
        if let Some(ty) = ty {
            return Some(ty.hir_id);
        }

        if let Some(generic_args) = method_args {
            if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
                return Some(ty.hir_id);
            }
        }

        None
    }
    if let ExprKind::Block(block, _) = expr.kind {
        for stmt in block.stmts {
            if_chain! {
                if let StmtKind::Local(local) = stmt.kind;
                if let PatKind::Binding(_, id, ..) = local.pat.kind;
                if let Some(init_expr) = local.init;
                if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
                if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
                if let Some(hir_id) = get_hir_id(local.ty, method_name.args);
                if let Some(ty) = cx.typeck_results().node_type_opt(hir_id);
                if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                    is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                    is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
                    is_type_diagnostic_item(cx, ty, sym::LinkedList);
                if let Some(iter_calls) = detect_iter_and_into_iters(block, id);
                if let [iter_call] = &*iter_calls;
                then {
                    let mut used_count_visitor = UsedCountVisitor {
                        cx,
                        id,
                        count: 0,
                    };
                    walk_block(&mut used_count_visitor, block);
                    if used_count_visitor.count > 1 {
                        return;
                    }

                    // Suggest replacing iter_call with iter_replacement, and removing stmt
                    let mut span = MultiSpan::from_span(collect_span);
                    span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
                    span_lint_hir_and_then(
                        cx,
                        super::NEEDLESS_COLLECT,
                        init_expr.hir_id,
                        span,
                        NEEDLESS_COLLECT_MSG,
                        |diag| {
                            let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
                            diag.multipart_suggestion(
                                iter_call.get_suggestion_text(),
                                vec![
                                    (stmt.span, String::new()),
                                    (iter_call.span, iter_replacement)
                                ],
                                Applicability::MachineApplicable,// MaybeIncorrect,
                            );
                        },
                    );
                }
            }
        }
    }
}

struct IterFunction {
    func: IterFunctionKind,
    span: Span,
}
impl IterFunction {
    fn get_iter_method(&self, cx: &LateContext<'_>) -> String {
        match &self.func {
            IterFunctionKind::IntoIter => String::new(),
            IterFunctionKind::Len => String::from(".count()"),
            IterFunctionKind::IsEmpty => String::from(".next().is_none()"),
            IterFunctionKind::Contains(span) => {
                let s = snippet(cx, *span, "..");
                if let Some(stripped) = s.strip_prefix('&') {
                    format!(".any(|x| x == {})", stripped)
                } else {
                    format!(".any(|x| x == *{})", s)
                }
            },
        }
    }
    fn get_suggestion_text(&self) -> &'static str {
        match &self.func {
            IterFunctionKind::IntoIter => {
                "use the original Iterator instead of collecting it and then producing a new one"
            },
            IterFunctionKind::Len => {
                "take the original Iterator's count instead of collecting it and finding the length"
            },
            IterFunctionKind::IsEmpty => {
                "check if the original Iterator has anything instead of collecting it and seeing if it's empty"
            },
            IterFunctionKind::Contains(_) => {
                "check if the original Iterator contains an element instead of collecting then checking"
            },
        }
    }
}
enum IterFunctionKind {
    IntoIter,
    Len,
    IsEmpty,
    Contains(Span),
}

struct IterFunctionVisitor {
    uses: Vec<IterFunction>,
    seen_other: bool,
    target: HirId,
}
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
        // Check function calls on our collection
        if let ExprKind::MethodCall(method_name, _, [recv, args @ ..], _) = &expr.kind {
            if path_to_local_id(recv, self.target) {
                match &*method_name.ident.name.as_str() {
                    "into_iter" => self.uses.push(IterFunction {
                        func: IterFunctionKind::IntoIter,
                        span: expr.span,
                    }),
                    "len" => self.uses.push(IterFunction {
                        func: IterFunctionKind::Len,
                        span: expr.span,
                    }),
                    "is_empty" => self.uses.push(IterFunction {
                        func: IterFunctionKind::IsEmpty,
                        span: expr.span,
                    }),
                    "contains" => self.uses.push(IterFunction {
                        func: IterFunctionKind::Contains(args[0].span),
                        span: expr.span,
                    }),
                    _ => self.seen_other = true,
                }
                return;
            }
        }
        // Check if the collection is used for anything else
        if path_to_local_id(expr, self.target) {
            self.seen_other = true;
        } else {
            walk_expr(self, expr);
        }
    }

    type Map = Map<'tcx>;
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

struct UsedCountVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    id: HirId,
    count: usize,
}

impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if path_to_local_id(expr, self.id) {
            self.count += 1;
        } else {
            walk_expr(self, expr);
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
    }
}

/// Detect the occurrences of calls to `iter` or `into_iter` for the
/// given identifier
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, id: HirId) -> Option<Vec<IterFunction>> {
    let mut visitor = IterFunctionVisitor {
        uses: Vec::new(),
        target: id,
        seen_other: false,
    };
    visitor.visit_block(block);
    if visitor.seen_other { None } else { Some(visitor.uses) }
}
<|endoftext|>