<commit_before>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }

    pub fn is_word(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        let second_char = chars_iterator.next();
        if second_char.is_some() {
            // We consist of multiple characters, that means we are a word
            return true;
        }

        // If we get here, it means our token consists of one character only. If
        // that single character is alphanumeric, we are a word, otherwise not.
        return first_char.is_alphanumeric();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    bytes_count: usize,
    highlighted_bytes_count: usize,
    rendered: bool,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    pub fn inverted(&self) -> Style {
        return match self {
            Style::Old => Style::OldInverse,
            Style::New => Style::NewInverse,
            Style::OldInverse => Style::OldInverse,
            Style::NewInverse => Style::NewInverse,
            Style::Error => Style::Error,
        };
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            bytes_count: 0,
            highlighted_bytes_count: 0,
            rendered: false,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if row.is_empty() {
            return rendered;
        }

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }
        highlight_space_between_words(row);

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    #[must_use]
    pub fn render(&mut self) -> String {
        assert!(!self.rendered);
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        let tokens = std::mem::take(&mut self.tokens);
        for token in tokens {
            self.bytes_count += token.token.len();
            if token.style.is_inverse() {
                self.highlighted_bytes_count += token.token.len();
            }

            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token);
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        self.rendered = true;
        return rendered;
    }

    pub fn chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.bytes_count;
    }

    pub fn highlighted_chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.highlighted_bytes_count;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

/// Highlight single space between two highlighted words
fn highlight_space_between_words(row: &mut [StyledToken]) {
    enum FoundState {
        Nothing,
        HighlightedWord,
        WordSpace,
    };

    let mut found_state = FoundState::Nothing;
    let mut previous_token: Option<&mut StyledToken> = None;
    for token in row.iter_mut() {
        match found_state {
            FoundState::Nothing => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey"
                    found_state = FoundState::HighlightedWord;
                }
            }

            FoundState::HighlightedWord => {
                if token.is_whitespace() {
                    // Found "Monkey " (note trailing space)
                    found_state = FoundState::WordSpace;
                } else if token.style.is_inverse() && token.is_word() {
                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }

            FoundState::WordSpace => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey Dance"
                    if let Some(_previous_token) = previous_token {
                        _previous_token.style = _previous_token.style.inverted();
                    }

                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }
        }

        previous_token = Some(token);
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }

    #[test]
    fn test_highlight_space_between_words() {
        let mut row = [
            StyledToken::new("Monkey".to_string(), Style::NewInverse),
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("Dance".to_string(), Style::NewInverse),
        ];

        highlight_space_between_words(&mut row);

        assert_eq!(
            row,
            [
                StyledToken::new("Monkey".to_string(), Style::NewInverse),
                StyledToken::new(" ".to_string(), Style::NewInverse),
                StyledToken::new("Dance".to_string(), Style::NewInverse),
            ]
        );
    }
}
<commit_msg>Address lint issue for newer versions of rustc/clippy<commit_after>use crate::constants::*;

#[derive(Clone, Debug, PartialEq)]
pub enum Style {
    Old,
    OldInverse,
    New,
    NewInverse,
    Error,
}

#[derive(Clone, Debug, PartialEq)]
pub struct StyledToken {
    token: String,
    style: Style,
}

impl StyledToken {
    pub fn new(token: String, style: Style) -> StyledToken {
        return StyledToken { token, style };
    }

    pub fn is_whitespace(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        if chars_iterator.next().is_some() {
            // Multiple chars found in this token, but whitespace will only be
            // one per token.
            return false;
        }

        return first_char.is_whitespace();
    }

    pub fn is_word(&self) -> bool {
        let mut chars_iterator = self.token.chars();
        let first_char = chars_iterator.next().unwrap();
        let second_char = chars_iterator.next();
        if second_char.is_some() {
            // We consist of multiple characters, that means we are a word
            return true;
        }

        // If we get here, it means our token consists of one character only. If
        // that single character is alphanumeric, we are a word, otherwise not.
        return first_char.is_alphanumeric();
    }
}

pub struct TokenCollector {
    line_prefix: StyledToken,
    tokens: Vec<StyledToken>,
    bytes_count: usize,
    highlighted_bytes_count: usize,
    rendered: bool,
}

impl Style {
    #[must_use]
    pub fn is_inverse(&self) -> bool {
        match self {
            Style::OldInverse | Style::NewInverse | Style::Error => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    pub fn inverted(&self) -> Style {
        return match self {
            Style::Old => Style::OldInverse,
            Style::New => Style::NewInverse,
            Style::OldInverse => Style::OldInverse,
            Style::NewInverse => Style::NewInverse,
            Style::Error => Style::Error,
        };
    }

    #[must_use]
    pub fn color<'a>(&self) -> &'a str {
        match self {
            Style::Old => {
                return OLD;
            }
            Style::OldInverse => {
                return OLD;
            }
            Style::New => {
                return NEW;
            }
            Style::NewInverse => {
                return NEW;
            }
            Style::Error => {
                return ERROR;
            }
        }
    }
}

impl TokenCollector {
    #[must_use]
    pub fn create(line_prefix: StyledToken) -> Self {
        return TokenCollector {
            line_prefix,
            tokens: Vec::new(),
            bytes_count: 0,
            highlighted_bytes_count: 0,
            rendered: false,
        };
    }

    pub fn push(&mut self, token: StyledToken) {
        self.tokens.push(token);
    }

    #[must_use]
    fn render_row(&self, row: &mut [StyledToken]) -> String {
        let mut rendered = String::new();

        if row.is_empty() {
            return rendered;
        }

        if self.line_prefix.style == Style::New {
            highlight_trailing_whitespace(row);
            highlight_nonleading_tab(row);
        }
        highlight_space_between_words(row);

        // Set inverse from prefix
        let mut is_inverse = self.line_prefix.style.is_inverse();
        if is_inverse {
            rendered.push_str(INVERSE_VIDEO);
        }

        // Set line color from prefix
        let mut color = self.line_prefix.style.color();
        rendered.push_str(self.line_prefix.style.color());

        // Render prefix
        rendered.push_str(&self.line_prefix.token);

        for token in row {
            if token.style.is_inverse() && !is_inverse {
                rendered.push_str(INVERSE_VIDEO);
            }
            if is_inverse && !token.style.is_inverse() {
                rendered.push_str(NOT_INVERSE_VIDEO);
            }
            is_inverse = token.style.is_inverse();

            if token.style.color() != color {
                rendered.push_str(token.style.color());
                color = token.style.color();
            }

            rendered.push_str(&token.token);
        }

        rendered.push_str(NORMAL);

        return rendered;
    }

    #[must_use]
    pub fn render(&mut self) -> String {
        assert!(!self.rendered);
        let mut current_row: Vec<StyledToken> = Vec::new();
        let mut rendered = String::new();

        let tokens = std::mem::take(&mut self.tokens);
        for token in tokens {
            self.bytes_count += token.token.len();
            if token.style.is_inverse() {
                self.highlighted_bytes_count += token.token.len();
            }

            if token.token == "\n" {
                let rendered_row = &self.render_row(&mut current_row);
                rendered.push_str(rendered_row);
                rendered.push('\n');
                current_row.clear();
                continue;
            }

            current_row.push(token);
        }

        if !current_row.is_empty() {
            let rendered_row = &self.render_row(&mut current_row);
            rendered.push_str(rendered_row);
        }

        self.rendered = true;
        return rendered;
    }

    pub fn chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.bytes_count;
    }

    pub fn highlighted_chars_count(&self) -> usize {
        assert!(self.rendered); // It's the rendering that does the counting
        return self.highlighted_bytes_count;
    }
}

fn highlight_trailing_whitespace(row: &mut [StyledToken]) {
    for token in row.iter_mut().rev() {
        if !token.is_whitespace() {
            return;
        }

        token.style = Style::Error;
    }
}

fn highlight_nonleading_tab(row: &mut [StyledToken]) {
    let mut token_iter = row.iter_mut();

    // Skip leading TABs
    loop {
        let next = token_iter.next();
        if next.is_none() {
            // Done!
            return;
        }

        let token = next.unwrap();
        if token.token != "\t" {
            // Not a TAB, this means we're out of skipping the leading TABs
            break;
        }
    }

    // Scan the rest of the line for non-leading TABs
    for token in token_iter {
        if token.token != "\t" {
            // Not a TAB, never mind
            continue;
        }

        // Non-leading TAB, mark it!
        token.style = Style::Error;
    }
}

/// Highlight single space between two highlighted words
fn highlight_space_between_words(row: &mut [StyledToken]) {
    enum FoundState {
        Nothing,
        HighlightedWord,
        WordSpace,
    }

    let mut found_state = FoundState::Nothing;
    let mut previous_token: Option<&mut StyledToken> = None;
    for token in row.iter_mut() {
        match found_state {
            FoundState::Nothing => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey"
                    found_state = FoundState::HighlightedWord;
                }
            }

            FoundState::HighlightedWord => {
                if token.is_whitespace() {
                    // Found "Monkey " (note trailing space)
                    found_state = FoundState::WordSpace;
                } else if token.style.is_inverse() && token.is_word() {
                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }

            FoundState::WordSpace => {
                if token.style.is_inverse() && token.is_word() {
                    // Found "Monkey Dance"
                    if let Some(_previous_token) = previous_token {
                        _previous_token.style = _previous_token.style.inverted();
                    }

                    found_state = FoundState::HighlightedWord;
                } else {
                    found_state = FoundState::Nothing;
                }
            }
        }

        previous_token = Some(token);
    }
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_basic() {
        let mut test_me = TokenCollector::create(StyledToken {
            token: "+".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "hej".to_string(),
            style: Style::New,
        });

        test_me.push(StyledToken {
            token: "\n".to_string(),
            style: Style::New,
        });

        let rendered = test_me.render();
        assert_eq!(rendered, format!("{}+hej{}\n", NEW, NORMAL));
    }

    #[test]
    fn test_add_trailing_whitespace() {
        // Just a whitespace
        let mut row = [StyledToken::new(" ".to_string(), Style::New)];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(row, [StyledToken::new(" ".to_string(), Style::Error)]);

        // Trailing whitespace
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new(" ".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new(" ".to_string(), Style::Error),
            ]
        );

        // Leading whitespace
        let mut row = [
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_trailing_whitespace(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new(" ".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );
    }

    #[test]
    fn test_removed_trailing_whitespace() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new(" ".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}- {}", OLD, NORMAL));
    }

    #[test]
    fn test_add_nonleading_tab() {
        // Trailing TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
            ]
        );

        // Middle TAB
        let mut row = [
            StyledToken::new("x".to_string(), Style::New),
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("y".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("x".to_string(), Style::New),
                StyledToken::new("\t".to_string(), Style::Error),
                StyledToken::new("y".to_string(), Style::New),
            ]
        );

        // Leading TAB (don't highlight)
        let mut row = [
            StyledToken::new("\t".to_string(), Style::New),
            StyledToken::new("x".to_string(), Style::New),
        ];
        highlight_nonleading_tab(&mut row);
        assert_eq!(
            row,
            [
                StyledToken::new("\t".to_string(), Style::New),
                StyledToken::new("x".to_string(), Style::New),
            ]
        );

        // Single TAB (don't highlight because it is leading)
        let mut row = [StyledToken::new("\t".to_string(), Style::New)];
        highlight_nonleading_tab(&mut row);
        assert_eq!(row, [StyledToken::new("\t".to_string(), Style::New),]);
    }

    #[test]
    fn test_removed_nonleading_tab() {
        // It shouldn't be highlighted, just added ones should
        let mut test_me = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
        test_me.push(StyledToken::new("x".to_string(), Style::Old));
        test_me.push(StyledToken::new("\t".to_string(), Style::Old));
        let actual = test_me.render();

        assert_eq!(actual, format!("{}-x\t{}", OLD, NORMAL));
    }

    #[test]
    fn test_highlight_space_between_words() {
        let mut row = [
            StyledToken::new("Monkey".to_string(), Style::NewInverse),
            StyledToken::new(" ".to_string(), Style::New),
            StyledToken::new("Dance".to_string(), Style::NewInverse),
        ];

        highlight_space_between_words(&mut row);

        assert_eq!(
            row,
            [
                StyledToken::new("Monkey".to_string(), Style::NewInverse),
                StyledToken::new(" ".to_string(), Style::NewInverse),
                StyledToken::new("Dance".to_string(), Style::NewInverse),
            ]
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error;
use std::fmt;
use std::io;
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{ToSocketAddrs, SocketAddr, UdpSocket};

use cadence::prelude::*;
use cadence::{MetricSink, MetricResult, ErrorKind};

#[macro_use]
pub mod macros;

static mut CLIENT: Option<*const Metric> = None;
// IS_INITIALIZED indicates the state of CLIENT,
// `false` for uninitialized, `true` for initialized.
static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);

pub trait Metric: Counted + Gauged + Metered + Timed {}

impl<T: Counted + Gauged + Metered + Timed> Metric for T {}

/// The type returned by `set_metric_client` if `set_metric_client` has already been called.
#[derive(Debug)]
pub struct SetMetricError;

impl fmt::Display for SetMetricError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "attempted to set a metric client after the metric system was already initialized")
    }
}

impl error::Error for SetMetricError {
    fn description(&self) -> &str {
        "set_metric_client() called multiple times"
    }
}

pub fn set_metric_client(client: Box<Metric + Send + Sync>) -> Result<(), SetMetricError> {
    unsafe {
        if IS_INITIALIZED.compare_and_swap(false, true, Ordering::SeqCst) != false {
            return Err(SetMetricError);
        }

        CLIENT = Some(Box::into_raw(client));
        Ok(())
    }
}

#[doc(hidden)]
pub fn client() -> Option<&'static Metric> {
    if IS_INITIALIZED.load(Ordering::SeqCst) != true {
        return None;
    }

    unsafe { CLIENT.map(|c| &*c) }
}

/// Implementation of a `MetricSink` that emits metrics over UDP with nonblocking mode.
// TODO: add buffer.
pub struct NonblockUdpMetricSink {
    sink_addr: SocketAddr,
    socket: UdpSocket,
}

impl NonblockUdpMetricSink {
    pub fn from<A>(sink_addr: A, socket: UdpSocket) -> MetricResult<NonblockUdpMetricSink>
        where A: ToSocketAddrs
    {
        let mut addr_iter = try!(sink_addr.to_socket_addrs());
        let addr = try!(addr_iter.next()
            .ok_or((ErrorKind::InvalidInput, "No socket addresses yielded")));

        // Moves this UDP stream into nonblocking mode.
        let _ = socket.set_nonblocking(true).unwrap();

        Ok(NonblockUdpMetricSink {
            sink_addr: addr,
            socket: socket,
        })
    }
}

impl MetricSink for NonblockUdpMetricSink {
    fn emit(&self, metric: &str) -> io::Result<usize> {
        self.socket.send_to(metric.as_bytes(), &self.sink_addr)
    }
}
<commit_msg>metric: make clippy happy. (#652)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error;
use std::fmt;
use std::io;
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{ToSocketAddrs, SocketAddr, UdpSocket};

use cadence::prelude::*;
use cadence::{MetricSink, MetricResult, ErrorKind};

#[macro_use]
pub mod macros;

static mut CLIENT: Option<*const Metric> = None;
// IS_INITIALIZED indicates the state of CLIENT,
// `false` for uninitialized, `true` for initialized.
static IS_INITIALIZED: AtomicBool = AtomicBool::new(false);

pub trait Metric: Counted + Gauged + Metered + Timed {}

impl<T: Counted + Gauged + Metered + Timed> Metric for T {}

/// The type returned by `set_metric_client` if `set_metric_client` has already been called.
#[derive(Debug)]
pub struct SetMetricError;

impl fmt::Display for SetMetricError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt,
               "attempted to set a metric client after the metric system was already initialized")
    }
}

impl error::Error for SetMetricError {
    fn description(&self) -> &str {
        "set_metric_client() called multiple times"
    }
}

pub fn set_metric_client(client: Box<Metric + Send + Sync>) -> Result<(), SetMetricError> {
    unsafe {
        if IS_INITIALIZED.compare_and_swap(false, true, Ordering::SeqCst) != false {
            return Err(SetMetricError);
        }

        CLIENT = Some(Box::into_raw(client));
        Ok(())
    }
}

#[doc(hidden)]
pub fn client() -> Option<&'static Metric> {
    if IS_INITIALIZED.load(Ordering::SeqCst) != true {
        return None;
    }

    unsafe { CLIENT.map(|c| &*c) }
}

/// Implementation of a `MetricSink` that emits metrics over UDP with nonblocking mode.
// TODO: add buffer.
pub struct NonblockUdpMetricSink {
    sink_addr: SocketAddr,
    socket: UdpSocket,
}

impl NonblockUdpMetricSink {
    pub fn from<A>(sink_addr: A, socket: UdpSocket) -> MetricResult<NonblockUdpMetricSink>
        where A: ToSocketAddrs
    {
        let mut addr_iter = try!(sink_addr.to_socket_addrs());
        let addr = try!(addr_iter.next()
            .ok_or((ErrorKind::InvalidInput, "No socket addresses yielded")));

        // Moves this UDP stream into nonblocking mode.
        try!(socket.set_nonblocking(true));

        Ok(NonblockUdpMetricSink {
            sink_addr: addr,
            socket: socket,
        })
    }
}

impl MetricSink for NonblockUdpMetricSink {
    fn emit(&self, metric: &str) -> io::Result<usize> {
        self.socket.send_to(metric.as_bytes(), &self.sink_addr)
    }
}
<|endoftext|>


<commit_before>use Printer;
use With;
use XY;
use align::*;
use direction::Direction;
use event::*;
use owning_ref::{ArcRef, OwningHandle};
use std::ops::Deref;
use std::sync::{Mutex, MutexGuard};
use std::sync::Arc;
use unicode_width::UnicodeWidthStr;
use utils::{LinesIterator, Row};
use vec::Vec2;
use view::{ScrollBase, ScrollStrategy, SizeCache, View};

/// Provides access to the content of a TextView.
#[derive(Clone)]
pub struct TextContent {
    content: Arc<Mutex<TextContentInner>>,
}

impl TextContent {
    /// Creates a new text content around the given value.
    pub fn new<S: Into<String>>(content: S) -> Self {
        TextContent {
            content: Arc::new(Mutex::new(TextContentInner {
                content: content.into(),
                size_cache: None,
            })),
        }
    }
}

/// A reference to the text content.
///
/// It implements `Deref<Target=str>`.
///
/// This keeps the content locked. Do not store this!
pub struct TextContentRef {
    handle: OwningHandle<
        ArcRef<Mutex<TextContentInner>>,
        MutexGuard<'static, TextContentInner>,
    >,
}

impl Deref for TextContentRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.handle.content
    }
}

impl TextContent {
    /// Replaces the content with the given value.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        self.with_content(|c| *c = content.into());
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append_content(&mut self, content: &str) {
        self.with_content(|c| c.push_str(content));
    }

    /// Returns a reference to the content.
    ///
    /// This locks the data while the returned value is alive,
    /// so don't keep it too long.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    fn with_content<F>(&mut self, f: F)
    where
        F: FnOnce(&mut String),
    {
        let mut lock = self.content.lock().unwrap();

        f(&mut lock.content);

        lock.size_cache = None;
    }
}

struct TextContentInner {
    content: String,
    size_cache: Option<XY<SizeCache>>,
}

impl TextContentInner {
    fn get_content(content: &Arc<Mutex<TextContentInner>>) -> TextContentRef {
        let arc_ref: ArcRef<Mutex<TextContentInner>> =
            ArcRef::new(Arc::clone(content));

        TextContentRef {
            handle: OwningHandle::new_with_fn(arc_ref, |mutex| unsafe {
                (*mutex).lock().unwrap()
            }),
        }
    }
}

/// A simple view showing a fixed text
pub struct TextView {
    // content: String,
    content: Arc<Mutex<TextContentInner>>,
    rows: Vec<Row>,

    align: Align,

    // If `false`, disable scrolling.
    scrollable: bool,

    // ScrollBase make many scrolling-related things easier
    scrollbase: ScrollBase,
    scroll_strategy: ScrollStrategy,
    last_size: Vec2,
    width: Option<usize>,
}

// If the last character is a newline, strip it.
fn strip_last_newline(content: &str) -> &str {
    if content.ends_with('\n') {
        &content[..content.len() - 1]
    } else {
        content
    }
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S: Into<String>>(content: S) -> Self {
        TextView::new_with_content(TextContent::new(content))
    }

    /// Creates a new TextView using the given `Arc<Mutex<String>>`.
    pub fn new_with_content(content: TextContent) -> Self {
        TextView {
            content: Arc::clone(&content.content),
            rows: Vec::new(),
            scrollable: true,
            scrollbase: ScrollBase::new(),
            scroll_strategy: ScrollStrategy::KeepRow,
            align: Align::top_left(),
            last_size: Vec2::zero(),
            width: None,
        }
    }

    /// Creates a new empty `TextView`.
    pub fn empty() -> Self {
        TextView::new("")
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    pub fn set_scrollable(&mut self, scrollable: bool) {
        self.scrollable = scrollable;
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    ///
    /// Chainable variant.
    pub fn scrollable(self, scrollable: bool) -> Self {
        self.with(|s| s.set_scrollable(scrollable))
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    ///
    /// Chainable variant.
    pub fn content<S: Into<String>>(self, content: S) -> Self {
        self.with(|s| s.set_content(content))
    }

    /// Replace the text in this view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        let content = content.into();
        self.content.lock().unwrap().content = content;
        self.invalidate();
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append_content(&mut self, content: &str) {
        self.content.lock().unwrap().content.push_str(content);
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    /// Returns a shared reference to the content, allowing content mutation.
    pub fn get_shared_content(&mut self) -> TextContent {
        // We take &mut here without really needing it,
        // because it sort of "makes sense".

        TextContent {
            content: Arc::clone(&self.content),
        }
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        let content = self.content.lock().unwrap();

        match content.size_cache {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// The scroll strategy defines how the scrolling position is adjusted
    /// when the size of the view or the content change.
    ///
    /// It is reset to `ScrollStrategy::KeepRow` whenever the user scrolls
    /// manually.
    pub fn set_scroll_strategy(&mut self, strategy: ScrollStrategy) {
        self.scroll_strategy = strategy;
        self.adjust_scroll();
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// Chainable variant.
    pub fn scroll_strategy(self, strategy: ScrollStrategy) -> Self {
        self.with(|s| s.set_scroll_strategy(strategy))
    }

    // Apply the scrolling strategy to the current scroll position.
    //
    // Called when computing rows and when applying a new strategy.
    fn adjust_scroll(&mut self) {
        match self.scroll_strategy {
            ScrollStrategy::StickToTop => self.scrollbase.scroll_top(),
            ScrollStrategy::StickToBottom => self.scrollbase.scroll_bottom(),
            ScrollStrategy::KeepRow => (),
        };
    }

    // This must be non-destructive, as it may be called
    // multiple times during layout.
    fn compute_rows(&mut self, size: Vec2) {
        let mut content = self.content.lock().unwrap();
        if self.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        content.size_cache = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        // First attempt: naively hope that we won't need a scrollbar_width
        // (This means we try to use the entire available width for text).
        self.rows =
            LinesIterator::new(strip_last_newline(&content.content), size.x)
                .collect();

        // Width taken by the scrollbar. Without a scrollbar, it's 0.
        let mut scrollbar_width = 0;

        if self.scrollable && self.rows.len() > size.y {
            // We take 1 column for the bar itself + 1 spacing column
            scrollbar_width = 2;

            // If we're too high, include a scrollbar_width
            let available = match size.x.checked_sub(scrollbar_width) {
                Some(s) => s,
                None => return,
            };

            self.rows =
                LinesIterator::new(&content.content, available).collect();

            if self.rows.is_empty() && !content.content.is_empty() {
                // We have some content, we we didn't find any row for it?
                // This probably means we couldn't even make a single row
                // (for instance we only have 1 column and we have a wide
                // character).
                return;
            }
        }

        // Desired width, including the scrollbar_width.
        self.width = self.rows
            .iter()
            .map(|row| row.width)
            .max()
            .map(|w| w + scrollbar_width);

        // The entire "virtual" size (includes all rows)
        let mut my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // If we're scrolling, cap the the available size.
        if self.scrollable && my_size.y > size.y {
            my_size.y = size.y;
        }

        // Build a fresh cache.
        content.size_cache = Some(SizeCache::build(my_size, size));
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        let mut content = self.content.lock().unwrap();
        content.size_cache = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer) {
        let h = self.rows.len();
        // If the content is smaller than the view, align it somewhere.
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer = &printer.offset((0, offset), true);

        let content = self.content.lock().unwrap();

        self.scrollbase.draw(printer, |printer, i| {
            let row = &self.rows[i];
            let text = &content.content[row.start..row.end];
            let l = text.width();
            let x = self.align.h.get_offset(l, printer.size.x);
            printer.print((x, 0), text);
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if !self.scrollbase.scrollable() {
            return EventResult::Ignored;
        }

        // We have a scrollbar, otherwise the event would just be ignored.
        match event {
            Event::Key(Key::Home) => self.scrollbase.scroll_top(),
            Event::Key(Key::End) => self.scrollbase.scroll_bottom(),
            Event::Key(Key::Up) if self.scrollbase.can_scroll_up() => {
                self.scrollbase.scroll_up(1)
            }
            Event::Key(Key::Down) if self.scrollbase.can_scroll_down() => {
                self.scrollbase.scroll_down(1)
            }
            Event::Mouse {
                event: MouseEvent::WheelDown,
                ..
            } if self.scrollbase.can_scroll_down() =>
            {
                self.scrollbase.scroll_down(5);
            }
            Event::Mouse {
                event: MouseEvent::WheelUp,
                ..
            } if self.scrollbase.can_scroll_up() =>
            {
                self.scrollbase.scroll_up(5);
            }
            Event::Mouse {
                event: MouseEvent::Press(MouseButton::Left),
                position,
                offset,
            } if position
                .checked_sub(offset)
                .map(|position| {
                    self.scrollbase.start_drag(position, self.last_size.x)
                })
                .unwrap_or(false) =>
            {
                // Only consume the event if the mouse hits the scrollbar.
                // Start scroll drag at the given position.
            }
            Event::Mouse {
                event: MouseEvent::Hold(MouseButton::Left),
                position,
                offset,
            } => {
                // If the mouse is dragged, we always consume the event.
                let position = position.saturating_sub(offset);
                self.scrollbase.drag(position);
            }
            Event::Mouse {
                event: MouseEvent::Release(MouseButton::Left),
                ..
            } => {
                self.scrollbase.release_grab();
            }
            Event::Key(Key::PageDown) => self.scrollbase.scroll_down(10),
            Event::Key(Key::PageUp) => self.scrollbase.scroll_up(10),
            _ => return EventResult::Ignored,
        }

        // We just scrolled manually, so reset the scroll strategy.
        self.scroll_strategy = ScrollStrategy::KeepRow;
        EventResult::Consumed(None)
    }

    fn needs_relayout(&self) -> bool {
        let content = self.content.lock().unwrap();
        content.size_cache.is_none()
    }

    fn required_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        // This is what we'd like
        let mut ideal = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        if self.scrollable && ideal.y > size.y {
            ideal.y = size.y;
        }

        ideal
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.scrollbase.scrollable()
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.last_size = size;
        self.compute_rows(size);
        // Adjust scrolling, in case we're sticking to the bottom for instance.
        self.scrollbase.set_heights(size.y, self.rows.len());
        self.adjust_scroll();
    }
}
<commit_msg>No need to clone the Arc<commit_after>use Printer;
use With;
use XY;
use align::*;
use direction::Direction;
use event::*;
use owning_ref::{ArcRef, OwningHandle};
use std::ops::Deref;
use std::sync::{Mutex, MutexGuard};
use std::sync::Arc;
use unicode_width::UnicodeWidthStr;
use utils::{LinesIterator, Row};
use vec::Vec2;
use view::{ScrollBase, ScrollStrategy, SizeCache, View};

/// Provides access to the content of a TextView.
#[derive(Clone)]
pub struct TextContent {
    content: Arc<Mutex<TextContentInner>>,
}

impl TextContent {
    /// Creates a new text content around the given value.
    pub fn new<S: Into<String>>(content: S) -> Self {
        TextContent {
            content: Arc::new(Mutex::new(TextContentInner {
                content: content.into(),
                size_cache: None,
            })),
        }
    }
}

/// A reference to the text content.
///
/// It implements `Deref<Target=str>`.
///
/// This keeps the content locked. Do not store this!
pub struct TextContentRef {
    handle: OwningHandle<
        ArcRef<Mutex<TextContentInner>>,
        MutexGuard<'static, TextContentInner>,
    >,
}

impl Deref for TextContentRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.handle.content
    }
}

impl TextContent {
    /// Replaces the content with the given value.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        self.with_content(|c| *c = content.into());
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append_content(&mut self, content: &str) {
        self.with_content(|c| c.push_str(content));
    }

    /// Returns a reference to the content.
    ///
    /// This locks the data while the returned value is alive,
    /// so don't keep it too long.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    fn with_content<F>(&mut self, f: F)
    where
        F: FnOnce(&mut String),
    {
        let mut lock = self.content.lock().unwrap();

        f(&mut lock.content);

        lock.size_cache = None;
    }
}

struct TextContentInner {
    content: String,
    size_cache: Option<XY<SizeCache>>,
}

impl TextContentInner {
    fn get_content(content: &Arc<Mutex<TextContentInner>>) -> TextContentRef {
        let arc_ref: ArcRef<Mutex<TextContentInner>> =
            ArcRef::new(Arc::clone(content));

        TextContentRef {
            handle: OwningHandle::new_with_fn(arc_ref, |mutex| unsafe {
                (*mutex).lock().unwrap()
            }),
        }
    }
}

/// A simple view showing a fixed text
pub struct TextView {
    // content: String,
    content: Arc<Mutex<TextContentInner>>,
    rows: Vec<Row>,

    align: Align,

    // If `false`, disable scrolling.
    scrollable: bool,

    // ScrollBase make many scrolling-related things easier
    scrollbase: ScrollBase,
    scroll_strategy: ScrollStrategy,
    last_size: Vec2,
    width: Option<usize>,
}

// If the last character is a newline, strip it.
fn strip_last_newline(content: &str) -> &str {
    if content.ends_with('\n') {
        &content[..content.len() - 1]
    } else {
        content
    }
}

impl TextView {
    /// Creates a new TextView with the given content.
    pub fn new<S: Into<String>>(content: S) -> Self {
        TextView::new_with_content(TextContent::new(content))
    }

    /// Creates a new TextView using the given `Arc<Mutex<String>>`.
    pub fn new_with_content(content: TextContent) -> Self {
        TextView {
            content: content.content,
            rows: Vec::new(),
            scrollable: true,
            scrollbase: ScrollBase::new(),
            scroll_strategy: ScrollStrategy::KeepRow,
            align: Align::top_left(),
            last_size: Vec2::zero(),
            width: None,
        }
    }

    /// Creates a new empty `TextView`.
    pub fn empty() -> Self {
        TextView::new("")
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    pub fn set_scrollable(&mut self, scrollable: bool) {
        self.scrollable = scrollable;
    }

    /// Enable or disable the view's scrolling capabilities.
    ///
    /// When disabled, the view will never attempt to scroll
    /// (and will always ask for the full height).
    ///
    /// Chainable variant.
    pub fn scrollable(self, scrollable: bool) -> Self {
        self.with(|s| s.set_scrollable(scrollable))
    }

    /// Sets the horizontal alignment for this view.
    pub fn h_align(mut self, h: HAlign) -> Self {
        self.align.h = h;

        self
    }

    /// Sets the vertical alignment for this view.
    pub fn v_align(mut self, v: VAlign) -> Self {
        self.align.v = v;

        self
    }

    /// Sets the alignment for this view.
    pub fn align(mut self, a: Align) -> Self {
        self.align = a;

        self
    }

    /// Center the text horizontally and vertically inside the view.
    pub fn center(mut self) -> Self {
        self.align = Align::center();
        self
    }

    /// Replace the text in this view.
    ///
    /// Chainable variant.
    pub fn content<S: Into<String>>(self, content: S) -> Self {
        self.with(|s| s.set_content(content))
    }

    /// Replace the text in this view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        let content = content.into();
        self.content.lock().unwrap().content = content;
        self.invalidate();
    }

    /// Append `content` to the end of a `TextView`.
    pub fn append_content(&mut self, content: &str) {
        self.content.lock().unwrap().content.push_str(content);
        self.invalidate();
    }

    /// Returns the current text in this view.
    pub fn get_content(&self) -> TextContentRef {
        TextContentInner::get_content(&self.content)
    }

    /// Returns a shared reference to the content, allowing content mutation.
    pub fn get_shared_content(&mut self) -> TextContent {
        // We take &mut here without really needing it,
        // because it sort of "makes sense".

        TextContent {
            content: Arc::clone(&self.content),
        }
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        let content = self.content.lock().unwrap();

        match content.size_cache {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// The scroll strategy defines how the scrolling position is adjusted
    /// when the size of the view or the content change.
    ///
    /// It is reset to `ScrollStrategy::KeepRow` whenever the user scrolls
    /// manually.
    pub fn set_scroll_strategy(&mut self, strategy: ScrollStrategy) {
        self.scroll_strategy = strategy;
        self.adjust_scroll();
    }

    /// Defines the way scrolling is adjusted on content or size change.
    ///
    /// Chainable variant.
    pub fn scroll_strategy(self, strategy: ScrollStrategy) -> Self {
        self.with(|s| s.set_scroll_strategy(strategy))
    }

    // Apply the scrolling strategy to the current scroll position.
    //
    // Called when computing rows and when applying a new strategy.
    fn adjust_scroll(&mut self) {
        match self.scroll_strategy {
            ScrollStrategy::StickToTop => self.scrollbase.scroll_top(),
            ScrollStrategy::StickToBottom => self.scrollbase.scroll_bottom(),
            ScrollStrategy::KeepRow => (),
        };
    }

    // This must be non-destructive, as it may be called
    // multiple times during layout.
    fn compute_rows(&mut self, size: Vec2) {
        let mut content = self.content.lock().unwrap();
        if self.is_cache_valid(size) {
            return;
        }

        // Completely bust the cache
        // Just in case we fail, we don't want to leave a bad cache.
        content.size_cache = None;

        if size.x == 0 {
            // Nothing we can do at this point.
            return;
        }

        // First attempt: naively hope that we won't need a scrollbar_width
        // (This means we try to use the entire available width for text).
        self.rows =
            LinesIterator::new(strip_last_newline(&content.content), size.x)
                .collect();

        // Width taken by the scrollbar. Without a scrollbar, it's 0.
        let mut scrollbar_width = 0;

        if self.scrollable && self.rows.len() > size.y {
            // We take 1 column for the bar itself + 1 spacing column
            scrollbar_width = 2;

            // If we're too high, include a scrollbar_width
            let available = match size.x.checked_sub(scrollbar_width) {
                Some(s) => s,
                None => return,
            };

            self.rows =
                LinesIterator::new(&content.content, available).collect();

            if self.rows.is_empty() && !content.content.is_empty() {
                // We have some content, we we didn't find any row for it?
                // This probably means we couldn't even make a single row
                // (for instance we only have 1 column and we have a wide
                // character).
                return;
            }
        }

        // Desired width, including the scrollbar_width.
        self.width = self.rows
            .iter()
            .map(|row| row.width)
            .max()
            .map(|w| w + scrollbar_width);

        // The entire "virtual" size (includes all rows)
        let mut my_size = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        // If we're scrolling, cap the the available size.
        if self.scrollable && my_size.y > size.y {
            my_size.y = size.y;
        }

        // Build a fresh cache.
        content.size_cache = Some(SizeCache::build(my_size, size));
    }

    // Invalidates the cache, so next call will recompute everything.
    fn invalidate(&mut self) {
        let mut content = self.content.lock().unwrap();
        content.size_cache = None;
    }
}

impl View for TextView {
    fn draw(&self, printer: &Printer) {
        let h = self.rows.len();
        // If the content is smaller than the view, align it somewhere.
        let offset = self.align.v.get_offset(h, printer.size.y);
        let printer = &printer.offset((0, offset), true);

        let content = self.content.lock().unwrap();

        self.scrollbase.draw(printer, |printer, i| {
            let row = &self.rows[i];
            let text = &content.content[row.start..row.end];
            let l = text.width();
            let x = self.align.h.get_offset(l, printer.size.x);
            printer.print((x, 0), text);
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if !self.scrollbase.scrollable() {
            return EventResult::Ignored;
        }

        // We have a scrollbar, otherwise the event would just be ignored.
        match event {
            Event::Key(Key::Home) => self.scrollbase.scroll_top(),
            Event::Key(Key::End) => self.scrollbase.scroll_bottom(),
            Event::Key(Key::Up) if self.scrollbase.can_scroll_up() => {
                self.scrollbase.scroll_up(1)
            }
            Event::Key(Key::Down) if self.scrollbase.can_scroll_down() => {
                self.scrollbase.scroll_down(1)
            }
            Event::Mouse {
                event: MouseEvent::WheelDown,
                ..
            } if self.scrollbase.can_scroll_down() =>
            {
                self.scrollbase.scroll_down(5);
            }
            Event::Mouse {
                event: MouseEvent::WheelUp,
                ..
            } if self.scrollbase.can_scroll_up() =>
            {
                self.scrollbase.scroll_up(5);
            }
            Event::Mouse {
                event: MouseEvent::Press(MouseButton::Left),
                position,
                offset,
            } if position
                .checked_sub(offset)
                .map(|position| {
                    self.scrollbase.start_drag(position, self.last_size.x)
                })
                .unwrap_or(false) =>
            {
                // Only consume the event if the mouse hits the scrollbar.
                // Start scroll drag at the given position.
            }
            Event::Mouse {
                event: MouseEvent::Hold(MouseButton::Left),
                position,
                offset,
            } => {
                // If the mouse is dragged, we always consume the event.
                let position = position.saturating_sub(offset);
                self.scrollbase.drag(position);
            }
            Event::Mouse {
                event: MouseEvent::Release(MouseButton::Left),
                ..
            } => {
                self.scrollbase.release_grab();
            }
            Event::Key(Key::PageDown) => self.scrollbase.scroll_down(10),
            Event::Key(Key::PageUp) => self.scrollbase.scroll_up(10),
            _ => return EventResult::Ignored,
        }

        // We just scrolled manually, so reset the scroll strategy.
        self.scroll_strategy = ScrollStrategy::KeepRow;
        EventResult::Consumed(None)
    }

    fn needs_relayout(&self) -> bool {
        let content = self.content.lock().unwrap();
        content.size_cache.is_none()
    }

    fn required_size(&mut self, size: Vec2) -> Vec2 {
        self.compute_rows(size);

        // This is what we'd like
        let mut ideal = Vec2::new(self.width.unwrap_or(0), self.rows.len());

        if self.scrollable && ideal.y > size.y {
            ideal.y = size.y;
        }

        ideal
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.scrollbase.scrollable()
    }

    fn layout(&mut self, size: Vec2) {
        // Compute the text rows.
        self.last_size = size;
        self.compute_rows(size);
        // Adjust scrolling, in case we're sticking to the bottom for instance.
        self.scrollbase.set_heights(size.y, self.rows.len());
        self.adjust_scroll();
    }
}
<|endoftext|>


<commit_before>extern crate websocket;

use broadcaster;
use control_nexus::{ControlInfo, ControlNexus, ControlUpdateProcessor};
use controls;
use json;
use std::sync::{Arc, Mutex};
use std::thread;
use websocket::message::Message;
use websocket::sync::Server;
use websocket::OwnedMessage;

pub fn startserver<'a>(
  guistring: &str,
  cup: Box<dyn ControlUpdateProcessor>,
  ip: &str,
  websockets_port: &str,
  block: bool,
) -> Result<ControlNexus, Box<dyn std::error::Error>> {
  let guival = serde_json::from_str(guistring)?;

  let blah = try!(json::deserialize_root(&guival));

  println!(
    "title: {} rootcontroltype: {} ",
    blah.title,
    blah.root_control.control_type()
  );
  println!("controls: {:?}", blah.root_control);

  // from control tree, make a map of ids->controls.
  let mapp = controls::make_control_map(&*blah.root_control);
  let cnm = controls::control_map_to_name_map(&mapp);

  let ci = ControlInfo {
    cm: mapp,
    cnm: cnm,
    guijson: String::new() + guistring,
  };

  let cmshare = Arc::new(Mutex::new(ci));
  let wscmshare = cmshare.clone();
  // for sending, bind to this.  if we bind to localhost, we can't
  // send messages to other machines.
  let bc = broadcaster::Broadcaster::new();
  let wsbc = bc.clone();

  let cs_ret = ControlNexus {
    ci: cmshare,
    bc: bc,
  };

  let mut websockets_ip = String::from(ip);
  websockets_ip.push_str(":");
  websockets_ip.push_str(&websockets_port);

  if block {
    match websockets_main(websockets_ip, wscmshare, wsbc, Arc::new(Mutex::new(cup))) {
      Ok(_) => (),
      Err(e) => println!("error in websockets_main: {:?}", e),
    }
  } else {
    // Spawn a thread for the websockets handler.
    thread::spawn(move || {
      match websockets_main(websockets_ip, wscmshare, wsbc, Arc::new(Mutex::new(cup))) {
        Ok(_) => (),
        Err(e) => println!("error in websockets_main: {:?}", e),
      }
    });
  }

  Ok(cs_ret)
}

fn websockets_main(
  ipaddr: String,
  ci: Arc<Mutex<ControlInfo>>,
  broadcaster: broadcaster::Broadcaster,
  cup: Arc<Mutex<Box<dyn ControlUpdateProcessor>>>,
) -> Result<(), Box<dyn std::error::Error>> {
  println!("websockets_main {:?}", ipaddr);
  let server = Server::bind(&ipaddr[..])?;
  for request in server.filter_map(Result::ok) {
    let sci = ci.clone();
    let mut broadcaster = broadcaster.clone();
    let cup = cup.clone();
    println!("request: {:?}", request.protocols());
    // Spawn a new thread for each connection.
    thread::spawn(move || {
      if !request.protocols().contains(&"rust-websocket".to_string()) {
        request.reject().unwrap();
        return;
      }

      let client = request.use_protocol("rust-websocket").accept().unwrap();

      let ip = client.peer_addr().unwrap();

      println!("Connection from {}", ip);

      // TODO send up controls.

      /*    let (sender, mut receiver) = client.split();
            // register the sender with broadcaster.
            let sendmeh = Arc::new(Mutex::new(sender));
            broadcaster.register(sendmeh.clone());
      */

      /*      let message = OwnedMessage::Text("Hello".to_string());
            client.send_message(&message).unwrap();
      */
      //(websocket::receiver::Reader<std::net::TcpStream>, websocket::sender::Writer<std::net::TcpStream> )
      let (mut receiver, sender) = client.split().unwrap();

      let sendmeh = Arc::new(Mutex::new(sender));
      broadcaster.register(sendmeh.clone());

      for message in receiver.incoming_messages() {
        // TODO message handler here.
        let message = message.unwrap();

        println!("received msg: {:?}", message);

        match message {
          OwnedMessage::Close(_) => {
            let message = OwnedMessage::Close(None);
            let mut s = sendmeh.lock().unwrap();
            s.send_message(&message).unwrap();
            println!("Client {} disconnected", ip);
            return;
          }
          OwnedMessage::Ping(ping) => {
            let message = OwnedMessage::Pong(ping);
            let mut s = sendmeh.lock().unwrap();
            s.send_message(&message).unwrap();
          }
          OwnedMessage::Text(txt) => {
            println!("txt {}", txt);
            // let message = OwnedMessage::Pong(ping);
            // sender.send_message(&message).unwrap();
            match serde_json::from_str(txt.as_str()) {
              Err(e) => println!("error {:?}", e),
              Ok(jsonval) => {
                let s_um = json::decode_update_message(&jsonval);
                match s_um {
                  Some(updmsg) => {
                    {
                      println!("updmsg: {:?}", updmsg);
                      let mut sci = sci.lock().unwrap();
                      {
                        let mbcntrl = sci.cm.get_mut(controls::get_um_id(&updmsg));
                        match mbcntrl {
                          Some(cntrl) => {
                            (*cntrl).update(&updmsg);
                            broadcaster.broadcast_others(&ip, Message::text(txt.clone()));
                            ()
                          }
                          None => println!("none"),
                        }
                      }
                    }
                    let mut scup = cup.lock().unwrap();
                    let sci = match sci.lock() {
                      Ok(sci) => sci,
                      Err(poisoned) => poisoned.into_inner(),
                    };

                    scup.on_update_received(&updmsg, &*sci);
                  }
                  _ => println!("decode_update_message failed on websockets msg: {:?}", txt),
                }
              }
            }
          }
          _ => {
            println!("unrecognized message type: {:?}", message);
          }
        }
      }
    });
  }

  Ok(())
}

/*
 // send up the json of the current controls.
 {
   let sci = ci.lock().unwrap();

   let updarray = controls::cm_to_update_array(&sci.cm);

   // build json message containing both guijson and the updarray.
   let mut updvals = Vec::new();

   for upd in updarray {
     let um = json::encode_update_message(&upd);
     updvals.push(um);
   }

   let mut guival: Value = try!(serde_json::from_str(&sci.guijson[..]));

   match guival.as_object_mut() {
     Some(obj) => {
       obj.insert("state".to_string(), Value::Array(updvals));
       ()
     }
     None => (),
   }

   let guistring = try!(serde_json::ser::to_string(&guival));
   let message = Message::text(guistring);
   try!(client.send_message(&message));
}*/

/*
   Message handler

{
    let message: Message = try!(msg);
    // println!("message: {:?}", message);

    match message.opcode {
      Type::Close => {
        let message = Message::close();
        // let mut sender = try!(sendmeh.lock());
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(&mut *sender, &message));
        println!("Client {} disconnected", ip);
        return Ok(());
      }
      Type::Ping => {
        println!("Message::Ping(data)");
        let message = Message::pong(message.payload);
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(*sender, &message));
      }
      Type::Text => {
        let u8 = message.payload.to_owned();
        let str = try!(std::str::from_utf8(&*u8));
        let jsonval: Value = try!(serde_json::from_str(str));
        let s_um = json::decode_update_message(&jsonval);
        match s_um {
          Some(updmsg) => {
            {
              let mut sci = ci.lock().unwrap();
              {
                let mbcntrl = sci.cm.get_mut(controls::get_um_id(&updmsg));
                match mbcntrl {
                  Some(cntrl) => {
                    (*cntrl).update(&updmsg);
                    broadcaster.broadcast_others(&ip, Message::text(str));
                    ()
                  }
                  None => println!("none"),
                }
              }
            }
            let mut scup = cup.lock().unwrap();
            let sci = match ci.lock() {
              Ok(sci) => sci,
              Err(poisoned) => poisoned.into_inner(),
            };

            scup.on_update_received(&updmsg, &*sci);
          }
          _ => println!(
            "decode_update_message failed on websockets msg: {:?}",
            message
          ),
        }
      }
      _ => {
        println!("unknown websockets msg: {:?}", message);
      }
    }
  }*/

/*fn websockets_main(
  ipaddr: String,
  ci: Arc<Mutex<ControlInfo>>,
  broadcaster: broadcaster::Broadcaster,
  cup: Arc<Mutex<Box<dyn ControlUpdateProcessor>>>,
) -> Result<(), Box<std::error::Error>> {
  let server = try!(Server::bind(&ipaddr[..]));

  for connection in server {
    // Spawn a new thread for each connection.
    println!("new websockets connection!");
    let conn = try!(connection);
    let sci = ci.clone();
    let broadcaster = broadcaster.clone();
    let cup = cup.clone();
    thread::spawn(
      move || match websockets_client(conn, sci, broadcaster, cup) {
        Ok(_) => (),
        Err(e) => {
          println!("error in websockets thread: {:?}", e);
          ()
        }
      },
    );
  }

  Ok(())
}

*/
<commit_msg>send up controls on connect<commit_after>extern crate websocket;

use broadcaster;
use control_nexus::{ControlInfo, ControlNexus, ControlUpdateProcessor};
use controls;
use json;
use serde_json::Value;
use std::sync::{Arc, Mutex};
use std::thread;
use websocket::message::Message;
use websocket::sync::{Client, Server};
use websocket::OwnedMessage;

pub fn startserver<'a>(
  guistring: &str,
  cup: Box<dyn ControlUpdateProcessor>,
  ip: &str,
  websockets_port: &str,
  block: bool,
) -> Result<ControlNexus, Box<dyn std::error::Error>> {
  let guival = serde_json::from_str(guistring)?;

  let blah = try!(json::deserialize_root(&guival));

  println!(
    "title: {} rootcontroltype: {} ",
    blah.title,
    blah.root_control.control_type()
  );
  println!("controls: {:?}", blah.root_control);

  // from control tree, make a map of ids->controls.
  let mapp = controls::make_control_map(&*blah.root_control);
  let cnm = controls::control_map_to_name_map(&mapp);

  let ci = ControlInfo {
    cm: mapp,
    cnm: cnm,
    guijson: String::new() + guistring,
  };

  let cmshare = Arc::new(Mutex::new(ci));
  let wscmshare = cmshare.clone();
  // for sending, bind to this.  if we bind to localhost, we can't
  // send messages to other machines.
  let bc = broadcaster::Broadcaster::new();
  let wsbc = bc.clone();

  let cs_ret = ControlNexus {
    ci: cmshare,
    bc: bc,
  };

  let mut websockets_ip = String::from(ip);
  websockets_ip.push_str(":");
  websockets_ip.push_str(&websockets_port);

  if block {
    match websockets_main(websockets_ip, wscmshare, wsbc, Arc::new(Mutex::new(cup))) {
      Ok(_) => (),
      Err(e) => println!("error in websockets_main: {:?}", e),
    }
  } else {
    // Spawn a thread for the websockets handler.
    thread::spawn(move || {
      match websockets_main(websockets_ip, wscmshare, wsbc, Arc::new(Mutex::new(cup))) {
        Ok(_) => (),
        Err(e) => println!("error in websockets_main: {:?}", e),
      }
    });
  }

  Ok(cs_ret)
}

fn sendcontrols(
  ci: &Arc<Mutex<ControlInfo>>,
  client: &mut Client<std::net::TcpStream>,
) -> Result<(), Box<dyn std::error::Error>> {
  let sci = ci.lock().unwrap();

  let updarray = controls::cm_to_update_array(&sci.cm);

  // build json message containing both guijson and the updarray.
  let mut updvals = Vec::new();

  for upd in updarray {
    let um = json::encode_update_message(&upd);
    updvals.push(um);
  }

  let mut guival: Value = serde_json::from_str(&sci.guijson[..])?;

  match guival.as_object_mut() {
    Some(obj) => {
      obj.insert("state".to_string(), Value::Array(updvals));
      ()
    }
    None => (),
  }

  let guistring = serde_json::ser::to_string(&guival)?;
  let message = Message::text(guistring);
  client.send_message(&message)?;
  Ok(())
}

fn websockets_main(
  ipaddr: String,
  ci: Arc<Mutex<ControlInfo>>,
  broadcaster: broadcaster::Broadcaster,
  cup: Arc<Mutex<Box<dyn ControlUpdateProcessor>>>,
) -> Result<(), Box<dyn std::error::Error>> {
  println!("websockets_main {:?}", ipaddr);
  let server = Server::bind(&ipaddr[..])?;
  for request in server.filter_map(Result::ok) {
    let sci = ci.clone();
    let mut broadcaster = broadcaster.clone();
    let cup = cup.clone();
    println!("request: {:?}", request.protocols());
    // Spawn a new thread for each connection.
    thread::spawn(move || {
      if !request.protocols().contains(&"rust-websocket".to_string()) {
        request.reject().unwrap();
        return;
      }

      let mut client: Client<std::net::TcpStream> =
        request.use_protocol("rust-websocket").accept().unwrap();

      let ip = client.peer_addr().unwrap();

      println!("Connection from {}", ip);

      // send up controls.
      let sendres = sendcontrols(&sci, &mut client);

      //(websocket::receiver::Reader<std::net::TcpStream>, websocket::sender::Writer<std::net::TcpStream> )
      let (mut receiver, sender) = client.split().unwrap();

      let sendmeh = Arc::new(Mutex::new(sender));
      broadcaster.register(sendmeh.clone());

      for message in receiver.incoming_messages() {
        // TODO message handler here.
        let message = message.unwrap();

        println!("received msg: {:?}", message);

        match message {
          OwnedMessage::Close(_) => {
            let message = OwnedMessage::Close(None);
            let mut s = sendmeh.lock().unwrap();
            s.send_message(&message).unwrap();
            println!("Client {} disconnected", ip);
            return;
          }
          OwnedMessage::Ping(ping) => {
            let message = OwnedMessage::Pong(ping);
            let mut s = sendmeh.lock().unwrap();
            s.send_message(&message).unwrap();
          }
          OwnedMessage::Text(txt) => {
            println!("txt {}", txt);
            // let message = OwnedMessage::Pong(ping);
            // sender.send_message(&message).unwrap();
            match serde_json::from_str(txt.as_str()) {
              Err(e) => println!("error {:?}", e),
              Ok(jsonval) => {
                let s_um = json::decode_update_message(&jsonval);
                match s_um {
                  Some(updmsg) => {
                    {
                      println!("updmsg: {:?}", updmsg);
                      let mut sci = sci.lock().unwrap();
                      {
                        let mbcntrl = sci.cm.get_mut(controls::get_um_id(&updmsg));
                        match mbcntrl {
                          Some(cntrl) => {
                            (*cntrl).update(&updmsg);
                            broadcaster.broadcast_others(&ip, Message::text(txt.clone()));
                            ()
                          }
                          None => println!("none"),
                        }
                      }
                    }
                    let mut scup = cup.lock().unwrap();
                    let sci = match sci.lock() {
                      Ok(sci) => sci,
                      Err(poisoned) => poisoned.into_inner(),
                    };

                    scup.on_update_received(&updmsg, &*sci);
                  }
                  _ => println!("decode_update_message failed on websockets msg: {:?}", txt),
                }
              }
            }
          }
          _ => {
            println!("unrecognized message type: {:?}", message);
          }
        }
      }
    });
  }

  Ok(())
}

/*
 // send up the json of the current controls.
 {
   let sci = ci.lock().unwrap();

   let updarray = controls::cm_to_update_array(&sci.cm);

   // build json message containing both guijson and the updarray.
   let mut updvals = Vec::new();

   for upd in updarray {
     let um = json::encode_update_message(&upd);
     updvals.push(um);
   }

   let mut guival: Value = try!(serde_json::from_str(&sci.guijson[..]));

   match guival.as_object_mut() {
     Some(obj) => {
       obj.insert("state".to_string(), Value::Array(updvals));
       ()
     }
     None => (),
   }

   let guistring = try!(serde_json::ser::to_string(&guival));
   let message = Message::text(guistring);
   try!(client.send_message(&message));
}*/

/*
   Message handler

{
    let message: Message = try!(msg);
    // println!("message: {:?}", message);

    match message.opcode {
      Type::Close => {
        let message = Message::close();
        // let mut sender = try!(sendmeh.lock());
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(&mut *sender, &message));
        println!("Client {} disconnected", ip);
        return Ok(());
      }
      Type::Ping => {
        println!("Message::Ping(data)");
        let message = Message::pong(message.payload);
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(*sender, &message));
      }
      Type::Text => {
        let u8 = message.payload.to_owned();
        let str = try!(std::str::from_utf8(&*u8));
        let jsonval: Value = try!(serde_json::from_str(str));
        let s_um = json::decode_update_message(&jsonval);
        match s_um {
          Some(updmsg) => {
            {
              let mut sci = ci.lock().unwrap();
              {
                let mbcntrl = sci.cm.get_mut(controls::get_um_id(&updmsg));
                match mbcntrl {
                  Some(cntrl) => {
                    (*cntrl).update(&updmsg);
                    broadcaster.broadcast_others(&ip, Message::text(str));
                    ()
                  }
                  None => println!("none"),
                }
              }
            }
            let mut scup = cup.lock().unwrap();
            let sci = match ci.lock() {
              Ok(sci) => sci,
              Err(poisoned) => poisoned.into_inner(),
            };

            scup.on_update_received(&updmsg, &*sci);
          }
          _ => println!(
            "decode_update_message failed on websockets msg: {:?}",
            message
          ),
        }
      }
      _ => {
        println!("unknown websockets msg: {:?}", message);
      }
    }
  }*/

/*fn websockets_main(
  ipaddr: String,
  ci: Arc<Mutex<ControlInfo>>,
  broadcaster: broadcaster::Broadcaster,
  cup: Arc<Mutex<Box<dyn ControlUpdateProcessor>>>,
) -> Result<(), Box<std::error::Error>> {
  let server = try!(Server::bind(&ipaddr[..]));

  for connection in server {
    // Spawn a new thread for each connection.
    println!("new websockets connection!");
    let conn = try!(connection);
    let sci = ci.clone();
    let broadcaster = broadcaster.clone();
    let cup = cup.clone();
    thread::spawn(
      move || match websockets_client(conn, sci, broadcaster, cup) {
        Ok(_) => (),
        Err(e) => {
          println!("error in websockets thread: {:?}", e);
          ()
        }
      },
    );
  }

  Ok(())
}

*/
<|endoftext|>


<commit_before>//! SHA-1 (Secure Hash Algorithm)
//!
//! # WARNING!!!
//!
//! This hash function has been severely compromised. **Do not use!**
//!
//! Instead you should use SHA-2 or SHA-3 family.
//!
//! # General info
//!
//! | Name  | Digest size | Block size | Rounds | Structure            | Reference               |
//! | ----- | ----------: | ---------: | -----: | -------------------- | ----------------------- |
//! | SHA-1 |    160 bits |   512 bits |     80 | [Merkle–Damgård][md] | [FIPS 180-4][fips180-4] |
//!
//! [fips180-4]: http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf "FIPS 180-4 Secure Hash Standard (SHS)"
//! [md]: https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction

use byteorder::{ByteOrder, BigEndian};
use typenum::consts::{U20, U64, U160};
use static_buffer::{FixedBuf, FixedBuffer64, StandardPadding};

use Digest;

#[derive(Copy, Clone, Debug)]
struct State {
    a: u32,
    b: u32,
    c: u32,
    d: u32,
    e: u32,
}

macro_rules! schedule {
    ($schedule:ident[$i:expr] = $data:ident) => {
        $schedule[$i] =
              ($data[$i * 4 + 0] as u32) << 24
            | ($data[$i * 4 + 1] as u32) << 16
            | ($data[$i * 4 + 2] as u32) << 8
            | ($data[$i * 4 + 3] as u32);
    };

    ($schedule:ident[$i:expr]) => {
        $schedule[$i & 0xf] = {
              $schedule[($i - 3) & 0xf]
            ^ $schedule[($i - 8) & 0xf]
            ^ $schedule[($i - 14) & 0xf]
            ^ $schedule[($i - 16) & 0xf]
        }.rotate_left(1);
    }
}

macro_rules! process {
    () => ();
    (proc $state:ident, $f:block, $c:expr, $schedule:ident, $i:expr) => {{
        let tmp = $state.a
                      .rotate_left(5)
                      .wrapping_add($f)
                      .wrapping_add($state.e)
                      .wrapping_add($c)
                      .wrapping_add($schedule[$i & 0xf]);

        $state.e = $state.d;
        $state.d = $state.c;
        $state.c = $state.b.rotate_left(30);
        $state.b = $state.a;
        $state.a = tmp;
    }};

    (ff($state:ident, $schedule:ident[$i:expr] , $data:ident); $($rest:tt)*) => {
        schedule!($schedule[$i] = $data);
        process!(proc $state, {
            $state.d ^ ($state.b & ($state.c ^ $state.d))
        }, 0x5a827999, $schedule, $i);
        process!($($rest)*);
    };
    (ff($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            $state.d ^ ($state.b & ($state.c ^ $state.d))
        }, 0x5a827999, $schedule, $i);
        process!($($rest)*);
    };
    (gg($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            $state.b ^ $state.c ^ $state.d
        }, 0x6ed9eba1, $schedule, $i);
        process!($($rest)*);
    };
    (hh($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            ($state.b & $state.c) | ($state.d & ($state.b | $state.c))
        }, 0x8f1bbcdc, $schedule, $i);
        process!($($rest)*);
    };
    (ii($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            $state.b ^ $state.c ^ $state.d
        }, 0xca62c1d6, $schedule, $i);
        process!($($rest)*);
    };
}

impl State {
    fn new() -> Self {
        State {
            a: 0x67452301,
            b: 0xefcdab89,
            c: 0x98badcfe,
            d: 0x10325476,
            e: 0xc3d2e1f0,
        }
    }

    fn process_block(&mut self, data: &[u8]) {
        debug_assert!(data.len() == 64);

        let mut words = [0u32; 16];
        let mut state = self.clone();

        process! {
            ff(state, words[0],  data);
            ff(state, words[1],  data);
            ff(state, words[2],  data);
            ff(state, words[3],  data);
            ff(state, words[4],  data);
            ff(state, words[5],  data);
            ff(state, words[6],  data);
            ff(state, words[7],  data);
            ff(state, words[8],  data);
            ff(state, words[9],  data);
            ff(state, words[10], data);
            ff(state, words[11], data);
            ff(state, words[12], data);
            ff(state, words[13], data);
            ff(state, words[14], data);
            ff(state, words[15], data);
            ff(state, words[16]);
            ff(state, words[17]);
            ff(state, words[18]);
            ff(state, words[19]);
        }
        process! {
            gg(state, words[20]);
            gg(state, words[21]);
            gg(state, words[22]);
            gg(state, words[23]);
            gg(state, words[24]);
            gg(state, words[25]);
            gg(state, words[26]);
            gg(state, words[27]);
            gg(state, words[28]);
            gg(state, words[29]);
            gg(state, words[30]);
            gg(state, words[31]);
            gg(state, words[32]);
            gg(state, words[33]);
            gg(state, words[34]);
            gg(state, words[35]);
            gg(state, words[36]);
            gg(state, words[37]);
            gg(state, words[38]);
            gg(state, words[39]);
        }
        process! {
            hh(state, words[40]);
            hh(state, words[41]);
            hh(state, words[42]);
            hh(state, words[43]);
            hh(state, words[44]);
            hh(state, words[45]);
            hh(state, words[46]);
            hh(state, words[47]);
            hh(state, words[48]);
            hh(state, words[49]);
            hh(state, words[50]);
            hh(state, words[51]);
            hh(state, words[52]);
            hh(state, words[53]);
            hh(state, words[54]);
            hh(state, words[55]);
            hh(state, words[56]);
            hh(state, words[57]);
            hh(state, words[58]);
            hh(state, words[59]);
        }
        process! {
            ii(state, words[60]);
            ii(state, words[61]);
            ii(state, words[62]);
            ii(state, words[63]);
            ii(state, words[64]);
            ii(state, words[65]);
            ii(state, words[66]);
            ii(state, words[67]);
            ii(state, words[68]);
            ii(state, words[69]);
            ii(state, words[70]);
            ii(state, words[71]);
            ii(state, words[72]);
            ii(state, words[73]);
            ii(state, words[74]);
            ii(state, words[75]);
            ii(state, words[76]);
            ii(state, words[77]);
            ii(state, words[78]);
            ii(state, words[79]);
        }

        self.a = self.a.wrapping_add(state.a);
        self.b = self.b.wrapping_add(state.b);
        self.c = self.c.wrapping_add(state.c);
        self.d = self.d.wrapping_add(state.d);
        self.e = self.e.wrapping_add(state.e);
    }
}

/// SHA-1 implementation
///
/// For more details check [module docs](index.html)
#[derive(Clone)]
pub struct Sha1 {
    state: State,
    buffer: FixedBuffer64,
    length: u64,
}

impl Default for Sha1 {
    fn default() -> Self {
        Sha1 {
            state: State::new(),
            buffer: FixedBuffer64::new(),
            length: 0,
        }
    }
}

impl Digest for Sha1 {
    type OutputBits = U160;
    type OutputBytes = U20;

    type BlockSize = U64;

    fn update<T: AsRef<[u8]>>(&mut self, data: T) {
        let data = data.as_ref();
        self.length += data.len() as u64;

        let state = &mut self.state;
        self.buffer.input(data, |d| state.process_block(d));
    }

    fn result<T: AsMut<[u8]>>(mut self, mut out: T) {
        let state = &mut self.state;

        self.buffer.standard_padding(8, |d| state.process_block(d));
        BigEndian::write_u64(self.buffer.next(8), self.length * 8);
        state.process_block(self.buffer.full_buffer());

        let mut out = out.as_mut();
        assert!(out.len() >= Self::output_bytes());
        BigEndian::write_u32(&mut out[0..4], state.a);
        BigEndian::write_u32(&mut out[4..8], state.b);
        BigEndian::write_u32(&mut out[8..12], state.c);
        BigEndian::write_u32(&mut out[12..16], state.d);
        BigEndian::write_u32(&mut out[16..20], state.e);
    }
}
<commit_msg>perf(digest::sha1): use `unsafe` code to reduce boundary checks<commit_after>//! SHA-1 (Secure Hash Algorithm)
//!
//! # WARNING!!!
//!
//! This hash function has been severely compromised. **Do not use!**
//!
//! Instead you should use SHA-2 or SHA-3 family.
//!
//! # General info
//!
//! | Name  | Digest size | Block size | Rounds | Structure            | Reference               |
//! | ----- | ----------: | ---------: | -----: | -------------------- | ----------------------- |
//! | SHA-1 |    160 bits |   512 bits |     80 | [Merkle–Damgård][md] | [FIPS 180-4][fips180-4] |
//!
//! [fips180-4]: http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf "FIPS 180-4 Secure Hash Standard (SHS)"
//! [md]: https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction

use byteorder::{ByteOrder, BigEndian};
use typenum::consts::{U20, U64, U160};
use static_buffer::{FixedBuf, FixedBuffer64, StandardPadding};

use Digest;

#[derive(Copy, Clone, Debug)]
struct State {
    a: u32,
    b: u32,
    c: u32,
    d: u32,
    e: u32,
}

macro_rules! schedule {
    ($schedule:ident[$i:expr] = $data:ident) => {
        unsafe {
            *$schedule.get_unchecked_mut($i) =
                  (*$data.get_unchecked($i * 4 + 0) as u32) << 24
                | (*$data.get_unchecked($i * 4 + 1) as u32) << 16
                | (*$data.get_unchecked($i * 4 + 2) as u32) << 8
                | (*$data.get_unchecked($i * 4 + 3) as u32);
        }
    };

    ($schedule:ident[$i:expr]) => {
        unsafe {
            *$schedule.get_unchecked_mut($i & 0xf) = {
                  *$schedule.get_unchecked(($i - 3) & 0xf)
                ^ *$schedule.get_unchecked(($i - 8) & 0xf)
                ^ *$schedule.get_unchecked(($i - 14) & 0xf)
                ^ *$schedule.get_unchecked(($i - 16) & 0xf)
            }.rotate_left(1);
        }
    }
}

macro_rules! process {
    () => ();
    (proc $state:ident, $f:block, $c:expr, $schedule:ident, $i:expr) => {{
        let tmp = $state.a
                      .rotate_left(5)
                      .wrapping_add($f)
                      .wrapping_add($state.e)
                      .wrapping_add($c)
                      .wrapping_add(unsafe { *$schedule.get_unchecked($i & 0xf) });

        $state.e = $state.d;
        $state.d = $state.c;
        $state.c = $state.b.rotate_left(30);
        $state.b = $state.a;
        $state.a = tmp;
    }};

    (ff($state:ident, $schedule:ident[$i:expr] , $data:ident); $($rest:tt)*) => {
        schedule!($schedule[$i] = $data);
        process!(proc $state, {
            $state.d ^ ($state.b & ($state.c ^ $state.d))
        }, 0x5a827999, $schedule, $i);
        process!($($rest)*);
    };
    (ff($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            $state.d ^ ($state.b & ($state.c ^ $state.d))
        }, 0x5a827999, $schedule, $i);
        process!($($rest)*);
    };
    (gg($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            $state.b ^ $state.c ^ $state.d
        }, 0x6ed9eba1, $schedule, $i);
        process!($($rest)*);
    };
    (hh($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            ($state.b & $state.c) | ($state.d & ($state.b | $state.c))
        }, 0x8f1bbcdc, $schedule, $i);
        process!($($rest)*);
    };
    (ii($state:ident, $schedule:ident[$i:expr]); $($rest:tt)*) => {
        schedule!($schedule[$i]);
        process!(proc $state, {
            $state.b ^ $state.c ^ $state.d
        }, 0xca62c1d6, $schedule, $i);
        process!($($rest)*);
    };
}

impl State {
    fn new() -> Self {
        State {
            a: 0x67452301,
            b: 0xefcdab89,
            c: 0x98badcfe,
            d: 0x10325476,
            e: 0xc3d2e1f0,
        }
    }

    fn process_block(&mut self, data: &[u8]) {
        debug_assert!(data.len() == 64);

        let mut words = [0u32; 16];
        let mut state = self.clone();

        process! {
            ff(state, words[0],  data);
            ff(state, words[1],  data);
            ff(state, words[2],  data);
            ff(state, words[3],  data);
            ff(state, words[4],  data);
            ff(state, words[5],  data);
            ff(state, words[6],  data);
            ff(state, words[7],  data);
            ff(state, words[8],  data);
            ff(state, words[9],  data);
            ff(state, words[10], data);
            ff(state, words[11], data);
            ff(state, words[12], data);
            ff(state, words[13], data);
            ff(state, words[14], data);
            ff(state, words[15], data);
            ff(state, words[16]);
            ff(state, words[17]);
            ff(state, words[18]);
            ff(state, words[19]);
        }
        process! {
            gg(state, words[20]);
            gg(state, words[21]);
            gg(state, words[22]);
            gg(state, words[23]);
            gg(state, words[24]);
            gg(state, words[25]);
            gg(state, words[26]);
            gg(state, words[27]);
            gg(state, words[28]);
            gg(state, words[29]);
            gg(state, words[30]);
            gg(state, words[31]);
            gg(state, words[32]);
            gg(state, words[33]);
            gg(state, words[34]);
            gg(state, words[35]);
            gg(state, words[36]);
            gg(state, words[37]);
            gg(state, words[38]);
            gg(state, words[39]);
        }
        process! {
            hh(state, words[40]);
            hh(state, words[41]);
            hh(state, words[42]);
            hh(state, words[43]);
            hh(state, words[44]);
            hh(state, words[45]);
            hh(state, words[46]);
            hh(state, words[47]);
            hh(state, words[48]);
            hh(state, words[49]);
            hh(state, words[50]);
            hh(state, words[51]);
            hh(state, words[52]);
            hh(state, words[53]);
            hh(state, words[54]);
            hh(state, words[55]);
            hh(state, words[56]);
            hh(state, words[57]);
            hh(state, words[58]);
            hh(state, words[59]);
        }
        process! {
            ii(state, words[60]);
            ii(state, words[61]);
            ii(state, words[62]);
            ii(state, words[63]);
            ii(state, words[64]);
            ii(state, words[65]);
            ii(state, words[66]);
            ii(state, words[67]);
            ii(state, words[68]);
            ii(state, words[69]);
            ii(state, words[70]);
            ii(state, words[71]);
            ii(state, words[72]);
            ii(state, words[73]);
            ii(state, words[74]);
            ii(state, words[75]);
            ii(state, words[76]);
            ii(state, words[77]);
            ii(state, words[78]);
            ii(state, words[79]);
        }

        self.a = self.a.wrapping_add(state.a);
        self.b = self.b.wrapping_add(state.b);
        self.c = self.c.wrapping_add(state.c);
        self.d = self.d.wrapping_add(state.d);
        self.e = self.e.wrapping_add(state.e);
    }
}

/// SHA-1 implementation
///
/// For more details check [module docs](index.html)
#[derive(Clone)]
pub struct Sha1 {
    state: State,
    buffer: FixedBuffer64,
    length: u64,
}

impl Default for Sha1 {
    fn default() -> Self {
        Sha1 {
            state: State::new(),
            buffer: FixedBuffer64::new(),
            length: 0,
        }
    }
}

impl Digest for Sha1 {
    type OutputBits = U160;
    type OutputBytes = U20;

    type BlockSize = U64;

    fn update<T: AsRef<[u8]>>(&mut self, data: T) {
        let data = data.as_ref();
        self.length += data.len() as u64;

        let state = &mut self.state;
        self.buffer.input(data, |d| state.process_block(d));
    }

    fn result<T: AsMut<[u8]>>(mut self, mut out: T) {
        let state = &mut self.state;

        self.buffer.standard_padding(8, |d| state.process_block(d));
        BigEndian::write_u64(self.buffer.next(8), self.length * 8);
        state.process_block(self.buffer.full_buffer());

        let mut out = out.as_mut();
        assert!(out.len() >= Self::output_bytes());
        BigEndian::write_u32(&mut out[0..4], state.a);
        BigEndian::write_u32(&mut out[4..8], state.b);
        BigEndian::write_u32(&mut out[8..12], state.c);
        BigEndian::write_u32(&mut out[12..16], state.d);
        BigEndian::write_u32(&mut out[16..20], state.e);
    }
}
<|endoftext|>