<commit_before>//! Types for the *m.reaction* event.

use std::convert::TryFrom;

use ruma_events_macros::EventContent;
use ruma_identifiers::EventId;
use serde::{Deserialize, Serialize};

use crate::{
    room::relationships::{Annotation, RelatesToJsonRepr, RelationJsonRepr},
    MessageEvent,
};

/// A reaction to another event.
pub type ReactionEvent = MessageEvent<ReactionEventContent>;

/// The payload for a `ReactionEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.reaction", kind = Message)]
pub struct ReactionEventContent {
    /// Information about the related event.
    #[serde(rename = "m.relates_to")]
    pub relation: Relation,
}

impl ReactionEventContent {
    /// Creates a new `ReactionEventContent` from the given relation.
    ///
    /// You can also construct a `ReactionEventContent` from a relation using `From` / `Into`.
    pub fn new(relation: Relation) -> Self {
        Self { relation }
    }
}

impl From<Relation> for ReactionEventContent {
    fn from(relation: Relation) -> Self {
        Self::new(relation)
    }
}

/// The relation that contains info which event the reaction is applying to.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")]
pub struct Relation {
    /// The event that is being reacted to.
    pub event_id: EventId,

    /// A string that holds the emoji reaction.
    pub emoji: String,
}

impl Relation {
    /// Creates a new `Relation` with the given event ID and emoji.
    pub fn new(event_id: EventId, emoji: String) -> Self {
        Self { event_id, emoji }
    }
}

impl From<Relation> for RelatesToJsonRepr {
    fn from(relation: Relation) -> Self {
        RelatesToJsonRepr::Relation(RelationJsonRepr::Annotation(Annotation {
            event_id: relation.event_id,
            key: relation.emoji,
        }))
    }
}

impl TryFrom<RelatesToJsonRepr> for Relation {
    type Error = &'static str;

    fn try_from(value: RelatesToJsonRepr) -> Result<Self, Self::Error> {
        if let RelatesToJsonRepr::Relation(RelationJsonRepr::Annotation(a)) = value {
            Ok(Relation { event_id: a.event_id, emoji: a.key })
        } else {
            Err("Expected a relation with a rel_type of `annotation`")
        }
    }
}
<commit_msg>events: Clean up reaction event<commit_after>//! Types for the *m.reaction* event.

use ruma_events_macros::EventContent;
use ruma_identifiers::EventId;
use serde::{Deserialize, Serialize};

use crate::MessageEvent;

/// A reaction to another event.
pub type ReactionEvent = MessageEvent<ReactionEventContent>;

/// The payload for a `ReactionEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.reaction", kind = Message)]
pub struct ReactionEventContent {
    /// Information about the related event.
    #[serde(rename = "m.relates_to")]
    pub relates_to: Relation,
}

impl ReactionEventContent {
    /// Creates a new `ReactionEventContent` from the given relation.
    ///
    /// You can also construct a `ReactionEventContent` from a relation using `From` / `Into`.
    pub fn new(relates_to: Relation) -> Self {
        Self { relates_to }
    }
}

impl From<Relation> for ReactionEventContent {
    fn from(relates_to: Relation) -> Self {
        Self::new(relates_to)
    }
}

/// The relation that contains info which event the reaction is applying to.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "rel_type", rename = "m.annotation")]
pub struct Relation {
    /// The event that is being reacted to.
    pub event_id: EventId,

    /// A string that holds the emoji reaction.
    pub emoji: String,
}

impl Relation {
    /// Creates a new `Relation` with the given event ID and emoji.
    pub fn new(event_id: EventId, emoji: String) -> Self {
        Self { event_id, emoji }
    }
}
<|endoftext|>


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

use crate::proto::{
    command::Command::{JoinRoom, SendMessage},
    Command, Message,
};
use log::{info, warn};
use oak::Node;

oak::entrypoint!(backend_oak_main => |in_channel| {
    oak::logger::init_default();
    oak::run_event_loop(Room::default(), oak::io::Receiver::<Command>::new(in_channel));
});

#[derive(Default)]
struct Room {
    messages: Vec<Message>,
    clients: Vec<oak::grpc::ChannelResponseWriter>,
}

impl Node<Command> for Room {
    fn handle_command(&mut self, command: Command) -> Result<(), oak::OakError> {
        match command.command {
            Some(JoinRoom(sender)) => {
                self.clients
                    .push(oak::grpc::ChannelResponseWriter::new(sender));
                Ok(())
            }
            Some(SendMessage(message)) => {
                self.messages.push(message.clone());
                info!("fan out message to {} clients", self.clients.len());
                for writer in &mut self.clients {
                    // TODO(#746): Improve error handling.
                    writer
                        .write(&message, oak::grpc::WriteMode::KeepOpen)
                        .expect("could not write to channel");
                }
                Ok(())
            }
            None => {
                warn!("Received empty command");
                Err(oak::OakError::OakStatus(oak::OakStatus::ErrInvalidArgs))
            }
        }
    }
}
<commit_msg>examples: better error handling in chat<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use crate::proto::{
    command::Command::{JoinRoom, SendMessage},
    Command, Message,
};
use log::{info, warn};
use oak::Node;

oak::entrypoint!(backend_oak_main => |in_channel| {
    oak::logger::init_default();
    oak::run_event_loop(Room::default(), oak::io::Receiver::<Command>::new(in_channel));
});

#[derive(Default)]
struct Room {
    messages: Vec<Message>,
    clients: Vec<oak::grpc::ChannelResponseWriter>,
}

impl Node<Command> for Room {
    fn handle_command(&mut self, command: Command) -> Result<(), oak::OakError> {
        match command.command {
            Some(JoinRoom(sender)) => {
                self.clients
                    .push(oak::grpc::ChannelResponseWriter::new(sender));
                Ok(())
            }
            Some(SendMessage(message)) => {
                self.messages.push(message.clone());
                info!("fan out message to {} clients", self.clients.len());
                self.clients.retain(|writer| {
                    let result = writer.write(&message, oak::grpc::WriteMode::KeepOpen);
                    // Only retain clients we can write to successfully.
                    if result.is_err() {
                        warn!("Failed to write to client, dropping for future SendMessage invocations");
                    }
                    result.is_ok()
                });
                Ok(())
            }
            None => {
                warn!("Received empty command");
                Err(oak::OakError::OakStatus(oak::OakStatus::ErrInvalidArgs))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

pub fn find(sum: u32) -> HashSet<[u32; 3]> {
    let mut triplets = HashSet::new();

    for a in 1..(sum / 3) {
        for b in (a + 1)..=((sum - a) / 2) {
            let c = sum - (a + b);

            if a * a + b * b == c * c {
                triplets.insert([a, b, c]);
            }
        }
    }

    triplets
}
<commit_msg>pythagorean-triplet: Decide `b` based on `a` and `sum`<commit_after>use std::collections::HashSet;

pub fn find(sum: u32) -> HashSet<[u32; 3]> {
    let mut triplets = HashSet::new();

    for a in 1..sum {
        /*
         * (where n is a one-character alias for sum)
         * c = n - a - b
         * a^2 + b^2 = c^2
         * a^2 + b^2 = n^2 - 2an - 2bn + a^2 + 2ab + b^2
         * 2bn - 2ab = n^2 - 2an
         * 2b(n - a) = n(n-2a)
         * b = n(n-2a) / 2(n-a)
         * b = (n(n-a) - an) / 2(n-a)
         */
        let b = sum / 2 - a * sum / (2 * (sum - a));
        if a >= b {
            break;
        }
        let c = sum - (a + b);

        if a * a + b * b == c * c {
            triplets.insert([a, b, c]);
        }
    }

    triplets
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::ffi::OsString;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
    #[derive(Debug)]
    pub enum Coloring {
        Auto,
        Always,
        Never,
    }
}

/// Arguments for controlling cargo build and other similar commands (like check).
#[derive(Debug, StructOpt)]
pub struct BuildArgs {
    #[structopt(long, short)]
    /// No output printed to stdout
    pub(crate) quiet: bool,
    #[structopt(long, short)]
    /// Number of parallel jobs, defaults to # of CPUs
    pub(crate) jobs: Option<u16>,
    #[structopt(long)]
    /// Only this package's library
    pub(crate) lib: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified binary
    pub(crate) bin: Vec<String>,
    #[structopt(long)]
    /// All binaries
    pub(crate) bins: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified example
    pub(crate) example: Vec<String>,
    #[structopt(long)]
    /// All examples
    pub(crate) examples: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified test target
    pub(crate) test: Vec<String>,
    #[structopt(long)]
    /// All tests
    pub(crate) tests: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified bench target
    pub(crate) bench: Vec<String>,
    #[structopt(long)]
    /// All benches
    pub(crate) benches: bool,
    #[structopt(long)]
    /// All targets
    pub(crate) all_targets: bool,
    #[structopt(long)]
    /// Artifacts in release mode, with optimizations
    pub(crate) release: bool,
    #[structopt(long)]
    /// Artifacts with the specified profile
    pub(crate) profile: Option<String>,
    #[structopt(long, number_of_values = 1)]
    /// Space-separated list of features to activate
    pub(crate) features: Vec<String>,
    #[structopt(long)]
    /// Activate all available features
    pub(crate) all_features: bool,
    #[structopt(long)]
    /// Do not activate the `default` feature
    pub(crate) no_default_features: bool,
    #[structopt(long)]
    /// TRIPLE
    pub(crate) target: Option<String>,
    #[structopt(long, parse(from_os_str))]
    /// Directory for all generated artifacts
    pub(crate) target_dir: Option<OsString>,
    #[structopt(long, parse(from_os_str))]
    /// Path to Cargo.toml
    pub(crate) manifest_path: Option<OsString>,
    #[structopt(long)]
    /// Error format
    pub(crate) message_format: Option<String>,
    #[structopt(long, short, parse(from_occurrences))]
    /// Use verbose output (-vv very verbose/build.rs output)
    pub(crate) verbose: usize,
    #[structopt(long, possible_values = &Coloring::variants(), default_value="Auto")]
    /// Coloring: auto, always, never
    pub(crate) coloring: Coloring,
    #[structopt(long)]
    /// Require Cargo.lock and cache are up to date
    pub(crate) frozen: bool,
    #[structopt(long)]
    /// Require Cargo.lock is up to date
    pub(crate) locked: bool,
    #[structopt(long)]
    /// Run without accessing the network
    pub(crate) offline: bool,
}

impl BuildArgs {
    pub fn add_args(&self, direct_args: &mut Vec<OsString>) {
        if self.quiet {
            direct_args.push(OsString::from("--quiet"));
        }
        if let Some(jobs) = self.jobs {
            direct_args.push(OsString::from("--jobs"));
            direct_args.push(OsString::from(jobs.to_string()));
        };
        if self.lib {
            direct_args.push(OsString::from("--lib"));
        };
        if !self.bin.is_empty() {
            direct_args.push(OsString::from("--bin"));
            for bin in &self.bin {
                direct_args.push(OsString::from(bin));
            }
        }
        if self.bins {
            direct_args.push(OsString::from("--bins"));
        };
        if !self.example.is_empty() {
            direct_args.push(OsString::from("--example"));
            for example in &self.example {
                direct_args.push(OsString::from(example));
            }
        }
        if self.examples {
            direct_args.push(OsString::from("--examples"));
        };

        if !self.test.is_empty() {
            direct_args.push(OsString::from("--test"));
            for test in &self.test {
                direct_args.push(OsString::from(test));
            }
        }
        if self.tests {
            direct_args.push(OsString::from("--tests"));
        };

        if !self.bench.is_empty() {
            direct_args.push(OsString::from("--bench"));
            for bench in &self.bench {
                direct_args.push(OsString::from(bench));
            }
        }
        if self.benches {
            direct_args.push(OsString::from("--benches"));
        };

        if self.all_targets {
            direct_args.push(OsString::from("--all-targets"));
        };
        if self.release {
            direct_args.push(OsString::from("--release"));
        };

        if let Some(profile) = &self.profile {
            direct_args.push(OsString::from("--profile"));
            direct_args.push(OsString::from(profile.to_string()));
        };

        if !self.features.is_empty() {
            direct_args.push(OsString::from("--features"));
            for features in &self.features {
                direct_args.push(OsString::from(features));
            }
        }
        if self.all_features {
            direct_args.push(OsString::from("--all-features"));
        };
        if self.no_default_features {
            direct_args.push(OsString::from("--no-default-features"));
        };

        if let Some(target) = &self.target {
            direct_args.push(OsString::from("--target"));
            direct_args.push(OsString::from(target.to_string()));
        };
        if let Some(target_dir) = &self.target_dir {
            direct_args.push(OsString::from("--target-dir"));
            direct_args.push(OsString::from(target_dir));
        };
        if let Some(manifest_path) = &self.manifest_path {
            direct_args.push(OsString::from("--manifest-path"));
            direct_args.push(manifest_path.to_owned());
        };
        if let Some(message_format) = &self.message_format {
            direct_args.push(OsString::from("--message-format"));
            direct_args.push(OsString::from(message_format.to_string()));
        };
        if self.verbose > 0 {
            direct_args.push(OsString::from(format!("-{}", "v".repeat(self.verbose))));
        };
        if self.coloring.to_string() != Coloring::Auto.to_string() {
            direct_args.push(OsString::from("--coloring"));
            direct_args.push(OsString::from(self.coloring.to_string()));
        };
        if self.frozen {
            direct_args.push(OsString::from("--frozen"));
        };
        if self.locked {
            direct_args.push(OsString::from("--locked"));
        };
        if self.offline {
            direct_args.push(OsString::from("--offline"));
        };
    }
}
<commit_msg>[x] fix --color argument<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::ffi::OsString;
use structopt::{clap::arg_enum, StructOpt};

arg_enum! {
    #[derive(Debug)]
    pub enum Coloring {
        Auto,
        Always,
        Never,
    }
}

/// Arguments for controlling cargo build and other similar commands (like check).
#[derive(Debug, StructOpt)]
pub struct BuildArgs {
    #[structopt(long, short)]
    /// No output printed to stdout
    pub(crate) quiet: bool,
    #[structopt(long, short)]
    /// Number of parallel jobs, defaults to # of CPUs
    pub(crate) jobs: Option<u16>,
    #[structopt(long)]
    /// Only this package's library
    pub(crate) lib: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified binary
    pub(crate) bin: Vec<String>,
    #[structopt(long)]
    /// All binaries
    pub(crate) bins: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified example
    pub(crate) example: Vec<String>,
    #[structopt(long)]
    /// All examples
    pub(crate) examples: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified test target
    pub(crate) test: Vec<String>,
    #[structopt(long)]
    /// All tests
    pub(crate) tests: bool,
    #[structopt(long, number_of_values = 1)]
    /// Only the specified bench target
    pub(crate) bench: Vec<String>,
    #[structopt(long)]
    /// All benches
    pub(crate) benches: bool,
    #[structopt(long)]
    /// All targets
    pub(crate) all_targets: bool,
    #[structopt(long)]
    /// Artifacts in release mode, with optimizations
    pub(crate) release: bool,
    #[structopt(long)]
    /// Artifacts with the specified profile
    pub(crate) profile: Option<String>,
    #[structopt(long, number_of_values = 1)]
    /// Space-separated list of features to activate
    pub(crate) features: Vec<String>,
    #[structopt(long)]
    /// Activate all available features
    pub(crate) all_features: bool,
    #[structopt(long)]
    /// Do not activate the `default` feature
    pub(crate) no_default_features: bool,
    #[structopt(long)]
    /// TRIPLE
    pub(crate) target: Option<String>,
    #[structopt(long, parse(from_os_str))]
    /// Directory for all generated artifacts
    pub(crate) target_dir: Option<OsString>,
    #[structopt(long, parse(from_os_str))]
    /// Path to Cargo.toml
    pub(crate) manifest_path: Option<OsString>,
    #[structopt(long)]
    /// Error format
    pub(crate) message_format: Option<String>,
    #[structopt(long, short, parse(from_occurrences))]
    /// Use verbose output (-vv very verbose/build.rs output)
    pub(crate) verbose: usize,
    #[structopt(long, possible_values = &Coloring::variants(), default_value="Auto")]
    /// Coloring: auto, always, never
    pub(crate) color: Coloring,
    #[structopt(long)]
    /// Require Cargo.lock and cache are up to date
    pub(crate) frozen: bool,
    #[structopt(long)]
    /// Require Cargo.lock is up to date
    pub(crate) locked: bool,
    #[structopt(long)]
    /// Run without accessing the network
    pub(crate) offline: bool,
}

impl BuildArgs {
    pub fn add_args(&self, direct_args: &mut Vec<OsString>) {
        if self.quiet {
            direct_args.push(OsString::from("--quiet"));
        }
        if let Some(jobs) = self.jobs {
            direct_args.push(OsString::from("--jobs"));
            direct_args.push(OsString::from(jobs.to_string()));
        };
        if self.lib {
            direct_args.push(OsString::from("--lib"));
        };
        if !self.bin.is_empty() {
            direct_args.push(OsString::from("--bin"));
            for bin in &self.bin {
                direct_args.push(OsString::from(bin));
            }
        }
        if self.bins {
            direct_args.push(OsString::from("--bins"));
        };
        if !self.example.is_empty() {
            direct_args.push(OsString::from("--example"));
            for example in &self.example {
                direct_args.push(OsString::from(example));
            }
        }
        if self.examples {
            direct_args.push(OsString::from("--examples"));
        };

        if !self.test.is_empty() {
            direct_args.push(OsString::from("--test"));
            for test in &self.test {
                direct_args.push(OsString::from(test));
            }
        }
        if self.tests {
            direct_args.push(OsString::from("--tests"));
        };

        if !self.bench.is_empty() {
            direct_args.push(OsString::from("--bench"));
            for bench in &self.bench {
                direct_args.push(OsString::from(bench));
            }
        }
        if self.benches {
            direct_args.push(OsString::from("--benches"));
        };

        if self.all_targets {
            direct_args.push(OsString::from("--all-targets"));
        };
        if self.release {
            direct_args.push(OsString::from("--release"));
        };

        if let Some(profile) = &self.profile {
            direct_args.push(OsString::from("--profile"));
            direct_args.push(OsString::from(profile.to_string()));
        };

        if !self.features.is_empty() {
            direct_args.push(OsString::from("--features"));
            for features in &self.features {
                direct_args.push(OsString::from(features));
            }
        }
        if self.all_features {
            direct_args.push(OsString::from("--all-features"));
        };
        if self.no_default_features {
            direct_args.push(OsString::from("--no-default-features"));
        };

        if let Some(target) = &self.target {
            direct_args.push(OsString::from("--target"));
            direct_args.push(OsString::from(target.to_string()));
        };
        if let Some(target_dir) = &self.target_dir {
            direct_args.push(OsString::from("--target-dir"));
            direct_args.push(OsString::from(target_dir));
        };
        if let Some(manifest_path) = &self.manifest_path {
            direct_args.push(OsString::from("--manifest-path"));
            direct_args.push(manifest_path.to_owned());
        };
        if let Some(message_format) = &self.message_format {
            direct_args.push(OsString::from("--message-format"));
            direct_args.push(OsString::from(message_format.to_string()));
        };
        if self.verbose > 0 {
            direct_args.push(OsString::from(format!("-{}", "v".repeat(self.verbose))));
        };
        if self.color.to_string() != Coloring::Auto.to_string() {
            direct_args.push(OsString::from("--color"));
            direct_args.push(OsString::from(self.color.to_string()));
        };
        if self.frozen {
            direct_args.push(OsString::from("--frozen"));
        };
        if self.locked {
            direct_args.push(OsString::from("--locked"));
        };
        if self.offline {
            direct_args.push(OsString::from("--offline"));
        };
    }
}
<|endoftext|>


<commit_before>//! lint on enum variants that are prefixed or suffixed by the same characters

use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::symbol::InternedString;
use utils::{span_help_and_lint, span_lint};
use utils::{camel_case_from, camel_case_until, in_macro};

/// **What it does:** Detects enumeration variants that are prefixed or suffixed
/// by the same characters.
///
/// **Why is this bad?** Enumeration variant names should specify their variant,
/// not repeat the enumeration name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// enum Cake {
///     BlackForestCake,
///     HummingbirdCake,
/// }
/// ```
declare_clippy_lint! {
    pub ENUM_VARIANT_NAMES,
    style,
    "enums where all variants share a prefix/postfix"
}

/// **What it does:** Detects enumeration variants that are prefixed or suffixed
/// by the same characters.
///
/// **Why is this bad?** Enumeration variant names should specify their variant,
/// not repeat the enumeration name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// enum Cake {
///     BlackForestCake,
///     HummingbirdCake,
/// }
/// ```
declare_clippy_lint! {
    pub PUB_ENUM_VARIANT_NAMES,
    pedantic,
    "enums where all variants share a prefix/postfix"
}

/// **What it does:** Detects type names that are prefixed or suffixed by the
/// containing module's name.
///
/// **Why is this bad?** It requires the user to type the module name twice.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// mod cake {
///     struct BlackForestCake;
/// }
/// ```
declare_clippy_lint! {
    pub STUTTER,
    pedantic,
    "type names prefixed/postfixed with their containing module's name"
}

/// **What it does:** Checks for modules that have the same name as their
/// parent module
///
/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and
/// again `mod foo { ..
/// }` in `foo.rs`.
/// The expectation is that items inside the inner `mod foo { .. }` are then
/// available
/// through `foo::x`, but they are only available through
/// `foo::foo::x`.
/// If this is done on purpose, it would be better to choose a more
/// representative module name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // lib.rs
/// mod foo;
/// // foo.rs
/// mod foo {
///     ...
/// }
/// ```
declare_clippy_lint! {
    pub MODULE_INCEPTION,
    style,
    "modules that have the same name as their parent module"
}

pub struct EnumVariantNames {
    modules: Vec<(InternedString, String)>,
    threshold: u64,
}

impl EnumVariantNames {
    pub fn new(threshold: u64) -> Self {
        Self {
            modules: Vec::new(),
            threshold,
        }
    }
}

impl LintPass for EnumVariantNames {
    fn get_lints(&self) -> LintArray {
        lint_array!(ENUM_VARIANT_NAMES, PUB_ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION)
    }
}

fn var2str(var: &Variant) -> InternedString {
    var.node.ident.name.as_str()
}

/// Returns the number of chars that match from the start
fn partial_match(pre: &str, name: &str) -> usize {
    let mut name_iter = name.chars();
    let _ = name_iter.next_back(); // make sure the name is never fully matched
    pre.chars()
        .zip(name_iter)
        .take_while(|&(l, r)| l == r)
        .count()
}

/// Returns the number of chars that match from the end
fn partial_rmatch(post: &str, name: &str) -> usize {
    let mut name_iter = name.chars();
    let _ = name_iter.next(); // make sure the name is never fully matched
    post.chars()
        .rev()
        .zip(name_iter.rev())
        .take_while(|&(l, r)| l == r)
        .count()
}

// FIXME: #600
#[allow(while_let_on_iterator)]
fn check_variant(
    cx: &EarlyContext,
    threshold: u64,
    def: &EnumDef,
    item_name: &str,
    item_name_chars: usize,
    span: Span,
    lint: &'static Lint,
) {
    if (def.variants.len() as u64) < threshold {
        return;
    }
    for var in &def.variants {
        let name = var2str(var);
        if partial_match(item_name, &name) == item_name_chars
            && name.chars()
                .nth(item_name_chars)
                .map_or(false, |c| !c.is_lowercase())
        {
            span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
        }
        if partial_rmatch(item_name, &name) == item_name_chars {
            span_lint(cx, lint, var.span, "Variant name ends with the enum's name");
        }
    }
    let first = var2str(&def.variants[0]);
    let mut pre = &first[..camel_case_until(&*first)];
    let mut post = &first[camel_case_from(&*first)..];
    for var in &def.variants {
        let name = var2str(var);

        let pre_match = partial_match(pre, &name);
        pre = &pre[..pre_match];
        let pre_camel = camel_case_until(pre);
        pre = &pre[..pre_camel];
        while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
            if next.is_lowercase() {
                let last = pre.len() - last.len_utf8();
                let last_camel = camel_case_until(&pre[..last]);
                pre = &pre[..last_camel];
            } else {
                break;
            }
        }

        let post_match = partial_rmatch(post, &name);
        let post_end = post.len() - post_match;
        post = &post[post_end..];
        let post_camel = camel_case_from(post);
        post = &post[post_camel..];
    }
    let (what, value) = match (pre.is_empty(), post.is_empty()) {
        (true, true) => return,
        (false, _) => ("pre", pre),
        (true, false) => ("post", post),
    };
    span_help_and_lint(
        cx,
        lint,
        span,
        &format!("All variants have the same {}fix: `{}`", what, value),
        &format!(
            "remove the {}fixes and use full paths to \
             the variants instead of glob imports",
            what
        ),
    );
}

fn to_camel_case(item_name: &str) -> String {
    let mut s = String::new();
    let mut up = true;
    for c in item_name.chars() {
        if c.is_uppercase() {
            // we only turn snake case text into CamelCase
            return item_name.to_string();
        }
        if c == '_' {
            up = true;
            continue;
        }
        if up {
            up = false;
            s.extend(c.to_uppercase());
        } else {
            s.push(c);
        }
    }
    s
}

impl EarlyLintPass for EnumVariantNames {
    fn check_item_post(&mut self, _cx: &EarlyContext, _item: &Item) {
        let last = self.modules.pop();
        assert!(last.is_some());
    }

    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
        let item_name = item.ident.name.as_str();
        let item_name_chars = item_name.chars().count();
        let item_camel = to_camel_case(&item_name);
        if !in_macro(item.span) {
            if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
                // constants don't have surrounding modules
                if !mod_camel.is_empty() {
                    if *mod_name == item_name {
                        if let ItemKind::Mod(..) = item.node {
                            span_lint(
                                cx,
                                MODULE_INCEPTION,
                                item.span,
                                "module has the same name as its containing module",
                            );
                        }
                    }
                    if item.vis.node == VisibilityKind::Public {
                        let matching = partial_match(mod_camel, &item_camel);
                        let rmatching = partial_rmatch(mod_camel, &item_camel);
                        let nchars = mod_camel.chars().count();

                        let is_word_beginning = |c: char| {
                            c == '_' || c.is_uppercase() || c.is_numeric()
                        };

                        if matching == nchars {
                            match item_camel.chars().nth(nchars) {
                                Some(c) if is_word_beginning(c) =>
                                    span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"),
                                _ => ()
                            }
                        }
                        if rmatching == nchars {
                            span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name");
                        }
                    }
                }
            }
        }
        if let ItemKind::Enum(ref def, _) = item.node {
            let lint = match item.vis.node {
                VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
                _ => ENUM_VARIANT_NAMES,
            };
            check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
        }
        self.modules.push((item_name, item_camel));
    }
}
<commit_msg>Add third variant to {pub_,}enum_variant_names examples<commit_after>//! lint on enum variants that are prefixed or suffixed by the same characters

use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::symbol::InternedString;
use utils::{span_help_and_lint, span_lint};
use utils::{camel_case_from, camel_case_until, in_macro};

/// **What it does:** Detects enumeration variants that are prefixed or suffixed
/// by the same characters.
///
/// **Why is this bad?** Enumeration variant names should specify their variant,
/// not repeat the enumeration name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// enum Cake {
///     BlackForestCake,
///     HummingbirdCake,
///     BattenbergCake,
/// }
/// ```
declare_clippy_lint! {
    pub ENUM_VARIANT_NAMES,
    style,
    "enums where all variants share a prefix/postfix"
}

/// **What it does:** Detects enumeration variants that are prefixed or suffixed
/// by the same characters.
///
/// **Why is this bad?** Enumeration variant names should specify their variant,
/// not repeat the enumeration name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// enum Cake {
///     BlackForestCake,
///     HummingbirdCake,
///     BattenbergCake,
/// }
/// ```
declare_clippy_lint! {
    pub PUB_ENUM_VARIANT_NAMES,
    pedantic,
    "enums where all variants share a prefix/postfix"
}

/// **What it does:** Detects type names that are prefixed or suffixed by the
/// containing module's name.
///
/// **Why is this bad?** It requires the user to type the module name twice.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// mod cake {
///     struct BlackForestCake;
/// }
/// ```
declare_clippy_lint! {
    pub STUTTER,
    pedantic,
    "type names prefixed/postfixed with their containing module's name"
}

/// **What it does:** Checks for modules that have the same name as their
/// parent module
///
/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and
/// again `mod foo { ..
/// }` in `foo.rs`.
/// The expectation is that items inside the inner `mod foo { .. }` are then
/// available
/// through `foo::x`, but they are only available through
/// `foo::foo::x`.
/// If this is done on purpose, it would be better to choose a more
/// representative module name.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// // lib.rs
/// mod foo;
/// // foo.rs
/// mod foo {
///     ...
/// }
/// ```
declare_clippy_lint! {
    pub MODULE_INCEPTION,
    style,
    "modules that have the same name as their parent module"
}

pub struct EnumVariantNames {
    modules: Vec<(InternedString, String)>,
    threshold: u64,
}

impl EnumVariantNames {
    pub fn new(threshold: u64) -> Self {
        Self {
            modules: Vec::new(),
            threshold,
        }
    }
}

impl LintPass for EnumVariantNames {
    fn get_lints(&self) -> LintArray {
        lint_array!(ENUM_VARIANT_NAMES, PUB_ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION)
    }
}

fn var2str(var: &Variant) -> InternedString {
    var.node.ident.name.as_str()
}

/// Returns the number of chars that match from the start
fn partial_match(pre: &str, name: &str) -> usize {
    let mut name_iter = name.chars();
    let _ = name_iter.next_back(); // make sure the name is never fully matched
    pre.chars()
        .zip(name_iter)
        .take_while(|&(l, r)| l == r)
        .count()
}

/// Returns the number of chars that match from the end
fn partial_rmatch(post: &str, name: &str) -> usize {
    let mut name_iter = name.chars();
    let _ = name_iter.next(); // make sure the name is never fully matched
    post.chars()
        .rev()
        .zip(name_iter.rev())
        .take_while(|&(l, r)| l == r)
        .count()
}

// FIXME: #600
#[allow(while_let_on_iterator)]
fn check_variant(
    cx: &EarlyContext,
    threshold: u64,
    def: &EnumDef,
    item_name: &str,
    item_name_chars: usize,
    span: Span,
    lint: &'static Lint,
) {
    if (def.variants.len() as u64) < threshold {
        return;
    }
    for var in &def.variants {
        let name = var2str(var);
        if partial_match(item_name, &name) == item_name_chars
            && name.chars()
                .nth(item_name_chars)
                .map_or(false, |c| !c.is_lowercase())
        {
            span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
        }
        if partial_rmatch(item_name, &name) == item_name_chars {
            span_lint(cx, lint, var.span, "Variant name ends with the enum's name");
        }
    }
    let first = var2str(&def.variants[0]);
    let mut pre = &first[..camel_case_until(&*first)];
    let mut post = &first[camel_case_from(&*first)..];
    for var in &def.variants {
        let name = var2str(var);

        let pre_match = partial_match(pre, &name);
        pre = &pre[..pre_match];
        let pre_camel = camel_case_until(pre);
        pre = &pre[..pre_camel];
        while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
            if next.is_lowercase() {
                let last = pre.len() - last.len_utf8();
                let last_camel = camel_case_until(&pre[..last]);
                pre = &pre[..last_camel];
            } else {
                break;
            }
        }

        let post_match = partial_rmatch(post, &name);
        let post_end = post.len() - post_match;
        post = &post[post_end..];
        let post_camel = camel_case_from(post);
        post = &post[post_camel..];
    }
    let (what, value) = match (pre.is_empty(), post.is_empty()) {
        (true, true) => return,
        (false, _) => ("pre", pre),
        (true, false) => ("post", post),
    };
    span_help_and_lint(
        cx,
        lint,
        span,
        &format!("All variants have the same {}fix: `{}`", what, value),
        &format!(
            "remove the {}fixes and use full paths to \
             the variants instead of glob imports",
            what
        ),
    );
}

fn to_camel_case(item_name: &str) -> String {
    let mut s = String::new();
    let mut up = true;
    for c in item_name.chars() {
        if c.is_uppercase() {
            // we only turn snake case text into CamelCase
            return item_name.to_string();
        }
        if c == '_' {
            up = true;
            continue;
        }
        if up {
            up = false;
            s.extend(c.to_uppercase());
        } else {
            s.push(c);
        }
    }
    s
}

impl EarlyLintPass for EnumVariantNames {
    fn check_item_post(&mut self, _cx: &EarlyContext, _item: &Item) {
        let last = self.modules.pop();
        assert!(last.is_some());
    }

    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
        let item_name = item.ident.name.as_str();
        let item_name_chars = item_name.chars().count();
        let item_camel = to_camel_case(&item_name);
        if !in_macro(item.span) {
            if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
                // constants don't have surrounding modules
                if !mod_camel.is_empty() {
                    if *mod_name == item_name {
                        if let ItemKind::Mod(..) = item.node {
                            span_lint(
                                cx,
                                MODULE_INCEPTION,
                                item.span,
                                "module has the same name as its containing module",
                            );
                        }
                    }
                    if item.vis.node == VisibilityKind::Public {
                        let matching = partial_match(mod_camel, &item_camel);
                        let rmatching = partial_rmatch(mod_camel, &item_camel);
                        let nchars = mod_camel.chars().count();

                        let is_word_beginning = |c: char| {
                            c == '_' || c.is_uppercase() || c.is_numeric()
                        };

                        if matching == nchars {
                            match item_camel.chars().nth(nchars) {
                                Some(c) if is_word_beginning(c) =>
                                    span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"),
                                _ => ()
                            }
                        }
                        if rmatching == nchars {
                            span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name");
                        }
                    }
                }
            }
        }
        if let ItemKind::Enum(ref def, _) = item.node {
            let lint = match item.vis.node {
                VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
                _ => ENUM_VARIANT_NAMES,
            };
            check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
        }
        self.modules.push((item_name, item_camel));
    }
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use matches::matches;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;

use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function};

declare_clippy_lint! {
    /// **What it does:** Checks for closures which just call another function where
    /// the function can be called directly. `unsafe` functions or calls where types
    /// get adjusted are ignored.
    ///
    /// **Why is this bad?** Needlessly creating a closure adds code for no benefit
    /// and gives the optimizer more work.
    ///
    /// **Known problems:** If creating the closure inside the closure has a side-
    /// effect then moving the closure creation out will change when that side-
    /// effect runs.
    /// See rust-lang/rust-clippy#1439 for more details.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// xs.map(|x| foo(x))
    /// ```
    /// where `foo(_)` is a plain function that takes the exact argument type of
    /// `x`.
    pub REDUNDANT_CLOSURE,
    style,
    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
}

declare_clippy_lint! {
    /// **What it does:** Checks for closures which only invoke a method on the closure
    /// argument and can be replaced by referencing the method directly.
    ///
    /// **Why is this bad?** It's unnecessary to create the closure.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// Some('a').map(|s| s.to_uppercase());
    /// ```
    /// may be rewritten as
    /// ```rust,ignore
    /// Some('a').map(char::to_uppercase);
    /// ```
    pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
    pedantic,
    "redundant closures for method calls"
}

declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaReduction {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
                for arg in args {
                    check_closure(cx, arg)
                }
            },
            _ => (),
        }
    }
}

fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) {
    if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.node {
        let body = cx.tcx.hir().body(eid);
        let ex = &body.value;

        if_chain!(
            if let ExprKind::Call(ref caller, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));

            let fn_ty = cx.tables.expr_ty(caller);

            if matches!(fn_ty.sty, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));

            if !type_is_unsafe_function(cx, fn_ty);

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    if let Some(snippet) = snippet_opt(cx, caller.span) {
                        db.span_suggestion(
                            expr.span,
                            "remove closure as shown",
                            snippet,
                            Applicability::MachineApplicable,
                        );
                    }
                });
            }
        );

        if_chain!(
            if let ExprKind::MethodCall(ref path, _, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));

            let method_def_id = cx.tables.type_dependent_def_id(ex.hir_id).unwrap();
            if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure found", |db| {
                    db.span_suggestion(
                        expr.span,
                        "remove closure as shown",
                        format!("{}::{}", name, path.ident.name),
                        Applicability::MachineApplicable,
                    );
                });
            }
        );
    }
}

/// Tries to determine the type for universal function call to be used instead of the closure
fn get_ufcs_type_name(
    cx: &LateContext<'_, '_>,
    method_def_id: def_id::DefId,
    self_arg: &Expr,
) -> std::option::Option<String> {
    let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
    let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);

    if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
        if match_borrow_depth(expected_type_of_self, &actual_type_of_self) {
            return Some(cx.tcx.def_path_str(trait_id));
        }
    }

    cx.tcx.impl_of_method(method_def_id).and_then(|_| {
        //a type may implicitly implement other type's methods (e.g. Deref)
        if match_types(expected_type_of_self, &actual_type_of_self) {
            return Some(get_type_name(cx, &actual_type_of_self));
        }
        None
    })
}

fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _)) => match_borrow_depth(&t1, &t2),
        (l, r) => match (l, r) {
            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
            (_, _) => true,
        },
    }
}

fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Bool, ty::Bool)
        | (ty::Char, ty::Char)
        | (ty::Int(_), ty::Int(_))
        | (ty::Uint(_), ty::Uint(_))
        | (ty::Str, ty::Str) => true,
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _))
        | (ty::Array(t1, _), ty::Array(t2, _))
        | (ty::Slice(t1), ty::Slice(t2)) => match_types(t1, t2),
        (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
        (_, _) => false,
    }
}

fn get_type_name(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> String {
    match ty.sty {
        ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
        ty::Ref(_, r, _) => get_type_name(cx, &r),
        _ => ty.to_string(),
    }
}

fn compare_inputs(closure_inputs: &mut dyn Iterator<Item = &Arg>, call_args: &mut dyn Iterator<Item = &Expr>) -> bool {
    for (closure_input, function_arg) in closure_inputs.zip(call_args) {
        if let PatKind::Binding(_, _, ident, _) = closure_input.pat.node {
            // XXXManishearth Should I be checking the binding mode here?
            if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.node {
                if p.segments.len() != 1 {
                    // If it's a proper path, it can't be a local variable
                    return false;
                }
                if p.segments[0].ident.name != ident.name {
                    // The two idents should be the same
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    true
}
<commit_msg>Add known problems<commit_after>use if_chain::if_chain;
use matches::matches;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;

use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function};

declare_clippy_lint! {
    /// **What it does:** Checks for closures which just call another function where
    /// the function can be called directly. `unsafe` functions or calls where types
    /// get adjusted are ignored.
    ///
    /// **Why is this bad?** Needlessly creating a closure adds code for no benefit
    /// and gives the optimizer more work.
    ///
    /// **Known problems:** If creating the closure inside the closure has a side-
    /// effect then moving the closure creation out will change when that side-
    /// effect runs.
    /// See rust-lang/rust-clippy#1439 for more details.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// xs.map(|x| foo(x))
    /// ```
    /// where `foo(_)` is a plain function that takes the exact argument type of
    /// `x`.
    pub REDUNDANT_CLOSURE,
    style,
    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
}

declare_clippy_lint! {
    /// **What it does:** Checks for closures which only invoke a method on the closure
    /// argument and can be replaced by referencing the method directly.
    ///
    /// **Why is this bad?** It's unnecessary to create the closure.
    ///
    /// **Known problems:** rust-lang/rust-clippy#3071, rust-lang/rust-clippy#4002,
    /// rust-lang/rust-clippy#3942
    ///
    ///
    /// **Example:**
    /// ```rust,ignore
    /// Some('a').map(|s| s.to_uppercase());
    /// ```
    /// may be rewritten as
    /// ```rust,ignore
    /// Some('a').map(char::to_uppercase);
    /// ```
    pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
    pedantic,
    "redundant closures for method calls"
}

declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaReduction {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
                for arg in args {
                    check_closure(cx, arg)
                }
            },
            _ => (),
        }
    }
}

fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) {
    if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.node {
        let body = cx.tcx.hir().body(eid);
        let ex = &body.value;

        if_chain!(
            if let ExprKind::Call(ref caller, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));

            let fn_ty = cx.tables.expr_ty(caller);

            if matches!(fn_ty.sty, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));

            if !type_is_unsafe_function(cx, fn_ty);

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    if let Some(snippet) = snippet_opt(cx, caller.span) {
                        db.span_suggestion(
                            expr.span,
                            "remove closure as shown",
                            snippet,
                            Applicability::MachineApplicable,
                        );
                    }
                });
            }
        );

        if_chain!(
            if let ExprKind::MethodCall(ref path, _, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));

            let method_def_id = cx.tables.type_dependent_def_id(ex.hir_id).unwrap();
            if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure found", |db| {
                    db.span_suggestion(
                        expr.span,
                        "remove closure as shown",
                        format!("{}::{}", name, path.ident.name),
                        Applicability::MachineApplicable,
                    );
                });
            }
        );
    }
}

/// Tries to determine the type for universal function call to be used instead of the closure
fn get_ufcs_type_name(
    cx: &LateContext<'_, '_>,
    method_def_id: def_id::DefId,
    self_arg: &Expr,
) -> std::option::Option<String> {
    let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
    let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);

    if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
        if match_borrow_depth(expected_type_of_self, &actual_type_of_self) {
            return Some(cx.tcx.def_path_str(trait_id));
        }
    }

    cx.tcx.impl_of_method(method_def_id).and_then(|_| {
        //a type may implicitly implement other type's methods (e.g. Deref)
        if match_types(expected_type_of_self, &actual_type_of_self) {
            return Some(get_type_name(cx, &actual_type_of_self));
        }
        None
    })
}

fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _)) => match_borrow_depth(&t1, &t2),
        (l, r) => match (l, r) {
            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
            (_, _) => true,
        },
    }
}

fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Bool, ty::Bool)
        | (ty::Char, ty::Char)
        | (ty::Int(_), ty::Int(_))
        | (ty::Uint(_), ty::Uint(_))
        | (ty::Str, ty::Str) => true,
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _))
        | (ty::Array(t1, _), ty::Array(t2, _))
        | (ty::Slice(t1), ty::Slice(t2)) => match_types(t1, t2),
        (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
        (_, _) => false,
    }
}

fn get_type_name(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> String {
    match ty.sty {
        ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
        ty::Ref(_, r, _) => get_type_name(cx, &r),
        _ => ty.to_string(),
    }
}

fn compare_inputs(closure_inputs: &mut dyn Iterator<Item = &Arg>, call_args: &mut dyn Iterator<Item = &Expr>) -> bool {
    for (closure_input, function_arg) in closure_inputs.zip(call_args) {
        if let PatKind::Binding(_, _, ident, _) = closure_input.pat.node {
            // XXXManishearth Should I be checking the binding mode here?
            if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.node {
                if p.segments.len() != 1 {
                    // If it's a proper path, it can't be a local variable
                    return false;
                }
                if p.segments[0].ident.name != ident.name {
                    // The two idents should be the same
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    true
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::utils::{Reflectable, Reflector, BindingObject};
use script_task::page_from_context;

use js::jsapi::{JSContext, JSObject};

pub struct WindowProxy {
    reflector_: Reflector
}

impl WindowProxy {
    pub fn new() -> @mut WindowProxy {
        @mut WindowProxy {
            reflector_: Reflector::new()
        }
    }

    pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
        self.wrap_object_shared(cx, scope);
    }
}

impl BindingObject for WindowProxy {
    fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
        let page = page_from_context(cx);
        unsafe {
            Some((*page).frame.get_ref().window as @mut Reflectable)
        }
    }
}

impl Reflectable for WindowProxy {
    fn reflector(&mut self) -> &mut Reflector {
        return self.reflector()
    }

    fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
        fail!("not yet implemented")
    }
}
<commit_msg>Fix infinite-looping reflector() implementation for WindowProxy.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::utils::{Reflectable, Reflector, BindingObject};
use script_task::page_from_context;

use js::jsapi::{JSContext, JSObject};

use std::cast;

pub struct WindowProxy {
    reflector_: Reflector
}

impl WindowProxy {
    pub fn new() -> @mut WindowProxy {
        @mut WindowProxy {
            reflector_: Reflector::new()
        }
    }

    pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
        self.wrap_object_shared(cx, scope);
    }
}

impl BindingObject for WindowProxy {
    fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
        let page = page_from_context(cx);
        unsafe {
            Some((*page).frame.get_ref().window as @mut Reflectable)
        }
    }
}

impl Reflectable for WindowProxy {
    fn reflector(&mut self) -> &mut Reflector {
        unsafe { cast::transmute(self.reflector_) }
    }

    fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
        fail!("not yet implemented")
    }
}
<|endoftext|>


<commit_before>use codespan::CodeMap;
use std::{fmt, io};
use termcolor::{Color, ColorSpec, WriteColor};

use {Diagnostic, LabelStyle};

struct Pad<T>(T, usize);

impl<T: fmt::Display> fmt::Display for Pad<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for _ in 0..(self.1) {
            self.0.fmt(f)?;
        }
        Ok(())
    }
}

pub fn emit<W>(mut writer: W, codemap: &CodeMap, diagnostic: &Diagnostic) -> io::Result<()>
where
    W: WriteColor,
{
    let supports_color = writer.supports_color();
    let line_location_color = ColorSpec::new().set_fg(Some(Color::Blue)).clone();
    let diagnostic_color = ColorSpec::new()
        .set_fg(Some(diagnostic.severity.color()))
        .clone();

    writer.set_color(&diagnostic_color)?;
    write!(writer, "{}", diagnostic.severity)?;
    writer.reset()?;
    writeln!(writer, ": {}", diagnostic.message)?;
    for label in &diagnostic.labels {
        match codemap.find_file(label.span.start()) {
            None => if let Some(ref message) = label.message {
                writeln!(writer, "- {}", message)?
            },
            Some(file) => {
                let (line, column) = file.location(label.span.start()).expect("location");
                writeln!(
                    writer,
                    "- {file}:{line}:{column}",
                    file = file.name(),
                    line = line.number(),
                    column = column.number(),
                )?;

                let line_span = file.line_span(line).expect("line_span");

                let line_prefix = file.src_slice(line_span.with_end(label.span.start()))
                    .expect("line_prefix");
                let line_marked = file.src_slice(label.span).expect("line_marked");
                let line_suffix = file.src_slice(line_span.with_start(label.span.end()))
                    .expect("line_suffix")
                    .trim_right_matches(|ch: char| ch == '\r' || ch == '\n');

                let mark = match label.style {
                    LabelStyle::Primary => '^',
                    LabelStyle::Secondary => '-',
                };
                let label_color = match label.style {
                    LabelStyle::Primary => diagnostic_color.clone(),
                    LabelStyle::Secondary => ColorSpec::new().set_fg(Some(Color::Blue)).clone(),
                };

                writer.set_color(&line_location_color)?;
                let line_string = line.number().to_string();
                let line_location_prefix = format!("{} | ", Pad(' ', line_string.len()));
                write!(writer, "{} | ", line_string)?;
                writer.reset()?;

                write!(writer, "{}", line_prefix)?;
                writer.set_color(&label_color)?;
                write!(writer, "{}", line_marked)?;
                writer.reset()?;
                writeln!(writer, "{}", line_suffix)?;

                if !supports_color || label.message.is_some() {
                    writer.set_color(&line_location_color)?;
                    write!(writer, "{}", line_location_prefix)?;
                    writer.reset()?;

                    writer.set_color(&label_color)?;
                    write!(
                        writer,
                        "{}{}",
                        Pad(' ', line_prefix.len()),
                        Pad(mark, line_marked.len()),
                    )?;
                    writer.reset()?;

                    if label.message.is_none() {
                        writeln!(writer)?;
                    }
                }

                match label.message {
                    None => (),
                    Some(ref label) => {
                        writer.set_color(&label_color)?;
                        writeln!(writer, " {}", label)?;
                        writer.reset()?;
                    },
                }
            },
        }
    }
    Ok(())
}
<commit_msg>feat: Avoid using blue on windows since it is too dark<commit_after>use codespan::CodeMap;
use std::{fmt, io};
use termcolor::{Color, ColorSpec, WriteColor};

use {Diagnostic, LabelStyle};

struct Pad<T>(T, usize);

impl<T: fmt::Display> fmt::Display for Pad<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for _ in 0..(self.1) {
            self.0.fmt(f)?;
        }
        Ok(())
    }
}

pub fn emit<W>(mut writer: W, codemap: &CodeMap, diagnostic: &Diagnostic) -> io::Result<()>
where
    W: WriteColor,
{
    let supports_color = writer.supports_color();
    let line_location_color = ColorSpec::new()
        // Blue is really difficult to see on the standard windows command line
        .set_fg(Some(if cfg!(windows) { Color::Cyan } else { Color::Blue }))
        .clone();
    let diagnostic_color = ColorSpec::new()
        .set_fg(Some(diagnostic.severity.color()))
        .clone();

    writer.set_color(&diagnostic_color)?;
    write!(writer, "{}", diagnostic.severity)?;
    writer.reset()?;
    writeln!(writer, ": {}", diagnostic.message)?;
    for label in &diagnostic.labels {
        match codemap.find_file(label.span.start()) {
            None => if let Some(ref message) = label.message {
                writeln!(writer, "- {}", message)?
            },
            Some(file) => {
                let (line, column) = file.location(label.span.start()).expect("location");
                writeln!(
                    writer,
                    "- {file}:{line}:{column}",
                    file = file.name(),
                    line = line.number(),
                    column = column.number(),
                )?;

                let line_span = file.line_span(line).expect("line_span");

                let line_prefix = file.src_slice(line_span.with_end(label.span.start()))
                    .expect("line_prefix");
                let line_marked = file.src_slice(label.span).expect("line_marked");
                let line_suffix = file.src_slice(line_span.with_start(label.span.end()))
                    .expect("line_suffix")
                    .trim_right_matches(|ch: char| ch == '\r' || ch == '\n');

                let mark = match label.style {
                    LabelStyle::Primary => '^',
                    LabelStyle::Secondary => '-',
                };
                let label_color = match label.style {
                    LabelStyle::Primary => diagnostic_color.clone(),
                    LabelStyle::Secondary => ColorSpec::new()
                        .set_fg(Some(if cfg!(windows) {
                            Color::Cyan
                        } else {
                            Color::Blue
                        }))
                        .clone(),
                };

                writer.set_color(&line_location_color)?;
                let line_string = line.number().to_string();
                let line_location_prefix = format!("{} | ", Pad(' ', line_string.len()));
                write!(writer, "{} | ", line_string)?;
                writer.reset()?;

                write!(writer, "{}", line_prefix)?;
                writer.set_color(&label_color)?;
                write!(writer, "{}", line_marked)?;
                writer.reset()?;
                writeln!(writer, "{}", line_suffix)?;

                if !supports_color || label.message.is_some() {
                    writer.set_color(&line_location_color)?;
                    write!(writer, "{}", line_location_prefix)?;
                    writer.reset()?;

                    writer.set_color(&label_color)?;
                    write!(
                        writer,
                        "{}{}",
                        Pad(' ', line_prefix.len()),
                        Pad(mark, line_marked.len()),
                    )?;
                    writer.reset()?;

                    if label.message.is_none() {
                        writeln!(writer)?;
                    }
                }

                match label.message {
                    None => (),
                    Some(ref label) => {
                        writer.set_color(&label_color)?;
                        writeln!(writer, " {}", label)?;
                        writer.reset()?;
                    }
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::AudioNode;
use dom::audioparam::AudioParam;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
use dom::bindings::codegen::Bindings::GainNodeBinding::{self, GainNodeMethods, GainOptions};
use dom::bindings::error::Fallible;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::root::{Dom, DomRoot};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::gain_node::GainNodeOptions;
use servo_media::audio::node::AudioNodeInit;
use servo_media::audio::param::ParamType;
use std::f32;

#[dom_struct]
pub struct GainNode {
    node: AudioNode,
    gain: Dom<AudioParam>,
}

impl GainNode {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(
        window: &Window,
        context: &BaseAudioContext,
        options: &GainOptions,
    ) -> Fallible<GainNode> {
        let node_options = options.parent
                                  .unwrap_or(2, ChannelCountMode::Max,
                                             ChannelInterpretation::Speakers);
        let node = AudioNode::new_inherited(
            AudioNodeInit::GainNode(options.into()),
            context,
            node_options,
            1, // inputs
            1, // outputs
        )?;
        let gain = AudioParam::new(
            window,
            context,
            node.node_id(),
            ParamType::Gain,
            AutomationRate::A_rate,
            1.,       // default value
            f32::MIN, // min value
            f32::MAX, // max value
        );
        Ok(GainNode {
            node,
            gain: Dom::from_ref(&gain),
        })
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        window: &Window,
        context: &BaseAudioContext,
        options: &GainOptions,
    ) -> Fallible<DomRoot<GainNode>> {
        let node = GainNode::new_inherited(window, context, options)?;
        Ok(reflect_dom_object(Box::new(node), window, GainNodeBinding::Wrap))
    }

    pub fn Constructor(
        window: &Window,
        context: &BaseAudioContext,
        options: &GainOptions,
    ) -> Fallible<DomRoot<GainNode>> {
        GainNode::new(window, context, options)
    }
}

impl GainNodeMethods for GainNode {
    // https://webaudio.github.io/web-audio-api/#dom-gainnode-gain
    fn Gain(&self) -> DomRoot<AudioParam> {
        DomRoot::from_ref(&self.gain)
    }
}

impl<'a> From<&'a GainOptions> for GainNodeOptions {
    fn from(options: &'a GainOptions) -> Self {
        Self {
            gain: *options.gain,
        }
    }
}
<commit_msg>Fix GainNode constructor for gain audioparam<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::AudioNode;
use dom::audioparam::AudioParam;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
use dom::bindings::codegen::Bindings::GainNodeBinding::{self, GainNodeMethods, GainOptions};
use dom::bindings::error::Fallible;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::root::{Dom, DomRoot};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::gain_node::GainNodeOptions;
use servo_media::audio::node::AudioNodeInit;
use servo_media::audio::param::ParamType;
use std::f32;

#[dom_struct]
pub struct GainNode {
    node: AudioNode,
    gain: Dom<AudioParam>,
}

impl GainNode {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(
        window: &Window,
        context: &BaseAudioContext,
        options: &GainOptions,
    ) -> Fallible<GainNode> {
        let node_options = options.parent
                                  .unwrap_or(2, ChannelCountMode::Max,
                                             ChannelInterpretation::Speakers);
        let node = AudioNode::new_inherited(
            AudioNodeInit::GainNode(options.into()),
            context,
            node_options,
            1, // inputs
            1, // outputs
        )?;
        let gain = AudioParam::new(
            window,
            context,
            node.node_id(),
            ParamType::Gain,
            AutomationRate::A_rate,
            *options.gain,  // default value
            f32::MIN, // min value
            f32::MAX, // max value
        );
        Ok(GainNode {
            node,
            gain: Dom::from_ref(&gain),
        })
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        window: &Window,
        context: &BaseAudioContext,
        options: &GainOptions,
    ) -> Fallible<DomRoot<GainNode>> {
        let node = GainNode::new_inherited(window, context, options)?;
        Ok(reflect_dom_object(Box::new(node), window, GainNodeBinding::Wrap))
    }

    pub fn Constructor(
        window: &Window,
        context: &BaseAudioContext,
        options: &GainOptions,
    ) -> Fallible<DomRoot<GainNode>> {
        GainNode::new(window, context, options)
    }
}

impl GainNodeMethods for GainNode {
    // https://webaudio.github.io/web-audio-api/#dom-gainnode-gain
    fn Gain(&self) -> DomRoot<AudioParam> {
        DomRoot::from_ref(&self.gain)
    }
}

impl<'a> From<&'a GainOptions> for GainNodeOptions {
    fn from(options: &'a GainOptions) -> Self {
        Self {
            gain: *options.gain,
        }
    }
}
<|endoftext|>


<commit_before>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String)
}

enum Opcode {
    Text = 0x1
}

struct Message {
    payload: Payload,
    opcode: Opcode
}

impl Message {
    fn from_str (msg: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            // XXX: maybe we shouldn't own headers and should .clone() here
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes().as_slice()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             headers: Vec<ClientHeader>) {

    let msg = b"hello world";
    stream.write_u8(0b1000_0000 | Opcode::Text as u8).unwrap();
    stream.write_u8(msg.len() as u8).unwrap();
    stream.write(msg);
}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("../html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("../html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.into_bytes().as_slice()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.into_bytes().as_slice()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>some Message impl<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String)
}

enum Opcode {
    Text = 0x1
}

struct Message {
    pub payload: Payload,
    pub opcode: Opcode,
    pub length: u8
}

impl Message {
    fn new (msg: &[u8]) -> Message {
        let payload = match msg.to_string() {
            String => Payload::Text(msg.to_string())
        };
        Message {payload: payload,
                 opcode: Opcode::Text,
                 length: msg.len() as u8}
    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            // XXX: maybe we shouldn't own headers and should .clone() here
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes().as_slice()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             headers: Vec<ClientHeader>) {

    let msg = Message::new(b"hello world");
    stream.write_u8(0b1000_0000 | Opcode::Text as u8).unwrap();
    stream.write_u8(msg.length).unwrap();
    stream.write(b"hello world");
}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("../html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("../html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.into_bytes().as_slice()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.into_bytes().as_slice()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>