<commit_before>#![feature(test)]
extern crate test;
extern crate uuid;
#[cfg(feature = "slog")]
#[macro_use]
extern crate slog;
use test::Bencher;
use uuid::Uuid;
#[cfg(feature = "slog")]
use slog::Drain;

#[bench]
fn bench_parse(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("");
        let _ = Uuid::parse_str("!");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8");
        let _ = Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8");

        // Valid
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546");
        let _ = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8");

        // Nil
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000");

        // Test error reporting
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd");
        let _ = Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4");
    });
}

#[bench]
fn bench_parse_invalid_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_character(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_group_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
    });
}

#[bench]
fn bench_parse_invalid_groups(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
    });
}

#[bench]
fn bench_valid_hyphenated(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
    });
}

#[bench]
fn bench_valid_short(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
    });
}

#[cfg(feature = "slog")]
#[bench]
fn bench_log_discard_kv(b: &mut Bencher) {
    let root = slog::Logger::root(slog::Discard.fuse(), o!());
    let u1 = Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap();
    b.iter(|| {
        crit!(root, "test"; "u1" => u1);
    });
}
<commit_msg>fmt fixed<commit_after>#![feature(test)]
#[cfg(feature = "slog")]
#[macro_use]
extern crate slog;
extern crate test;
extern crate uuid;
use test::Bencher;
use uuid::Uuid;
#[cfg(feature = "slog")]
use slog::Drain;

#[bench]
fn bench_parse(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("");
        let _ = Uuid::parse_str("!");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8");
        let _ = Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8");

        // Valid
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546");
        let _ = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8");

        // Nil
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000");

        // Test error reporting
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd");
        let _ = Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4");
    });
}

#[bench]
fn bench_parse_invalid_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_character(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_group_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
    });
}

#[bench]
fn bench_parse_invalid_groups(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
    });
}

#[bench]
fn bench_valid_hyphenated(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
    });
}

#[bench]
fn bench_valid_short(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
    });
}

#[cfg(feature = "slog")]
#[bench]
fn bench_log_discard_kv(b: &mut Bencher) {
    let root = slog::Logger::root(slog::Discard.fuse(), o!());
    let u1 = Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap();
    b.iter(|| {
        crit!(root, "test"; "u1" => u1);
    });
}
<|endoftext|>


<commit_before>//! Error conditions.

use std::str::Utf8Error;

/// An error encountered when trying to parse an invalid ID string.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    /// The client secret is empty.
    #[error("client secret is empty")]
    EmptyClientSecret,

    /// The room name is empty.
    #[error("room name is empty")]
    EmptyRoomName,

    /// The room version ID is empty.
    #[error("room version ID is empty")]
    EmptyRoomVersionId,

    /// The ID's localpart contains invalid characters.
    ///
    /// Only relevant for user IDs.
    #[error("localpart contains invalid characters")]
    InvalidCharacters,

    /// The key algorithm is invalid (e.g. empty).
    #[error("invalid key algorithm specified")]
    InvalidKeyAlgorithm,

    /// The key version contains outside of [a-zA-Z0-9_].
    #[error("key ID version contains invalid characters")]
    InvalidKeyVersion,

    /// The string isn't a valid Matrix ID.
    #[error("invalid matrix ID: {0}")]
    InvalidMatrixId(#[from] MatrixIdError),

    /// The string isn't a valid Matrix.to URI.
    #[error("invalid matrix.to URI: {0}")]
    InvalidMatrixToRef(#[from] MatrixToError),

    /// The mxc:// isn't a valid Matrix Content URI.
    #[error("invalid Matrix Content URI: {0}")]
    InvalidMxcUri(#[from] MxcUriError),

    /// The server name part of the the ID string is not a valid server name.
    #[error("server name is not a valid IP address or domain name")]
    InvalidServerName,

    /// The string isn't a valid URI.
    #[error("invalid URI")]
    InvalidUri,

    /// The string isn't valid UTF-8.
    #[error("invalid UTF-8")]
    InvalidUtf8,

    /// The ID exceeds 255 bytes (or 32 codepoints for a room version ID).
    #[error("ID exceeds 255 bytes")]
    MaximumLengthExceeded,

    /// The ID is missing the colon delimiter between localpart and server name, or between key
    /// algorithm and key name / version.
    #[error("required colon is missing")]
    MissingDelimiter,

    /// The ID is missing the correct leading sigil.
    #[error("leading sigil is incorrect or missing")]
    MissingLeadingSigil,
}

impl From<Utf8Error> for Error {
    fn from(_: Utf8Error) -> Self {
        Self::InvalidUtf8
    }
}

impl From<url::ParseError> for Error {
    fn from(_: url::ParseError) -> Self {
        Self::InvalidUri
    }
}

/// An error occurred while validating an MXC URI.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum MxcUriError {
    /// MXC URI did not start with `mxc://`.
    #[error("MXC URI schema was not mxc://")]
    WrongSchema,

    /// MXC URI did not have first slash, required for `server.name/media_id`.
    #[error("MXC URI does not have first slash")]
    MissingSlash,

    /// Media identifier malformed due to invalid characters detected.
    ///
    /// Valid characters are (in regex notation) `[A-Za-z0-9_-]+`.
    /// See [here](https://spec.matrix.org/v1.2/client-server-api/#security-considerations-5) for more details.
    #[error("Media Identifier malformed, invalid characters")]
    MediaIdMalformed,

    /// Server identifier malformed: invalid IP or domain name.
    #[error("invalid Server Name")]
    ServerNameMalformed,
}

/// An error occurred while validating a `MatrixId`.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum MatrixIdError {
    /// The string is missing a room ID or alias.
    #[error("missing room ID or alias")]
    MissingRoom,

    /// The string contains no identifier.
    #[error("no identifier")]
    NoIdentifier,

    /// The string contains too many identifiers.
    #[error("too many identifiers")]
    TooManyIdentifiers,

    /// The string contains an unknown identifier.
    #[error("unknown identifier")]
    UnknownIdentifier,

    /// The string contains two identifiers that cannot be paired.
    #[error("unknown identifier pair")]
    UnknownIdentifierPair,
}

/// An error occurred while validating an MXC URI.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum MatrixToError {
    /// String did not start with `https://matrix.to/#/`.
    #[error("base URL is not https://matrix.to/#/")]
    WrongBaseUrl,

    /// String has an unknown additional argument.
    #[error("unknown additional argument")]
    UnknownArgument,
}
<commit_msg>identifiers-validation: Fix docs for MatrixToError<commit_after>//! Error conditions.

use std::str::Utf8Error;

/// An error encountered when trying to parse an invalid ID string.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    /// The client secret is empty.
    #[error("client secret is empty")]
    EmptyClientSecret,

    /// The room name is empty.
    #[error("room name is empty")]
    EmptyRoomName,

    /// The room version ID is empty.
    #[error("room version ID is empty")]
    EmptyRoomVersionId,

    /// The ID's localpart contains invalid characters.
    ///
    /// Only relevant for user IDs.
    #[error("localpart contains invalid characters")]
    InvalidCharacters,

    /// The key algorithm is invalid (e.g. empty).
    #[error("invalid key algorithm specified")]
    InvalidKeyAlgorithm,

    /// The key version contains outside of [a-zA-Z0-9_].
    #[error("key ID version contains invalid characters")]
    InvalidKeyVersion,

    /// The string isn't a valid Matrix ID.
    #[error("invalid matrix ID: {0}")]
    InvalidMatrixId(#[from] MatrixIdError),

    /// The string isn't a valid Matrix.to URI.
    #[error("invalid matrix.to URI: {0}")]
    InvalidMatrixToRef(#[from] MatrixToError),

    /// The mxc:// isn't a valid Matrix Content URI.
    #[error("invalid Matrix Content URI: {0}")]
    InvalidMxcUri(#[from] MxcUriError),

    /// The server name part of the the ID string is not a valid server name.
    #[error("server name is not a valid IP address or domain name")]
    InvalidServerName,

    /// The string isn't a valid URI.
    #[error("invalid URI")]
    InvalidUri,

    /// The string isn't valid UTF-8.
    #[error("invalid UTF-8")]
    InvalidUtf8,

    /// The ID exceeds 255 bytes (or 32 codepoints for a room version ID).
    #[error("ID exceeds 255 bytes")]
    MaximumLengthExceeded,

    /// The ID is missing the colon delimiter between localpart and server name, or between key
    /// algorithm and key name / version.
    #[error("required colon is missing")]
    MissingDelimiter,

    /// The ID is missing the correct leading sigil.
    #[error("leading sigil is incorrect or missing")]
    MissingLeadingSigil,
}

impl From<Utf8Error> for Error {
    fn from(_: Utf8Error) -> Self {
        Self::InvalidUtf8
    }
}

impl From<url::ParseError> for Error {
    fn from(_: url::ParseError) -> Self {
        Self::InvalidUri
    }
}

/// An error occurred while validating an MXC URI.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum MxcUriError {
    /// MXC URI did not start with `mxc://`.
    #[error("MXC URI schema was not mxc://")]
    WrongSchema,

    /// MXC URI did not have first slash, required for `server.name/media_id`.
    #[error("MXC URI does not have first slash")]
    MissingSlash,

    /// Media identifier malformed due to invalid characters detected.
    ///
    /// Valid characters are (in regex notation) `[A-Za-z0-9_-]+`.
    /// See [here](https://spec.matrix.org/v1.2/client-server-api/#security-considerations-5) for more details.
    #[error("Media Identifier malformed, invalid characters")]
    MediaIdMalformed,

    /// Server identifier malformed: invalid IP or domain name.
    #[error("invalid Server Name")]
    ServerNameMalformed,
}

/// An error occurred while validating a `MatrixId`.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum MatrixIdError {
    /// The string is missing a room ID or alias.
    #[error("missing room ID or alias")]
    MissingRoom,

    /// The string contains no identifier.
    #[error("no identifier")]
    NoIdentifier,

    /// The string contains too many identifiers.
    #[error("too many identifiers")]
    TooManyIdentifiers,

    /// The string contains an unknown identifier.
    #[error("unknown identifier")]
    UnknownIdentifier,

    /// The string contains two identifiers that cannot be paired.
    #[error("unknown identifier pair")]
    UnknownIdentifierPair,
}

/// An error occurred while validating a `matrix.to` URI.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum MatrixToError {
    /// String did not start with `https://matrix.to/#/`.
    #[error("base URL is not https://matrix.to/#/")]
    WrongBaseUrl,

    /// String has an unknown additional argument.
    #[error("unknown additional argument")]
    UnknownArgument,
}
<|endoftext|>


<commit_before>#![feature(conservative_impl_trait)]

extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Remote, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();

    let conn_id = Rc::new(RefCell::new(Counter::new()));
    let connections_inner = connections.clone();
    // Handle new connection
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections_inner = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            let channel = receive_channel_out.clone();
            let handle_inner = handle.clone();
            let conn_id = conn_id.clone();
            let f = upgrade
                .accept()
                .and_then(move |(framed, _)| {
                    let id = conn_id
                        .borrow_mut()
                        .next()
                        .expect("maximum amount of ids reached");
                    let (sink, stream) = framed.split();
                    let f = channel.send((id, stream));
                    spawn_future(f, "Senk stream to connection pool", &handle_inner);
                    connections_inner.write().unwrap().insert(id, sink);
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|_| ());

    // Handle receiving messages from a client
    let state_read = state.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let state_read = state_read.clone();
            remote_inner.spawn(move |_| {
                stream.for_each(move |msg| {
                                    process_message(id, &msg, &mut state_read.write().unwrap());
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    // Handle sending messages to a client
    let connections_inner = connections.clone();
    let remote_inner = remote.clone();
    let send_handler =
        pool.spawn_fn(move || {
            let connections = connections_inner.clone();
            let remote = remote_inner.clone();
            send_channel_in.for_each(move |(id, state): (Id, Arc<RwLock<State>>)| {
                    let connections = connections.clone();
                    let sink = connections.write()
                        .unwrap()
                        .remove(&id)
                        .expect("Tried to send to invalid client id");

                    let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                    println!("Sending message: {}", msg);
                    let f = sink.send(OwnedMessage::Text(msg)).and_then(move |sink| {
                        connections.write().unwrap().insert(id, sink);
                        Ok(())
                    });
                    remote.spawn(move |_| f.map_err(|_| ()));
                    Ok(())
                })
                .map_err(|_| ())
        });

    // Main 'logic' loop
    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(send_channel_out, move |send_channel_out| {
            thread::sleep(Duration::from_millis(100));

            let should_continue = update(connections.clone(),
                                         state.clone(),
                                         send_channel_out.clone(),
                                         &remote);
            match should_continue {
                Ok(true) => Ok(Loop::Continue(send_channel_out)),
                Ok(false) => Ok(Loop::Break(())),
                Err(()) => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(receive_handler.select(send_handler)));
    core.run(handlers).map_err(|_| println!("Error while running core loop")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn process_message(_: u32, msg: &OwnedMessage, _: &mut State) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

type SinkContent =
    websocket::client::async::Framed<tokio_core::net::TcpStream,
                                     websocket::async::MessageCodec<websocket::OwnedMessage>>;
type SplitSink = futures::stream::SplitSink<SinkContent>;
// Represents one tick in the main loop
fn update(connections: Arc<RwLock<HashMap<Id, SplitSink>>>,
          state: Arc<RwLock<State>>,
          channel: futures::sync::mpsc::UnboundedSender<(Id, Arc<RwLock<State>>)>,
          remote: &Remote)
          -> Result<bool, ()> {
    remote.spawn(move |handle| {
        for (id, _) in connections.read().unwrap().iter() {
            let f = channel.clone().send((*id, state.clone()));
            spawn_future(f, "Send message to write handler", handle);
        }
        Ok(())
    });
    Ok(true)
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

/*
impl Pos {
    fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }

    fn add_x(&mut self, x: i32) -> &mut Self {
        self.x += x;
        self
    }

    fn add_y(&mut self, y: i32) -> &mut Self {
        self.y += y;
        self
    }

    fn add(&mut self, x: i32, y: i32) -> &mut Self {
        self.x += x;
        self.y += y;
        self
    }
}
*/
<commit_msg>Core: Gardening<commit_after>#![feature(conservative_impl_trait)]

extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Remote, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures::sync::mpsc;
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;
use std::ops::Deref;
use std::collections::HashMap;
use std::cell::RefCell;

type Id = u32;

fn main() {
    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).expect("Failed to create server");
    let pool = Rc::new(CpuPool::new_num_cpus());
    let connections = Arc::new(RwLock::new(HashMap::new()));
    let state = Arc::new(RwLock::new(State::new()));
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();

    let conn_id = Rc::new(RefCell::new(Counter::new()));
    let connections_inner = connections.clone();
    // Handle new connection
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            let connections_inner = connections_inner.clone();
            println!("Got a connection from: {}", addr);
            let channel = receive_channel_out.clone();
            let handle_inner = handle.clone();
            let conn_id = conn_id.clone();
            let f = upgrade
                .accept()
                .and_then(move |(framed, _)| {
                    let id = conn_id
                        .borrow_mut()
                        .next()
                        .expect("maximum amount of ids reached");
                    let (sink, stream) = framed.split();
                    let f = channel.send((id, stream));
                    spawn_future(f, "Senk stream to connection pool", &handle_inner);
                    connections_inner.write().unwrap().insert(id, sink);
                    Ok(())
                });
            spawn_future(f, "Handle new connection", &handle);
            Ok(())
        })
        .map_err(|_| ());

    // Handle receiving messages from a client
    let state_read = state.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let state_read = state_read.clone();
            remote_inner.spawn(move |_| {
                stream.for_each(move |msg| {
                                    process_message(id, &msg, &mut state_read.write().unwrap());
                                    Ok(())
                                })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    // Handle sending messages to a client
    let connections_inner = connections.clone();
    let remote_inner = remote.clone();
    let send_handler =
        pool.spawn_fn(move || {
            let connections = connections_inner.clone();
            let remote = remote_inner.clone();
            send_channel_in.for_each(move |(id, state): (Id, Arc<RwLock<State>>)| {
                    let connections = connections.clone();
                    let sink = connections.write()
                        .unwrap()
                        .remove(&id)
                        .expect("Tried to send to invalid client id");

                    let msg = serde_json::to_string(state.read().unwrap().deref()).unwrap();
                    println!("Sending message: {}", msg);
                    let f = sink.send(OwnedMessage::Text(msg)).and_then(move |sink| {
                        connections.write().unwrap().insert(id, sink);
                        Ok(())
                    });
                    remote.spawn(move |_| f.map_err(|_| ()));
                    Ok(())
                })
                .map_err(|_| ())
        });

    // Main 'logic' loop
    let game_loop = pool.spawn_fn(move || {
        future::loop_fn(send_channel_out, move |send_channel_out| {
            thread::sleep(Duration::from_millis(100));

            let should_continue = update(connections.clone(),
                                         state.clone(),
                                         send_channel_out.clone(),
                                         &remote);
            match should_continue {
                Ok(true) => Ok(Loop::Continue(send_channel_out)),
                Ok(false) => Ok(Loop::Break(())),
                Err(()) => Err(()),
            }
        })
    });

    let handlers =
        game_loop.select2(connection_handler.select2(receive_handler.select(send_handler)));
    core.run(handlers).map_err(|_| println!("Error while running core loop")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn process_message(_: u32, msg: &OwnedMessage, _: &mut State) {
    if let OwnedMessage::Text(ref txt) = *msg {
        println!("Received message: {}", txt);
        //state.msg = txt.clone();
    }
}

type SinkContent =
    websocket::client::async::Framed<tokio_core::net::TcpStream,
                                     websocket::async::MessageCodec<OwnedMessage>>;
type SplitSink = futures::stream::SplitSink<SinkContent>;
// Represents one tick in the main loop
fn update(connections: Arc<RwLock<HashMap<Id, SplitSink>>>,
          state: Arc<RwLock<State>>,
          channel: mpsc::UnboundedSender<(Id, Arc<RwLock<State>>)>,
          remote: &Remote)
          -> Result<bool, ()> {
    remote.spawn(move |handle| {
        for (id, _) in connections.read().unwrap().iter() {
            let f = channel.clone().send((*id, state.clone()));
            spawn_future(f, "Send message to write handler", handle);
        }
        Ok(())
    });
    Ok(true)
}

struct Counter {
    count: Id,
}
impl Counter {
    fn new() -> Self {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = Id;

    fn next(&mut self) -> Option<Id> {
        if self.count != Id::max_value() {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

#[derive(Serialize, Deserialize)]
struct State {
    positions: Vec<Pos>,
}

impl State {
    fn new() -> Self {
        Self { positions: Vec::new() }
    }
}

#[derive(Serialize, Deserialize)]
struct Pos {
    x: i32,
    y: i32,
}

<|endoftext|>


<commit_before>use job::*;
use registry::Registry;
use std::mem;
use std::sync::Arc;
use unwind;

/// Fires off a task into the Rayon threadpool in the "static" or
/// "global" scope.  Just like a standard thread, this task is not
/// tied to the current stack frame, and hence it cannot hold any
/// references other than those with `'static` lifetime. If you want
/// to spawn a task that references stack data, use [the `scope()`
/// function][scope] to create a scope.
///
/// [scope]: fn.scope.html
///
/// Since tasks spawned with this function cannot hold references into
/// the enclosing stack frame, you almost certainly want to use a
/// `move` closure as their argument (otherwise, the closure will
/// typically hold references to any variables from the enclosing
/// function that you happen to use).
///
/// This API assumes that the closure is executed purely for its
/// side-effects (i.e., it might send messages, modify data protected
/// by a mutex, or some such thing). If you want to compute a result,
/// consider `spawn_future()`.
///
/// # Panic handling
///
/// If this closure should panic, the resulting panic will be
/// propagated to the panic handler registered in the `ThreadPoolBuilder`,
/// if any.  See [`ThreadPoolBuilder::panic_handler()`][ph] for more
/// details.
///
/// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler
///
/// # Examples
///
/// This code creates a Rayon task that increments a global counter.
///
/// ```rust
/// # use rayon_core as rayon;
/// use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
///
/// static GLOBAL_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
///
/// rayon::spawn(move || {
///     GLOBAL_COUNTER.fetch_add(1, Ordering::SeqCst);
/// });
/// ```
pub fn spawn<F>(func: F)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that current registry has not terminated.
    unsafe { spawn_in(func, &Registry::current()) }
}

/// Spawn an asynchronous job in `registry.`
///
/// Unsafe because `registry` must not yet have terminated.
///
/// Not a public API, but used elsewhere in Rayon.
pub unsafe fn spawn_in<F>(func: F, registry: &Arc<Registry>)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that this does not hold any references (we know
    // this because of the `'static` bound in the inferface);
    // moreover, we assert that the code below is not supposed to
    // be able to panic, and hence the data won't leak but will be
    // enqueued into some deque for later execution.
    let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic
    let job_ref = spawn_job(func, registry);
    registry.inject_or_push(job_ref);
    mem::forget(abort_guard);
}

unsafe fn spawn_job<F>(func: F, registry: &Arc<Registry>) -> JobRef
where
    F: FnOnce() + Send + 'static,
{
    // Ensure that registry cannot terminate until this job has
    // executed. This ref is decremented at the (*) below.
    registry.increment_terminate_count();

    Box::new(HeapJob::new({
        let registry = registry.clone();
        move || {
            match unwind::halt_unwinding(func) {
                Ok(()) => {}
                Err(err) => {
                    registry.handle_panic(err);
                }
            }
            registry.terminate(); // (*) permit registry to terminate now
        }
    }))
    .as_job_ref()
}

/// TODO: like `spawn`, but FIFO
pub fn spawn_fifo<F>(func: F)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that current registry has not terminated.
    unsafe { spawn_fifo_in(func, &Registry::current()) }
}

/// Spawn an asynchronous FIFO job in `registry.`
///
/// Unsafe because `registry` must not yet have terminated.
///
/// Not a public API, but used elsewhere in Rayon.
pub unsafe fn spawn_fifo_in<F>(func: F, registry: &Arc<Registry>)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that this does not hold any references (we know
    // this because of the `'static` bound in the inferface);
    // moreover, we assert that the code below is not supposed to
    // be able to panic, and hence the data won't leak but will be
    // enqueued into some deque for later execution.
    let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic
    let job_ref = spawn_job(func, registry);

    // If we're in the pool, use our thread's private fifo for this thread to execute
    // in a locally-FIFO order.  Otherwise, just use the pool's global injector.
    match registry.current_thread() {
        Some(worker) => worker.push_fifo(job_ref),
        None => registry.inject(&[job_ref]),
    }
    mem::forget(abort_guard);
}

#[cfg(test)]
mod test;
<commit_msg>Document the global `spawn_fifo`<commit_after>use job::*;
use registry::Registry;
use std::mem;
use std::sync::Arc;
use unwind;

/// Fires off a task into the Rayon threadpool in the "static" or
/// "global" scope.  Just like a standard thread, this task is not
/// tied to the current stack frame, and hence it cannot hold any
/// references other than those with `'static` lifetime. If you want
/// to spawn a task that references stack data, use [the `scope()`
/// function][scope] to create a scope.
///
/// [scope]: fn.scope.html
///
/// Since tasks spawned with this function cannot hold references into
/// the enclosing stack frame, you almost certainly want to use a
/// `move` closure as their argument (otherwise, the closure will
/// typically hold references to any variables from the enclosing
/// function that you happen to use).
///
/// This API assumes that the closure is executed purely for its
/// side-effects (i.e., it might send messages, modify data protected
/// by a mutex, or some such thing). If you want to compute a result,
/// consider `spawn_future()`.
///
/// There is no guaranteed order of execution for spawns, given that
/// other threads may steal tasks at any time. However, they are
/// generally prioritized in a LIFO order on the thread from which
/// they were spawned. Other threads always steal from the other end of
/// the deque, like FIFO order.  The idea is that "recent" tasks are
/// most likely to be fresh in the local CPU's cache, while other
/// threads can steal older "stale" tasks.  For an alternate approach,
/// consider [`spawn_fifo()`] instead.
///
/// [`spawn_fifo()`]: fn.spawn_fifo.html
///
/// # Panic handling
///
/// If this closure should panic, the resulting panic will be
/// propagated to the panic handler registered in the `ThreadPoolBuilder`,
/// if any.  See [`ThreadPoolBuilder::panic_handler()`][ph] for more
/// details.
///
/// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler
///
/// # Examples
///
/// This code creates a Rayon task that increments a global counter.
///
/// ```rust
/// # use rayon_core as rayon;
/// use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
///
/// static GLOBAL_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
///
/// rayon::spawn(move || {
///     GLOBAL_COUNTER.fetch_add(1, Ordering::SeqCst);
/// });
/// ```
pub fn spawn<F>(func: F)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that current registry has not terminated.
    unsafe { spawn_in(func, &Registry::current()) }
}

/// Spawn an asynchronous job in `registry.`
///
/// Unsafe because `registry` must not yet have terminated.
///
/// Not a public API, but used elsewhere in Rayon.
pub unsafe fn spawn_in<F>(func: F, registry: &Arc<Registry>)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that this does not hold any references (we know
    // this because of the `'static` bound in the inferface);
    // moreover, we assert that the code below is not supposed to
    // be able to panic, and hence the data won't leak but will be
    // enqueued into some deque for later execution.
    let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic
    let job_ref = spawn_job(func, registry);
    registry.inject_or_push(job_ref);
    mem::forget(abort_guard);
}

unsafe fn spawn_job<F>(func: F, registry: &Arc<Registry>) -> JobRef
where
    F: FnOnce() + Send + 'static,
{
    // Ensure that registry cannot terminate until this job has
    // executed. This ref is decremented at the (*) below.
    registry.increment_terminate_count();

    Box::new(HeapJob::new({
        let registry = registry.clone();
        move || {
            match unwind::halt_unwinding(func) {
                Ok(()) => {}
                Err(err) => {
                    registry.handle_panic(err);
                }
            }
            registry.terminate(); // (*) permit registry to terminate now
        }
    }))
    .as_job_ref()
}

/// Fires off a task into the Rayon threadpool in the "static" or
/// "global" scope.  Just like a standard thread, this task is not
/// tied to the current stack frame, and hence it cannot hold any
/// references other than those with `'static` lifetime. If you want
/// to spawn a task that references stack data, use [the `scope_fifo()`
/// function](fn.scope_fifo.html) to create a scope.
///
/// The behavior is essentially the same as [the `spawn`
/// function](fn.spawn.html), except that calls from the same thread
/// will be prioritized in FIFO order. This is similar to the now-
/// deprecated [`breadth_first`] option, except the effect is isolated
/// to relative `spawn_fifo` calls, not all threadpool tasks.
///
/// For more details on this design, see Rayon [RFC #1].
///
/// [`breadth_first`]: struct.ThreadPoolBuilder.html#method.breadth_first
/// [RFC #1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md
///
/// # Panic handling
///
/// If this closure should panic, the resulting panic will be
/// propagated to the panic handler registered in the `ThreadPoolBuilder`,
/// if any.  See [`ThreadPoolBuilder::panic_handler()`][ph] for more
/// details.
///
/// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler
pub fn spawn_fifo<F>(func: F)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that current registry has not terminated.
    unsafe { spawn_fifo_in(func, &Registry::current()) }
}

/// Spawn an asynchronous FIFO job in `registry.`
///
/// Unsafe because `registry` must not yet have terminated.
///
/// Not a public API, but used elsewhere in Rayon.
pub unsafe fn spawn_fifo_in<F>(func: F, registry: &Arc<Registry>)
where
    F: FnOnce() + Send + 'static,
{
    // We assert that this does not hold any references (we know
    // this because of the `'static` bound in the inferface);
    // moreover, we assert that the code below is not supposed to
    // be able to panic, and hence the data won't leak but will be
    // enqueued into some deque for later execution.
    let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic
    let job_ref = spawn_job(func, registry);

    // If we're in the pool, use our thread's private fifo for this thread to execute
    // in a locally-FIFO order.  Otherwise, just use the pool's global injector.
    match registry.current_thread() {
        Some(worker) => worker.push_fifo(job_ref),
        None => registry.inject(&[job_ref]),
    }
    mem::forget(abort_guard);
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>extern crate varlink_parser;

use std::env;
use std::path::{Path, PathBuf};
use std::process::exit;
use std::io::Error as IOError;
use std::error::Error;
use std::io::{Read, Write};
use std::result::Result;
use std::fmt;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::io;
use std::fs::File;

use varlink_parser::{Interface, VStructOrEnum, VType, VTypeExt, Varlink};

type EnumHash<'a> = HashMap<String, Vec<String>>;

trait ToRust {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError>;
}

#[derive(Debug)]
pub enum ToRustError {
    IoError(IOError),
}

impl Error for ToRustError {
    fn description(&self) -> &str {
        match *self {
            ToRustError::IoError(_) => "an I/O error occurred",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ToRustError::IoError(ref err) => Some(&*err as &Error),
        }
    }
}

impl From<IOError> for ToRustError {
    fn from(err: IOError) -> ToRustError {
        ToRustError::IoError(err)
    }
}

impl fmt::Display for ToRustError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())?;
        Ok(())
    }
}

impl<'a> ToRust for VType<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        match *self {
            VType::Bool(_) => Ok("bool".into()),
            VType::Int(_) => Ok("i64".into()),
            VType::Float(_) => Ok("f64".into()),
            VType::VString(_) => Ok("String".into()),
            VType::VData(_) => Ok("String".into()),
            VType::VTypename(v) => Ok(v.into()),
            VType::VEnum(ref v) => {
                enumhash.insert(
                    parent.into(),
                    Vec::from_iter(v.elts.iter().map(|s| String::from(*s))),
                );
                Ok(format!("{}", parent).into())
            }
            VType::VStruct(_) => Ok(format!("{}", parent).into()),
        }
    }
}

impl<'a> ToRust for VTypeExt<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        let v = self.vtype.to_rust(parent, enumhash)?;

        if self.isarray {
            Ok(format!("Vec<{}>", v).into())
        } else {
            Ok(v.into())
        }
    }
}

fn camel_case_to_underscore(s: &str) -> String {
    let mut out = String::from("");
    for g in s.chars() {
        match g {
            c @ 'A'...'Z' => {
                out += "_";
                out += c.to_lowercase().to_string().as_ref();
            }
            c => out += c.to_string().as_ref(),
        }
    }
    out
}

trait InterfaceToRust {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError>;
}

impl<'a> InterfaceToRust for Interface<'a> {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError> {
        let mut out: String = "".to_owned();
        let mut enumhash = EnumHash::new();

        for t in self.typedefs.values() {
            out += "#[derive(Serialize, Deserialize, Debug)]\n";
            match t.elt {
                VStructOrEnum::VStruct(ref v) => {
                    out += format!("pub struct {} {{\n", t.name).as_ref();
                    for e in &v.elts {
                        out += format!(
                            "    pub {}: Option<{}>,\n",
                            e.name,
                            e.vtype
                                .to_rust(format!("{}_{}", t.name, e.name).as_ref(), &mut enumhash)?
                        ).as_ref();
                    }
                }
                VStructOrEnum::VEnum(ref v) => {
                    out += format!("pub enum {} {{\n", t.name).as_ref();
                    let mut iter = v.elts.iter();
                    if let Some(fst) = iter.next() {
                        out += format!("    {}", fst).as_ref();
                        for elt in iter {
                            out += format!(",\n    {}", elt).as_ref();
                        }
                    }
                    out += "\n";
                }
            }
            out += "}\n\n";
        }

        for t in self.methods.values() {
            if t.output.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Reply {{\n", t.name).as_ref();
                for e in &t.output.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n";
                out += format!("impl varlink::VarlinkReply for _{}Reply {{}}\n\n", t.name).as_ref();
            }

            if t.input.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.input.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        for t in self.errors.values() {
            if t.parm.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.parm.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        out += "pub trait _CallErr: varlink::CallTrait {\n";
        if self.errors.len() > 0 {
            for t in self.errors.values() {
                let mut inparms: String = "".to_owned();
                let mut innames: String = "".to_owned();
                if t.parm.elts.len() > 0 {
                    for e in &t.parm.elts {
                        inparms += format!(
                            ", {}: Option<{}>",
                            e.name,
                            e.vtype.to_rust(self.name, &mut enumhash)?
                        ).as_ref();
                        innames += format!("{}, ", e.name).as_ref();
                        innames.pop();
                        innames.pop();
                    }
                }

                out += format!(
                    r#"    fn reply{}(&mut self{}) -> io::Result<()> {{
        self.reply_struct(varlink::Reply::error(
            "{}.{}".into(),
"#,
                    camel_case_to_underscore(t.name),
                    inparms,
                    self.name,
                    t.name,
                ).as_ref();

                out += format!(
                    "            Some(serde_json::to_value(_{}Args {{ {} }}).unwrap()),",
                    t.name, innames
                ).as_ref();

                out += r#"
        ))
    }
"#;
            }
        }
        out += "}\nimpl<'a> _CallErr for varlink::Call<'a> {}\n\n";

        for (name, v) in &enumhash {
            out += format!("pub enum {} {{\n", name).as_ref();
            let mut iter = v.iter();
            if let Some(fst) = iter.next() {
                out += format!("    {}", fst).as_ref();
                for elt in iter {
                    out += format!(",\n    {}", elt).as_ref();
                }
            }
            out += "\n}\n\n";
        }

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            let mut innames: String = "".to_owned();
            if t.output.elts.len() > 0 {
                for e in &t.output.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                    innames += format!("{}, ", e.name).as_ref();
                    innames.pop();
                    innames.pop();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!("pub trait _Call{}: _CallErr {{\n", t.name).as_ref();
            out += format!("    fn reply(&mut self{}) -> io::Result<()> {{\n", inparms).as_ref();
            out += format!(
                "        self.reply_struct(_{}Reply {{ {} }}.into())\n",
                t.name, innames
            ).as_ref();
            out += format!(
                "    }}\n}}\nimpl<'a> _Call{} for varlink::Call<'a> {{}}\n\n",
                t.name
            ).as_ref();
        }

        out += "pub trait VarlinkInterface {\n";
        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                for e in &t.input.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!(
                "    fn {}(&self, &mut _Call{}{}) -> io::Result<()>;\n",
                fname, t.name, inparms
            ).as_ref();
        }
        out += r#"    fn call_upgraded(&self, &mut varlink::Call) -> io::Result<()> {
        Ok(())
    }
}
"#;

        out += format!(
            r####"
pub struct _InterfaceProxy {{
    inner: Box<VarlinkInterface + Send + Sync>,
}}

pub fn new(inner: Box<VarlinkInterface + Send + Sync>) -> _InterfaceProxy {{
    _InterfaceProxy {{ inner }}
}}

impl varlink::Interface for _InterfaceProxy {{
    fn get_description(&self) -> &'static str {{
        r#"
{}
"#
    }}

    fn get_name(&self) -> &'static str {{
        "{}"
    }}

"####,
            description, self.name
        ).as_ref();

        out += r#"    fn call_upgraded(&self, call: &mut varlink::Call) -> io::Result<()> {
        self.inner.call_upgraded(call)
    }

    fn call(&self, call: &mut varlink::Call) -> io::Result<()> {
        let req = call.request.unwrap();
        let method = req.method.clone();
        match method.as_ref() {
"#;

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                let ref e = t.input.elts[0];
                inparms += format!("args.{}", e.name).as_ref();
                for e in &t.input.elts[1..] {
                    inparms += format!(", args.{}, ", e.name).as_ref();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!("            \"{}.{}\" => {{", self.name, t.name).as_ref();
            if t.input.elts.len() > 0 {
                out +=
                    format!(
                        concat!("\n                if let Some(args) = req.parameters.clone() {{\n",
"                    let args: _{}Args = serde_json::from_value(args)?;\n",
"                    return self.inner.{}(call as &mut _Call{}, {});\n",
"                }} else {{\n",
"                    return call.reply_invalid_parameter(None);\n",
"                }}\n",
"            }}\n"),
                        t.name,
                        fname, t.name,
                        inparms
                    ).as_ref();
            } else {
                out += format!(
                    "\n                return self.inner.{}(call as &mut _Call{});\n            }}\n",
                    fname, t.name
                ).as_ref();
            }
        }
        out += concat!(
            "\n",
            "            m => {\n",
            "                let method: String = m.clone().into();\n",
            "                return call.reply_method_not_found(Some(method));\n",
            "            }\n",
            "        }\n",
            "    }\n",
            "}"
        );

        Ok(out)
    }
}

pub fn generate(mut reader: Box<Read>, mut writer: Box<Write>) -> io::Result<()> {
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer)?;

    let vr = Varlink::from_string(&buffer);

    if let Err(e) = vr {
        eprintln!("{}", e);
        exit(1);
    }

    match vr.unwrap().interface.to_rust(&buffer) {
        Ok(out) => {
            writeln!(
                writer,
                r#"// This file is automatically generated by the varlink rust generator
use std::io;

use varlink;
use serde_json;

{}"#,
                out
            )?;
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }

    Ok(())
}

/// Errors are emitted to stderr and terminate the process.
pub fn cargo_build<T: AsRef<Path> + ?Sized>(input_path: &T) {
    let mut stderr = io::stderr();
    let input_path = input_path.as_ref();

    let reader: Box<Read>;

    let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
    let rust_path = out_dir
        .join(input_path.file_name().unwrap())
        .with_extension("rs");

    let writer: Box<Write> = Box::new(File::create(&rust_path).unwrap());

    match File::open(input_path) {
        Ok(r) => reader = Box::new(r),
        Err(e) => {
            writeln!(
                stderr,
                "Could not read varlink input file `{}`: {}",
                input_path.display(),
                e
            ).unwrap();
            exit(1);
        }
    }
    if let Err(e) = generate(reader, writer) {
        writeln!(
            stderr,
            "Could not generate rust code from varlink file `{}`: {}",
            input_path.display(),
            e
        ).unwrap();
        exit(1);
    }

    println!("cargo:rerun-if-changed={}", input_path.display());
}
<commit_msg>remove unused code<commit_after>extern crate varlink_parser;

use std::env;
use std::path::{Path, PathBuf};
use std::process::exit;
use std::io::Error as IOError;
use std::error::Error;
use std::io::{Read, Write};
use std::result::Result;
use std::fmt;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::io;
use std::fs::File;

use varlink_parser::{Interface, VStructOrEnum, VType, VTypeExt, Varlink};

type EnumHash<'a> = HashMap<String, Vec<String>>;

trait ToRust {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError>;
}

#[derive(Debug)]
pub enum ToRustError {
    IoError(IOError),
}

impl Error for ToRustError {
    fn description(&self) -> &str {
        match *self {
            ToRustError::IoError(_) => "an I/O error occurred",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ToRustError::IoError(ref err) => Some(&*err as &Error),
        }
    }
}

impl From<IOError> for ToRustError {
    fn from(err: IOError) -> ToRustError {
        ToRustError::IoError(err)
    }
}

impl fmt::Display for ToRustError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())?;
        Ok(())
    }
}

impl<'a> ToRust for VType<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        match *self {
            VType::Bool(_) => Ok("bool".into()),
            VType::Int(_) => Ok("i64".into()),
            VType::Float(_) => Ok("f64".into()),
            VType::VString(_) => Ok("String".into()),
            VType::VData(_) => Ok("String".into()),
            VType::VTypename(v) => Ok(v.into()),
            VType::VEnum(ref v) => {
                enumhash.insert(
                    parent.into(),
                    Vec::from_iter(v.elts.iter().map(|s| String::from(*s))),
                );
                Ok(format!("{}", parent).into())
            }
            VType::VStruct(_) => Ok(format!("{}", parent).into()),
        }
    }
}

impl<'a> ToRust for VTypeExt<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        let v = self.vtype.to_rust(parent, enumhash)?;

        if self.isarray {
            Ok(format!("Vec<{}>", v).into())
        } else {
            Ok(v.into())
        }
    }
}

fn camel_case_to_underscore(s: &str) -> String {
    let mut out = String::from("");
    for g in s.chars() {
        match g {
            c @ 'A'...'Z' => {
                out += "_";
                out += c.to_lowercase().to_string().as_ref();
            }
            c => out += c.to_string().as_ref(),
        }
    }
    out
}

trait InterfaceToRust {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError>;
}

impl<'a> InterfaceToRust for Interface<'a> {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError> {
        let mut out: String = "".to_owned();
        let mut enumhash = EnumHash::new();

        for t in self.typedefs.values() {
            out += "#[derive(Serialize, Deserialize, Debug)]\n";
            match t.elt {
                VStructOrEnum::VStruct(ref v) => {
                    out += format!("pub struct {} {{\n", t.name).as_ref();
                    for e in &v.elts {
                        out += format!(
                            "    pub {}: Option<{}>,\n",
                            e.name,
                            e.vtype
                                .to_rust(format!("{}_{}", t.name, e.name).as_ref(), &mut enumhash)?
                        ).as_ref();
                    }
                }
                VStructOrEnum::VEnum(ref v) => {
                    out += format!("pub enum {} {{\n", t.name).as_ref();
                    let mut iter = v.elts.iter();
                    if let Some(fst) = iter.next() {
                        out += format!("    {}", fst).as_ref();
                        for elt in iter {
                            out += format!(",\n    {}", elt).as_ref();
                        }
                    }
                    out += "\n";
                }
            }
            out += "}\n\n";
        }

        for t in self.methods.values() {
            if t.output.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Reply {{\n", t.name).as_ref();
                for e in &t.output.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n";
                out += format!("impl varlink::VarlinkReply for _{}Reply {{}}\n\n", t.name).as_ref();
            }

            if t.input.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.input.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        for t in self.errors.values() {
            if t.parm.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.parm.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        out += "pub trait _CallErr: varlink::CallTrait {\n";
        if self.errors.len() > 0 {
            for t in self.errors.values() {
                let mut inparms: String = "".to_owned();
                let mut innames: String = "".to_owned();
                if t.parm.elts.len() > 0 {
                    for e in &t.parm.elts {
                        inparms += format!(
                            ", {}: Option<{}>",
                            e.name,
                            e.vtype.to_rust(self.name, &mut enumhash)?
                        ).as_ref();
                        innames += format!("{}, ", e.name).as_ref();
                        innames.pop();
                        innames.pop();
                    }
                }

                out += format!(
                    r#"    fn reply{}(&mut self{}) -> io::Result<()> {{
        self.reply_struct(varlink::Reply::error(
            "{}.{}".into(),
"#,
                    camel_case_to_underscore(t.name),
                    inparms,
                    self.name,
                    t.name,
                ).as_ref();

                out += format!(
                    "            Some(serde_json::to_value(_{}Args {{ {} }}).unwrap()),",
                    t.name, innames
                ).as_ref();

                out += r#"
        ))
    }
"#;
            }
        }
        out += "}\nimpl<'a> _CallErr for varlink::Call<'a> {}\n\n";

        for (name, v) in &enumhash {
            out += format!("pub enum {} {{\n", name).as_ref();
            let mut iter = v.iter();
            if let Some(fst) = iter.next() {
                out += format!("    {}", fst).as_ref();
                for elt in iter {
                    out += format!(",\n    {}", elt).as_ref();
                }
            }
            out += "\n}\n\n";
        }

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            let mut innames: String = "".to_owned();
            if t.output.elts.len() > 0 {
                for e in &t.output.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                    innames += format!("{}, ", e.name).as_ref();
                    innames.pop();
                    innames.pop();
                }
            }
            out += format!("pub trait _Call{}: _CallErr {{\n", t.name).as_ref();
            out += format!("    fn reply(&mut self{}) -> io::Result<()> {{\n", inparms).as_ref();
            out += format!(
                "        self.reply_struct(_{}Reply {{ {} }}.into())\n",
                t.name, innames
            ).as_ref();
            out += format!(
                "    }}\n}}\nimpl<'a> _Call{} for varlink::Call<'a> {{}}\n\n",
                t.name
            ).as_ref();
        }

        out += "pub trait VarlinkInterface {\n";
        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                for e in &t.input.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!(
                "    fn {}(&self, &mut _Call{}{}) -> io::Result<()>;\n",
                fname, t.name, inparms
            ).as_ref();
        }
        out += r#"    fn call_upgraded(&self, &mut varlink::Call) -> io::Result<()> {
        Ok(())
    }
}
"#;

        out += format!(
            r####"
pub struct _InterfaceProxy {{
    inner: Box<VarlinkInterface + Send + Sync>,
}}

pub fn new(inner: Box<VarlinkInterface + Send + Sync>) -> _InterfaceProxy {{
    _InterfaceProxy {{ inner }}
}}

impl varlink::Interface for _InterfaceProxy {{
    fn get_description(&self) -> &'static str {{
        r#"
{}
"#
    }}

    fn get_name(&self) -> &'static str {{
        "{}"
    }}

"####,
            description, self.name
        ).as_ref();

        out += r#"    fn call_upgraded(&self, call: &mut varlink::Call) -> io::Result<()> {
        self.inner.call_upgraded(call)
    }

    fn call(&self, call: &mut varlink::Call) -> io::Result<()> {
        let req = call.request.unwrap();
        let method = req.method.clone();
        match method.as_ref() {
"#;

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                let ref e = t.input.elts[0];
                inparms += format!("args.{}", e.name).as_ref();
                for e in &t.input.elts[1..] {
                    inparms += format!(", args.{}, ", e.name).as_ref();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!("            \"{}.{}\" => {{", self.name, t.name).as_ref();
            if t.input.elts.len() > 0 {
                out +=
                    format!(
                        concat!("\n                if let Some(args) = req.parameters.clone() {{\n",
"                    let args: _{}Args = serde_json::from_value(args)?;\n",
"                    return self.inner.{}(call as &mut _Call{}, {});\n",
"                }} else {{\n",
"                    return call.reply_invalid_parameter(None);\n",
"                }}\n",
"            }}\n"),
                        t.name,
                        fname, t.name,
                        inparms
                    ).as_ref();
            } else {
                out += format!(
                    "\n                return self.inner.{}(call as &mut _Call{});\n            }}\n",
                    fname, t.name
                ).as_ref();
            }
        }
        out += concat!(
            "\n",
            "            m => {\n",
            "                let method: String = m.clone().into();\n",
            "                return call.reply_method_not_found(Some(method));\n",
            "            }\n",
            "        }\n",
            "    }\n",
            "}"
        );

        Ok(out)
    }
}

pub fn generate(mut reader: Box<Read>, mut writer: Box<Write>) -> io::Result<()> {
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer)?;

    let vr = Varlink::from_string(&buffer);

    if let Err(e) = vr {
        eprintln!("{}", e);
        exit(1);
    }

    match vr.unwrap().interface.to_rust(&buffer) {
        Ok(out) => {
            writeln!(
                writer,
                r#"// This file is automatically generated by the varlink rust generator
use std::io;

use varlink;
use serde_json;

{}"#,
                out
            )?;
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }

    Ok(())
}

/// Errors are emitted to stderr and terminate the process.
pub fn cargo_build<T: AsRef<Path> + ?Sized>(input_path: &T) {
    let mut stderr = io::stderr();
    let input_path = input_path.as_ref();

    let reader: Box<Read>;

    let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
    let rust_path = out_dir
        .join(input_path.file_name().unwrap())
        .with_extension("rs");

    let writer: Box<Write> = Box::new(File::create(&rust_path).unwrap());

    match File::open(input_path) {
        Ok(r) => reader = Box::new(r),
        Err(e) => {
            writeln!(
                stderr,
                "Could not read varlink input file `{}`: {}",
                input_path.display(),
                e
            ).unwrap();
            exit(1);
        }
    }
    if let Err(e) = generate(reader, writer) {
        writeln!(
            stderr,
            "Could not generate rust code from varlink file `{}`: {}",
            input_path.display(),
            e
        ).unwrap();
        exit(1);
    }

    println!("cargo:rerun-if-changed={}", input_path.display());
}
<|endoftext|>


<commit_before>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// To satisfy this lint, you will have to adjust either the expression that is matched
    /// against or the pattern itself, as well as the bindings that are introduced by the
    /// adjusted patterns. For matching you will have to either dereference the expression
    /// with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
    /// or `&mut <pattern>` depending on the reference mutability. For the bindings you need
    /// to use the inverse. You can leave them as plain bindings if you wish for the value
    /// to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
    /// a reference into the matched structure.
    ///
    /// If you are looking for a way to learn about ownership semantics in more detail, it
    /// is recommended to look at IDE options available to you to highlight types, lifetimes
    /// and reference semantics in your code. The available tooling would expose these things
    /// in a general way even outside of the various pattern matching mechanics. Of course
    /// this lint can still be used to highlight areas of interest and ensure a good understanding
    /// of ownership semantics.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// This example shows the basic adjustments necessary to satisfy the lint. Note how
    /// the matched expression is explicitly dereferenced with `*` and the `inner` variable
    /// is bound to a shared borrow via `ref inner`.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    ///
    /// The following example demonstrates one of the advantages of the more verbose style.
    /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
    /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot
    /// accidentally modify the wrong part of the structure.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for (a, b) in &mut values {
    ///     *a += *b;
    /// }
    ///
    /// // Good
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for &mut (ref mut a, b) in &mut values {
    ///     *a += b;
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'a, 'tcx, I>(
    cx: &LateContext<'a, 'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<commit_msg>LateContext has only one lifetime parameter now<commit_after>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// To satisfy this lint, you will have to adjust either the expression that is matched
    /// against or the pattern itself, as well as the bindings that are introduced by the
    /// adjusted patterns. For matching you will have to either dereference the expression
    /// with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
    /// or `&mut <pattern>` depending on the reference mutability. For the bindings you need
    /// to use the inverse. You can leave them as plain bindings if you wish for the value
    /// to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
    /// a reference into the matched structure.
    ///
    /// If you are looking for a way to learn about ownership semantics in more detail, it
    /// is recommended to look at IDE options available to you to highlight types, lifetimes
    /// and reference semantics in your code. The available tooling would expose these things
    /// in a general way even outside of the various pattern matching mechanics. Of course
    /// this lint can still be used to highlight areas of interest and ensure a good understanding
    /// of ownership semantics.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// This example shows the basic adjustments necessary to satisfy the lint. Note how
    /// the matched expression is explicitly dereferenced with `*` and the `inner` variable
    /// is bound to a shared borrow via `ref inner`.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    ///
    /// The following example demonstrates one of the advantages of the more verbose style.
    /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
    /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot
    /// accidentally modify the wrong part of the structure.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for (a, b) in &mut values {
    ///     *a += *b;
    /// }
    ///
    /// // Good
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for &mut (ref mut a, b) in &mut values {
    ///     *a += b;
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'tcx>(
    cx: &LateContext<'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'tcx>(
    cx: &LateContext<'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'tcx, I>(
    cx: &LateContext<'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'tcx>(
    cx: &LateContext<'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<|endoftext|>


<commit_before>use config::{Config, OutputFormat, Verbosity};
use errors::*;
use utils::console::*;
use utils::output;

use clap::{App, Arg, ArgMatches, SubCommand};
use indicatif::{ProgressBar, ProgressStyle};
use serde_json;
use std::io::Write;
use tabwriter::TabWriter;

mod comdirect;

pub const NAME: &'static str = "stocks";

#[derive(Serialize, Debug)]
pub struct StockPrice {
    pub name: String,
    pub wkn: String,
    pub date: String,
    pub price: f32,
    pub currency: String,
}

pub fn build_sub_cli() -> App<'static, 'static> {
    SubCommand::with_name(NAME)
        .about("Stocks scrapes current stock prices from comdirect.de")
        .arg(Arg::with_name("queries")
            .index(1)
            .required(true)
            .multiple(true)
            .help("search term like company name, ISIN, WKN, or symbol"))
}

pub fn call(cli_args: Option<&ArgMatches>, config: &Config) -> Result<()> {
    let args = cli_args.unwrap();
    let queries: Vec<&str> = args.values_of("queries").unwrap().map(|x| x).collect();

    let mut progress_bar: Option<ProgressBar> = None;
    let mut progress = None;
    if config.general.output_format == OutputFormat::HUMAN && config.general.verbosity <= Verbosity::NORMAL {
        let pb = ProgressBar::new(0);
        pb.set_style(ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{bar:40.blue/blue}] {pos}/{len} ({eta}) {msg} {spinner:.blue}")
        );
        pb.set_length(queries.len() as u64);
        progress_bar = Some(pb);
        progress = Some(|str: String| {
            progress_bar.as_ref().unwrap().set_message(&str);
        });
    };

    let mut stock_prices: Vec<StockPrice> = vec![];
    for query in queries {
        let r = comdirect::scrape_stock_price(query, progress.as_ref())
            .chain_err(|| format!("Failed to get stock price for query '{}'", query))?;
        if let Some(ref pb) = progress_bar {
            pb.inc(1);
        }
        stock_prices.push(r)
    }

    if let Some(ref pb) = progress_bar {
        pb.finish_with_message("done");
    };

    output(&stock_prices, &config.general.output_format)
}

fn output(stock_prices: &[StockPrice], format: &OutputFormat) -> Result<()> {
    match *format {
        OutputFormat::HUMAN => output_human(stock_prices),
        OutputFormat::JSON => {
            let json = serde_json::to_string(stock_prices).chain_err(|| "Failed to serialize JSON")?;
            output::as_json(&json).chain_err(|| "Output failed")
        },
    }
}

fn output_human(stock_prices: &[StockPrice]) -> Result<()> {
    let mut tw = TabWriter::new(vec![]);
    for ref sp in stock_prices {
        let _ = writeln!(
            &mut tw, "{}\t({})\tis at {:7.2} {}\ton {}", sp.name, sp.wkn, sp.price, sp.currency, sp.date);
    }
    tw.flush().unwrap();
    let out_str = String::from_utf8(tw.into_inner().unwrap()).unwrap();

    msgln(format!("{}", out_str));

    Ok(())
}
<commit_msg>Make stocks::comdirect::scraping function pub<commit_after>use config::{Config, OutputFormat, Verbosity};
use errors::*;
use utils::console::*;
use utils::output;

use clap::{App, Arg, ArgMatches, SubCommand};
use indicatif::{ProgressBar, ProgressStyle};
use serde_json;
use std::io::Write;
use tabwriter::TabWriter;

pub mod comdirect;

pub const NAME: &'static str = "stocks";

#[derive(Serialize, Debug)]
pub struct StockPrice {
    pub name: String,
    pub wkn: String,
    pub date: String,
    pub price: f32,
    pub currency: String,
}

pub fn build_sub_cli() -> App<'static, 'static> {
    SubCommand::with_name(NAME)
        .about("Stocks scrapes current stock prices from comdirect.de")
        .arg(Arg::with_name("queries")
            .index(1)
            .required(true)
            .multiple(true)
            .help("search term like company name, ISIN, WKN, or symbol"))
}

pub fn call(cli_args: Option<&ArgMatches>, config: &Config) -> Result<()> {
    let args = cli_args.unwrap();
    let queries: Vec<&str> = args.values_of("queries").unwrap().map(|x| x).collect();

    let mut progress_bar: Option<ProgressBar> = None;
    let mut progress = None;
    if config.general.output_format == OutputFormat::HUMAN && config.general.verbosity <= Verbosity::NORMAL {
        let pb = ProgressBar::new(0);
        pb.set_style(ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{bar:40.blue/blue}] {pos}/{len} ({eta}) {msg} {spinner:.blue}")
        );
        pb.set_length(queries.len() as u64);
        progress_bar = Some(pb);
        progress = Some(|str: String| {
            progress_bar.as_ref().unwrap().set_message(&str);
        });
    };

    let mut stock_prices: Vec<StockPrice> = vec![];
    for query in queries {
        let r = comdirect::scrape_stock_price(query, progress.as_ref())
            .chain_err(|| format!("Failed to get stock price for query '{}'", query))?;
        if let Some(ref pb) = progress_bar {
            pb.inc(1);
        }
        stock_prices.push(r)
    }

    if let Some(ref pb) = progress_bar {
        pb.finish_with_message("done");
    };

    output(&stock_prices, &config.general.output_format)
}

fn output(stock_prices: &[StockPrice], format: &OutputFormat) -> Result<()> {
    match *format {
        OutputFormat::HUMAN => output_human(stock_prices),
        OutputFormat::JSON => {
            let json = serde_json::to_string(stock_prices).chain_err(|| "Failed to serialize JSON")?;
            output::as_json(&json).chain_err(|| "Output failed")
        },
    }
}

fn output_human(stock_prices: &[StockPrice]) -> Result<()> {
    let mut tw = TabWriter::new(vec![]);
    for ref sp in stock_prices {
        let _ = writeln!(
            &mut tw, "{}\t({})\tis at {:7.2} {}\ton {}", sp.name, sp.wkn, sp.price, sp.currency, sp.date);
    }
    tw.flush().unwrap();
    let out_str = String::from_utf8(tw.into_inner().unwrap()).unwrap();

    msgln(format!("{}", out_str));

    Ok(())
}
<|endoftext|>