<commit_before>//! # Command Parser
//!
//! The ``commands::parser`` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the ``commands::tokenizer`` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

#![allow(dead_code)]

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// root node of the command tree that was used to create this
/// parser.
///
/// The lifetime parameter `'p` refers to the lifetime of the parser
/// and of the tokens passed into this parser.
pub struct Parser<'p> {
    current_node: &'p Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<&'p Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<&'p Token<'p>>,
    commands: Vec<&'p Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: &'p Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<&'p Token<'p>>) -> Vec<Completion> {
        fn possible_completion(node: &Rc<Node>, parser: &Parser, token: Option<&Token>) -> bool {
            // To be a possible completion, the node should not be
            // hidden, it should be acceptable, and if there's a token,
            // it should be a valid match for the node.
            !node.hidden() && node.acceptable(parser) &&
            match token {
                Some(t) => node.matches(parser, t),
                _ => true,
            }
        }
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| possible_completion(n, self, token))
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<&'p Token<'p>>) {
        for token in tokens {
            if token.token_type != TokenType::Whitespace {
                self.advance(token);
            }
        }
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: &'p Token<'p>) {
        let matches = self.current_node
                          .successors()
                          .into_iter()
                          .filter(|n| n.acceptable(self) && n.matches(self, token))
                          .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node);
                self.tokens.push(token);
            }
            0 => panic!("No matches for '{}'.", token.text),
            _ => panic!("Ambiguous matches for '{}'.", token.text),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() {
                    if !self.parameters.contains_key(expected.name()) {
                        return false;
                    }
                }
            }
        }
        true
    }
}

trait Advance {
    fn acceptable(&self, parser: &Parser) -> bool;

    fn matches(&self, parser: &Parser, token: &Token) -> bool;
}

impl Advance for Node {
    fn acceptable(&self, _parser: &Parser) -> bool {
        unimplemented!();
        // !parser.nodes.contains(self)
    }

    fn matches(&self, _parser: &Parser, token: &Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token);
}

impl Accept for Node {
    fn accept<'p>(&'p self, _parser: &mut Parser<'p>, _token: &Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, _token: &Token) {
        match self.handler() {
            Some(_) => parser.commands.push(self),
            _ => {}
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<commit_msg>Parser: No longer allow dead code.<commit_after>//! # Command Parser
//!
//! The ``commands::parser`` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the ``commands::tokenizer`` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// root node of the command tree that was used to create this
/// parser.
///
/// The lifetime parameter `'p` refers to the lifetime of the parser
/// and of the tokens passed into this parser.
pub struct Parser<'p> {
    current_node: &'p Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<&'p Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<&'p Token<'p>>,
    commands: Vec<&'p Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: &'p Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<&'p Token<'p>>) -> Vec<Completion> {
        fn possible_completion(node: &Rc<Node>, parser: &Parser, token: Option<&Token>) -> bool {
            // To be a possible completion, the node should not be
            // hidden, it should be acceptable, and if there's a token,
            // it should be a valid match for the node.
            !node.hidden() && node.acceptable(parser) &&
            match token {
                Some(t) => node.matches(parser, t),
                _ => true,
            }
        }
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| possible_completion(n, self, token))
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<&'p Token<'p>>) {
        for token in tokens {
            if token.token_type != TokenType::Whitespace {
                self.advance(token);
            }
        }
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: &'p Token<'p>) {
        let matches = self.current_node
                          .successors()
                          .into_iter()
                          .filter(|n| n.acceptable(self) && n.matches(self, token))
                          .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node);
                self.tokens.push(token);
            }
            0 => panic!("No matches for '{}'.", token.text),
            _ => panic!("Ambiguous matches for '{}'.", token.text),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() {
                    if !self.parameters.contains_key(expected.name()) {
                        return false;
                    }
                }
            }
        }
        true
    }
}

trait Advance {
    fn acceptable(&self, parser: &Parser) -> bool;

    fn matches(&self, parser: &Parser, token: &Token) -> bool;
}

impl Advance for Node {
    fn acceptable(&self, _parser: &Parser) -> bool {
        unimplemented!();
        // !parser.nodes.contains(self)
    }

    fn matches(&self, _parser: &Parser, token: &Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token);
}

impl Accept for Node {
    fn accept<'p>(&'p self, _parser: &mut Parser<'p>, _token: &Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, _token: &Token) {
        match self.handler() {
            Some(_) => parser.commands.push(self),
            _ => {}
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<|endoftext|>


<commit_before>use ascii::{AsciiChar, AsciiStr};
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::convert::AsRef;
use std::iter::{ExactSizeIterator, Iterator};
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::slice::{Iter, IterMut};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    /// Returns the number of characters used in the string.
    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns true if the string has a length of 0
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns true if the string has a length of 255.
    ///
    /// When this value is true, no more elements can be pushed onto the string.
    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }

    /// Get an immutable iterator to the internal character array.
    #[inline]
    pub fn chars<'a>(&'a self) -> Chars<'a> {
        Chars(self.string.as_slice().iter())
    }

    /// Get a mutable iterator to the internal character array.
    #[inline]
    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
        CharsMut(self.string.as_mut_slice().iter_mut())
    }
}

impl AsciiExt for PascalStr {
    type Owned = PascalString;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut upper = PascalString::from(bytes).unwrap();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut lower = PascalString::from(bytes).unwrap();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.string.eq_ignore_ascii_case(&other.string)
    }

    fn make_ascii_uppercase(&mut self) {
        self.string.make_ascii_uppercase()
    }

    fn make_ascii_lowercase(&mut self) {
        self.string.make_ascii_lowercase()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from(&self.string).unwrap()
    }
}

impl AsRef<str> for PascalStr {
    fn as_ref(&self) -> &str {
        self.string.as_ref()
    }
}

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, _: RangeFull) -> &Self::Output {
        &self.string[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        &mut self.string[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        &self.string[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        &mut self.string[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.string[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.string[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        &self.string[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        &mut self.string[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        &self.string[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        &mut self.string[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        &self.string[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        &mut self.string[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = AsciiStr;
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        &self.string[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        &mut self.string[..range.end]
    }
}

/// An immutable iterator over the buffer of a `PascalStr`.
pub struct Chars<'a>(Iter<'a, AsciiChar>);

impl<'a> Iterator for Chars<'a> {
    type Item = &'a AsciiChar;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for Chars<'a> {
    fn len(&self) -> usize {
        self.0.len()
    }
}

/// A mutable iterator over the buffer of a `PascalStr`.
pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);

impl<'a> Iterator for CharsMut<'a> {
    type Item = &'a mut AsciiChar;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for CharsMut<'a> {
    fn len(&self) -> usize {
        self.0.len()
    }
}
<commit_msg>Make range index methods return a slice<commit_after>use ascii::{AsciiChar, AsciiStr};
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::convert::AsRef;
use std::iter::{ExactSizeIterator, Iterator};
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::slice::{Iter, IterMut};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    /// Returns the number of characters used in the string.
    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns true if the string has a length of 0
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns true if the string has a length of 255.
    ///
    /// When this value is true, no more elements can be pushed onto the string.
    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }

    /// Get an immutable iterator to the internal character array.
    #[inline]
    pub fn chars<'a>(&'a self) -> Chars<'a> {
        Chars(self.string.as_slice().iter())
    }

    /// Get a mutable iterator to the internal character array.
    #[inline]
    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
        CharsMut(self.string.as_mut_slice().iter_mut())
    }
}

impl AsciiExt for PascalStr {
    type Owned = PascalString;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut upper = PascalString::from(bytes).unwrap();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut lower = PascalString::from(bytes).unwrap();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.string.eq_ignore_ascii_case(&other.string)
    }

    fn make_ascii_uppercase(&mut self) {
        self.string.make_ascii_uppercase()
    }

    fn make_ascii_lowercase(&mut self) {
        self.string.make_ascii_lowercase()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from(&self.string).unwrap()
    }
}

impl AsRef<str> for PascalStr {
    fn as_ref(&self) -> &str {
        self.string.as_ref()
    }
}

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, _: RangeFull) -> &Self::Output {
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        assert!(range.start < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        assert!(range.start < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end]
    }
}

/// An immutable iterator over the buffer of a `PascalStr`.
pub struct Chars<'a>(Iter<'a, AsciiChar>);

impl<'a> Iterator for Chars<'a> {
    type Item = &'a AsciiChar;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for Chars<'a> {
    fn len(&self) -> usize {
        self.0.len()
    }
}

/// A mutable iterator over the buffer of a `PascalStr`.
pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);

impl<'a> Iterator for CharsMut<'a> {
    type Item = &'a mut AsciiChar;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for CharsMut<'a> {
    fn len(&self) -> usize {
        self.0.len()
    }
}
<|endoftext|>


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

use std::num::cast;

use angle::{Angle, tan, cot};
use frustum::Frustum;
use matrix::{Matrix4, ToMatrix4};
use num::{BaseFloat, zero, one};
use plane::Plane;

/// Create a perspective projection matrix.
///
/// This is the equivalent to the [gluPerspective]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml) function.
pub fn perspective<S: BaseFloat + 'static, A: Angle<S>>(fovy: A, aspect: S, near: S, far: S) -> Matrix4<S> {
    PerspectiveFov {
        fovy:   fovy,
        aspect: aspect,
        near:   near,
        far:    far,
    }.to_matrix4()
}

/// Create a perspective matrix from a view frustrum.
///
/// This is the equivalent of the now deprecated [glFrustrum]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
pub fn frustum<S: BaseFloat + 'static>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Matrix4<S> {
    Perspective {
        left:   left,
        right:  right,
        bottom: bottom,
        top:    top,
        near:   near,
        far:    far,
    }.to_matrix4()
}

/// Create an orthographic projection matrix.
///
/// This is the equivalent of the now deprecated [glOrtho]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
pub fn ortho<S: BaseFloat + 'static>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Matrix4<S> {
    Ortho {
        left:   left,
        right:  right,
        bottom: bottom,
        top:    top,
        near:   near,
        far:    far,
    }.to_matrix4()
}

pub trait Projection<S>: ToMatrix4<S> {
    fn to_frustum(&self) -> Frustum<S>;
}

/// A perspective projection based on a vertical field-of-view angle.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct PerspectiveFov<S, A> {
    pub fovy:   A,
    pub aspect: S,
    pub near:   S,
    pub far:    S,
}

impl<S: BaseFloat, A: Angle<S>> PerspectiveFov<S, A> {
    pub fn to_perspective(&self) -> Perspective<S> {
        let angle = self.fovy.div_s(cast(2i8).unwrap());
        let ymax = self.near * tan(angle.to_rad());
        let xmax = ymax * self.aspect;

        Perspective {
            left:   -xmax,
            right:   xmax,
            bottom: -ymax,
            top:     ymax,
            near:    self.near.clone(),
            far:     self.far.clone(),
        }
    }
}

impl<S: BaseFloat + 'static, A: Angle<S>> Projection<S> for PerspectiveFov<S, A> {
    fn to_frustum(&self) -> Frustum<S> {
        // TODO: Could this be faster?
        Frustum::from_matrix4(self.to_matrix4()).unwrap()
    }
}

impl<S: BaseFloat, A: Angle<S>> ToMatrix4<S> for PerspectiveFov<S, A> {
    fn to_matrix4(&self) -> Matrix4<S> {
        let half_turn: A = Angle::turn_div_2();

        assert!(self.fovy   > zero(),    "The vertical field of view cannot be below zero, found: {:?}", self.fovy);
        assert!(self.fovy   < half_turn, "The vertical field of view cannot be greater than a half turn, found: {:?}", self.fovy);
        assert!(self.aspect > zero(),    "The aspect ratio cannot be below zero, found: {:?}", self.aspect);
        assert!(self.near   > zero(),    "The near plane distance cannot be below zero, found: {:?}", self.near);
        assert!(self.far    > zero(),    "The far plane distance cannot be below zero, found: {:?}", self.far);
        assert!(self.far    > self.near, "The far plane cannot be closer than the near plane, found: far: {:?}, near: {:?}", self.far, self.near);

        let f = cot(self.fovy.div_s(cast(2i8).unwrap()).to_rad());
        let two: S = cast(2i8).unwrap();

        let c0r0 = f / self.aspect;
        let c0r1 = zero();
        let c0r2 = zero();
        let c0r3 = zero();

        let c1r0 = zero();
        let c1r1 = f;
        let c1r2 = zero();
        let c1r3 = zero();

        let c2r0 = zero();
        let c2r1 = zero();
        let c2r2 = (self.far + self.near) / (self.near - self.far);
        let c2r3 = -one::<S>();

        let c3r0 = zero();
        let c3r1 = zero();
        let c3r2 = (two * self.far * self.near) / (self.near - self.far);
        let c3r3 = zero();

        Matrix4::new(c0r0, c0r1, c0r2, c0r3,
                     c1r0, c1r1, c1r2, c1r3,
                     c2r0, c2r1, c2r2, c2r3,
                     c3r0, c3r1, c3r2, c3r3)
    }
}

/// A perspective projection with arbitrary left/right/bottom/top distances
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Perspective<S> {
    pub left:   S,  right:  S,
    pub bottom: S,  top:    S,
    pub near:   S,  far:    S,
}

impl<S: BaseFloat + 'static> Projection<S> for Perspective<S> {
    fn to_frustum(&self) -> Frustum<S> {
        // TODO: Could this be faster?
        Frustum::from_matrix4(self.to_matrix4()).unwrap()
    }
}

impl<S: BaseFloat + 'static> ToMatrix4<S> for Perspective<S> {
    fn to_matrix4(&self) -> Matrix4<S> {
        assert!(self.left   <= self.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", self.left, self.right);
        assert!(self.bottom <= self.top,   "`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}", self.bottom, self.top);
        assert!(self.near   <= self.far,   "`near` cannot be greater than `far`, found: near: {:?} far: {:?}", self.near, self.far);

        let two: S = cast(2i8).unwrap();

        let c0r0 = (two * self.near) / (self.right - self.left);
        let c0r1 = zero();
        let c0r2 = zero();
        let c0r3 = zero();

        let c1r0 = zero();
        let c1r1 = (two * self.near) / (self.top - self.bottom);
        let c1r2 = zero();
        let c1r3 = zero();

        let c2r0 = (self.right + self.left) / (self.right - self.left);
        let c2r1 = (self.top + self.bottom) / (self.top - self.bottom);
        let c2r2 = -(self.far + self.near) / (self.far - self.near);
        let c2r3 = -one::<S>();

        let c3r0 = zero();
        let c3r1 = zero();
        let c3r2 = -(two * self.far * self.near) / (self.far - self.near);
        let c3r3 = zero();

        Matrix4::new(c0r0, c0r1, c0r2, c0r3,
                     c1r0, c1r1, c1r2, c1r3,
                     c2r0, c2r1, c2r2, c2r3,
                     c3r0, c3r1, c3r2, c3r3)
    }
}

/// An orthographic projection with arbitrary left/right/bottom/top distances
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Ortho<S> {
    pub left:   S,  right:  S,
    pub bottom: S,  top:    S,
    pub near:   S,  far:    S,
}

impl<S: BaseFloat> Projection<S> for Ortho<S> {
    fn to_frustum(&self) -> Frustum<S> {
        Frustum {
            left:   Plane::from_abcd( one::<S>(), zero::<S>(), zero::<S>(), self.left.clone()),
            right:  Plane::from_abcd(-one::<S>(), zero::<S>(), zero::<S>(), self.right.clone()),
            bottom: Plane::from_abcd(zero::<S>(),  one::<S>(), zero::<S>(), self.bottom.clone()),
            top:    Plane::from_abcd(zero::<S>(), -one::<S>(), zero::<S>(), self.top.clone()),
            near:   Plane::from_abcd(zero::<S>(), zero::<S>(), -one::<S>(), self.near.clone()),
            far:    Plane::from_abcd(zero::<S>(), zero::<S>(),  one::<S>(), self.far.clone()),
        }
    }
}

impl<S: BaseFloat> ToMatrix4<S> for Ortho<S> {
    fn to_matrix4(&self) -> Matrix4<S> {
        let two: S = cast(2i8).unwrap();

        let c0r0 = two / (self.right - self.left);
        let c0r1 = zero();
        let c0r2 = zero();
        let c0r3 = zero();

        let c1r0 = zero();
        let c1r1 = two / (self.top - self.bottom);
        let c1r2 = zero();
        let c1r3 = zero();

        let c2r0 = zero();
        let c2r1 = zero();
        let c2r2 = -two / (self.far - self.near);
        let c2r3 = zero();

        let c3r0 = -(self.right + self.left) / (self.right - self.left);
        let c3r1 = -(self.top + self.bottom) / (self.top - self.bottom);
        let c3r2 = -(self.far + self.near) / (self.far - self.near);
        let c3r3 = one::<S>();

        Matrix4::new(c0r0, c0r1, c0r2, c0r3,
                     c1r0, c1r1, c1r2, c1r3,
                     c2r0, c2r1, c2r2, c2r3,
                     c3r0, c3r1, c3r2, c3r3)
    }
}
<commit_msg>Exposed Ortho fields as public<commit_after>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::num::cast;

use angle::{Angle, tan, cot};
use frustum::Frustum;
use matrix::{Matrix4, ToMatrix4};
use num::{BaseFloat, zero, one};
use plane::Plane;

/// Create a perspective projection matrix.
///
/// This is the equivalent to the [gluPerspective]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml) function.
pub fn perspective<S: BaseFloat + 'static, A: Angle<S>>(fovy: A, aspect: S, near: S, far: S) -> Matrix4<S> {
    PerspectiveFov {
        fovy:   fovy,
        aspect: aspect,
        near:   near,
        far:    far,
    }.to_matrix4()
}

/// Create a perspective matrix from a view frustrum.
///
/// This is the equivalent of the now deprecated [glFrustrum]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
pub fn frustum<S: BaseFloat + 'static>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Matrix4<S> {
    Perspective {
        left:   left,
        right:  right,
        bottom: bottom,
        top:    top,
        near:   near,
        far:    far,
    }.to_matrix4()
}

/// Create an orthographic projection matrix.
///
/// This is the equivalent of the now deprecated [glOrtho]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
pub fn ortho<S: BaseFloat + 'static>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Matrix4<S> {
    Ortho {
        left:   left,
        right:  right,
        bottom: bottom,
        top:    top,
        near:   near,
        far:    far,
    }.to_matrix4()
}

pub trait Projection<S>: ToMatrix4<S> {
    fn to_frustum(&self) -> Frustum<S>;
}

/// A perspective projection based on a vertical field-of-view angle.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct PerspectiveFov<S, A> {
    pub fovy:   A,
    pub aspect: S,
    pub near:   S,
    pub far:    S,
}

impl<S: BaseFloat, A: Angle<S>> PerspectiveFov<S, A> {
    pub fn to_perspective(&self) -> Perspective<S> {
        let angle = self.fovy.div_s(cast(2i8).unwrap());
        let ymax = self.near * tan(angle.to_rad());
        let xmax = ymax * self.aspect;

        Perspective {
            left:   -xmax,
            right:   xmax,
            bottom: -ymax,
            top:     ymax,
            near:    self.near.clone(),
            far:     self.far.clone(),
        }
    }
}

impl<S: BaseFloat + 'static, A: Angle<S>> Projection<S> for PerspectiveFov<S, A> {
    fn to_frustum(&self) -> Frustum<S> {
        // TODO: Could this be faster?
        Frustum::from_matrix4(self.to_matrix4()).unwrap()
    }
}

impl<S: BaseFloat, A: Angle<S>> ToMatrix4<S> for PerspectiveFov<S, A> {
    fn to_matrix4(&self) -> Matrix4<S> {
        let half_turn: A = Angle::turn_div_2();

        assert!(self.fovy   > zero(),    "The vertical field of view cannot be below zero, found: {:?}", self.fovy);
        assert!(self.fovy   < half_turn, "The vertical field of view cannot be greater than a half turn, found: {:?}", self.fovy);
        assert!(self.aspect > zero(),    "The aspect ratio cannot be below zero, found: {:?}", self.aspect);
        assert!(self.near   > zero(),    "The near plane distance cannot be below zero, found: {:?}", self.near);
        assert!(self.far    > zero(),    "The far plane distance cannot be below zero, found: {:?}", self.far);
        assert!(self.far    > self.near, "The far plane cannot be closer than the near plane, found: far: {:?}, near: {:?}", self.far, self.near);

        let f = cot(self.fovy.div_s(cast(2i8).unwrap()).to_rad());
        let two: S = cast(2i8).unwrap();

        let c0r0 = f / self.aspect;
        let c0r1 = zero();
        let c0r2 = zero();
        let c0r3 = zero();

        let c1r0 = zero();
        let c1r1 = f;
        let c1r2 = zero();
        let c1r3 = zero();

        let c2r0 = zero();
        let c2r1 = zero();
        let c2r2 = (self.far + self.near) / (self.near - self.far);
        let c2r3 = -one::<S>();

        let c3r0 = zero();
        let c3r1 = zero();
        let c3r2 = (two * self.far * self.near) / (self.near - self.far);
        let c3r3 = zero();

        Matrix4::new(c0r0, c0r1, c0r2, c0r3,
                     c1r0, c1r1, c1r2, c1r3,
                     c2r0, c2r1, c2r2, c2r3,
                     c3r0, c3r1, c3r2, c3r3)
    }
}

/// A perspective projection with arbitrary left/right/bottom/top distances
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Perspective<S> {
    pub left:   S,
    pub right:  S,
    pub bottom: S,
    pub top:    S,
    pub near:   S,
    pub far:    S,
}

impl<S: BaseFloat + 'static> Projection<S> for Perspective<S> {
    fn to_frustum(&self) -> Frustum<S> {
        // TODO: Could this be faster?
        Frustum::from_matrix4(self.to_matrix4()).unwrap()
    }
}

impl<S: BaseFloat + 'static> ToMatrix4<S> for Perspective<S> {
    fn to_matrix4(&self) -> Matrix4<S> {
        assert!(self.left   <= self.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", self.left, self.right);
        assert!(self.bottom <= self.top,   "`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}", self.bottom, self.top);
        assert!(self.near   <= self.far,   "`near` cannot be greater than `far`, found: near: {:?} far: {:?}", self.near, self.far);

        let two: S = cast(2i8).unwrap();

        let c0r0 = (two * self.near) / (self.right - self.left);
        let c0r1 = zero();
        let c0r2 = zero();
        let c0r3 = zero();

        let c1r0 = zero();
        let c1r1 = (two * self.near) / (self.top - self.bottom);
        let c1r2 = zero();
        let c1r3 = zero();

        let c2r0 = (self.right + self.left) / (self.right - self.left);
        let c2r1 = (self.top + self.bottom) / (self.top - self.bottom);
        let c2r2 = -(self.far + self.near) / (self.far - self.near);
        let c2r3 = -one::<S>();

        let c3r0 = zero();
        let c3r1 = zero();
        let c3r2 = -(two * self.far * self.near) / (self.far - self.near);
        let c3r3 = zero();

        Matrix4::new(c0r0, c0r1, c0r2, c0r3,
                     c1r0, c1r1, c1r2, c1r3,
                     c2r0, c2r1, c2r2, c2r3,
                     c3r0, c3r1, c3r2, c3r3)
    }
}

/// An orthographic projection with arbitrary left/right/bottom/top distances
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Ortho<S> {
    pub left:   S,  right:  S,
    pub bottom: S,  top:    S,
    pub near:   S,  far:    S,
}

impl<S: BaseFloat> Projection<S> for Ortho<S> {
    fn to_frustum(&self) -> Frustum<S> {
        Frustum {
            left:   Plane::from_abcd( one::<S>(), zero::<S>(), zero::<S>(), self.left.clone()),
            right:  Plane::from_abcd(-one::<S>(), zero::<S>(), zero::<S>(), self.right.clone()),
            bottom: Plane::from_abcd(zero::<S>(),  one::<S>(), zero::<S>(), self.bottom.clone()),
            top:    Plane::from_abcd(zero::<S>(), -one::<S>(), zero::<S>(), self.top.clone()),
            near:   Plane::from_abcd(zero::<S>(), zero::<S>(), -one::<S>(), self.near.clone()),
            far:    Plane::from_abcd(zero::<S>(), zero::<S>(),  one::<S>(), self.far.clone()),
        }
    }
}

impl<S: BaseFloat> ToMatrix4<S> for Ortho<S> {
    fn to_matrix4(&self) -> Matrix4<S> {
        let two: S = cast(2i8).unwrap();

        let c0r0 = two / (self.right - self.left);
        let c0r1 = zero();
        let c0r2 = zero();
        let c0r3 = zero();

        let c1r0 = zero();
        let c1r1 = two / (self.top - self.bottom);
        let c1r2 = zero();
        let c1r3 = zero();

        let c2r0 = zero();
        let c2r1 = zero();
        let c2r2 = -two / (self.far - self.near);
        let c2r3 = zero();

        let c3r0 = -(self.right + self.left) / (self.right - self.left);
        let c3r1 = -(self.top + self.bottom) / (self.top - self.bottom);
        let c3r2 = -(self.far + self.near) / (self.far - self.near);
        let c3r3 = one::<S>();

        Matrix4::new(c0r0, c0r1, c0r2, c0r3,
                     c1r0, c1r1, c1r2, c1r3,
                     c2r0, c2r1, c2r2, c2r3,
                     c3r0, c3r1, c3r2, c3r3)
    }
}
<|endoftext|>


<commit_before>extern crate osmpbfreader;
use std::collections::HashMap;
use models::*;
use categorize::*;
use std;

// Way as represented in OpenStreetMap
struct Way {
    id: i64,
    nodes: Vec<i64>,
    properties: EdgeProperties,
}

struct Reader {
    nodes: HashMap<i64, Node>,
    ways: Vec<Way>,
}

impl Reader {
    fn new() -> Reader {
        Reader {
            nodes: HashMap::new(),
            ways: Vec::new(),
        }
    }

    fn count_nodes_uses(&mut self) {
        for way in &self.ways {
            for (i, node_id) in way.nodes.iter().enumerate() {
                if let Some(node) = self.nodes.get_mut(node_id) {
                    // Count double extremities nodes
                    if i == 0 || i == way.nodes.len() - 1 {
                        node.uses += 2;
                    } else {
                        node.uses += 1;
                    }
                } else {
                    panic!("Missing node, id: {}", node_id)
                }
            }
        }
    }

    fn split_way(&self, way: &Way) -> Vec<Edge> {
        let mut result = Vec::new();

        let mut source = 0;
        let mut geometry = Vec::new();
        for (i, &node_id) in way.nodes.iter().enumerate() {
            let node = self.nodes[&node_id];
            if i == 0 {
                source = node_id;
                geometry.push(node.coord);
            } else {
                geometry.push(node.coord);

                if node.uses > 1 {
                    result.push(Edge {
                        id: way.id,
                        source: source,
                        target: node_id,
                        geometry: geometry,
                        properties: way.properties,
                    });

                    source = node_id;
                    geometry = vec![node.coord];
                }
            }
        }
        result
    }

    fn read(&mut self, filename: &str) -> Result<(), String> {
        let path = std::path::Path::new(filename);
        let r = try!(std::fs::File::open(&path).map_err(|e| e.to_string()));
        let mut pbf = osmpbfreader::OsmPbfReader::new(r);
        for obj in pbf.iter() {
            match obj {
                osmpbfreader::OsmObj::Node(node) => {
                    let mut n = Node::new();
                    n.id = node.id;
                    n.coord = Coord {
                        lon: node.lon,
                        lat: node.lat,
                    };
                    self.nodes.insert(node.id, n);
                }
                osmpbfreader::OsmObj::Way(way) => {
                    let mut properties = EdgeProperties::new();
                    for (key, val) in way.tags {
                        properties.update(key, val);
                    }
                    properties.normalize();
                    if properties.accessible() {
                        self.ways.push(Way {
                            id: way.id,
                            nodes: way.nodes,
                            properties: properties,
                        })
                    }
                }
                osmpbfreader::OsmObj::Relation(_) => {}
            }
        }
        Ok(())
    }

    fn nodes(&self) -> Vec<Node> {
        self.nodes
            .iter()
            .map(|(_, node)| node)
            .filter(|node| node.uses > 1)
            .map(|n| n.clone())
            .collect()
    }

    fn edges(&self) -> Vec<Edge> {
        self.ways.iter().flat_map(|way| self.split_way(way)).collect()
    }
}

// Read all the nodes and ways of the osm.pbf file
pub fn read(filename: &str) -> Result<(Vec<Node>, Vec<Edge>), String> {
    let mut r = Reader::new();
    try!(r.read(filename));
    r.count_nodes_uses();
    Ok((r.nodes(), r.edges()))
}

#[test]
fn test_real_all() {
    let (nodes, ways) = read("src/osm4routing/test_data/minimal.osm.pbf");
    assert_eq!(2, nodes.len());
    assert_eq!(1, ways.len());
}

#[test]
fn test_count_nodes() {
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    }];
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    let mut r = Reader {
        ways: ways,
        nodes: nodes,
    };
    r.count_nodes_uses();
    assert_eq!(2, r.nodes[&1].uses);
    assert_eq!(1, r.nodes[&2].uses);
    assert_eq!(2, r.nodes[&3].uses);

    assert_eq!(2, r.nodes().len());
}

#[test]
fn test_split() {
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    nodes.insert(4, Node::new());
    nodes.insert(5, Node::new());
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    },
                    Way {
                        id: 0,
                        nodes: vec![4, 5, 2],
                        properties: EdgeProperties::new(),
                    }];
    let mut r = Reader {
        nodes: nodes,
        ways: ways,
    };
    r.count_nodes_uses();
    let edges = r.edges();
    assert_eq!(3, edges.len());
}

#[test]
#[should_panic]
fn test_wrong_file() {
    read("i hope you have no file name like this one");
}
<commit_msg>consume the nodes not to copy them all<commit_after>extern crate osmpbfreader;
use std::collections::HashMap;
use models::*;
use categorize::*;
use std;

// Way as represented in OpenStreetMap
struct Way {
    id: i64,
    nodes: Vec<i64>,
    properties: EdgeProperties,
}

struct Reader {
    nodes: HashMap<i64, Node>,
    ways: Vec<Way>,
}

impl Reader {
    fn new() -> Reader {
        Reader {
            nodes: HashMap::new(),
            ways: Vec::new(),
        }
    }

    fn count_nodes_uses(&mut self) {
        for way in &self.ways {
            for (i, node_id) in way.nodes.iter().enumerate() {
                if let Some(node) = self.nodes.get_mut(node_id) {
                    // Count double extremities nodes
                    if i == 0 || i == way.nodes.len() - 1 {
                        node.uses += 2;
                    } else {
                        node.uses += 1;
                    }
                } else {
                    panic!("Missing node, id: {}", node_id)
                }
            }
        }
    }

    fn split_way(&self, way: &Way) -> Vec<Edge> {
        let mut result = Vec::new();

        let mut source = 0;
        let mut geometry = Vec::new();
        for (i, &node_id) in way.nodes.iter().enumerate() {
            let node = self.nodes[&node_id];
            if i == 0 {
                source = node_id;
                geometry.push(node.coord);
            } else {
                geometry.push(node.coord);

                if node.uses > 1 {
                    result.push(Edge {
                        id: way.id,
                        source: source,
                        target: node_id,
                        geometry: geometry,
                        properties: way.properties,
                    });

                    source = node_id;
                    geometry = vec![node.coord];
                }
            }
        }
        result
    }

    fn read(&mut self, filename: &str) -> Result<(), String> {
        let path = std::path::Path::new(filename);
        let r = try!(std::fs::File::open(&path).map_err(|e| e.to_string()));
        let mut pbf = osmpbfreader::OsmPbfReader::new(r);
        for obj in pbf.iter() {
            match obj {
                osmpbfreader::OsmObj::Node(node) => {
                    let mut n = Node::new();
                    n.id = node.id;
                    n.coord = Coord {
                        lon: node.lon,
                        lat: node.lat,
                    };
                    self.nodes.insert(node.id, n);
                }
                osmpbfreader::OsmObj::Way(way) => {
                    let mut properties = EdgeProperties::new();
                    for (key, val) in way.tags {
                        properties.update(key, val);
                    }
                    properties.normalize();
                    if properties.accessible() {
                        self.ways.push(Way {
                            id: way.id,
                            nodes: way.nodes,
                            properties: properties,
                        })
                    }
                }
                osmpbfreader::OsmObj::Relation(_) => {}
            }
        }
        Ok(())
    }

    fn nodes(self) -> Vec<Node> {
        self.nodes
            .into_iter()
            .map(|(_, node)| node)
            .filter(|node| node.uses > 1)
            .collect()
    }

    fn edges(&self) -> Vec<Edge> {
        self.ways.iter().flat_map(|way| self.split_way(way)).collect()
    }
}

// Read all the nodes and ways of the osm.pbf file
pub fn read(filename: &str) -> Result<(Vec<Node>, Vec<Edge>), String> {
    let mut r = Reader::new();
    try!(r.read(filename));
    r.count_nodes_uses();
    let edges = r.edges();
    Ok((r.nodes(), edges)
}

#[test]
fn test_real_all() {
    let (nodes, ways) = read("src/osm4routing/test_data/minimal.osm.pbf");
    assert_eq!(2, nodes.len());
    assert_eq!(1, ways.len());
}

#[test]
fn test_count_nodes() {
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    }];
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    let mut r = Reader {
        ways: ways,
        nodes: nodes,
    };
    r.count_nodes_uses();
    assert_eq!(2, r.nodes[&1].uses);
    assert_eq!(1, r.nodes[&2].uses);
    assert_eq!(2, r.nodes[&3].uses);

    assert_eq!(2, r.nodes().len());
}

#[test]
fn test_split() {
    let mut nodes = HashMap::new();
    nodes.insert(1, Node::new());
    nodes.insert(2, Node::new());
    nodes.insert(3, Node::new());
    nodes.insert(4, Node::new());
    nodes.insert(5, Node::new());
    let ways = vec![Way {
                        id: 0,
                        nodes: vec![1, 2, 3],
                        properties: EdgeProperties::new(),
                    },
                    Way {
                        id: 0,
                        nodes: vec![4, 5, 2],
                        properties: EdgeProperties::new(),
                    }];
    let mut r = Reader {
        nodes: nodes,
        ways: ways,
    };
    r.count_nodes_uses();
    let edges = r.edges();
    assert_eq!(3, edges.len());
}

#[test]
#[should_panic]
fn test_wrong_file() {
    read("i hope you have no file name like this one");
}
<|endoftext|>


<commit_before>use std::{fs, io, path};

use syntax::{ast, visit, codemap};

use tree::{Tree, Visibility};

pub struct Config {
    pub include_orphans: bool,
    pub ignored_files: Vec<path::PathBuf>,
}

pub struct Builder<'a> {
    tree: Tree,
    path: Vec<String>,
    config: Config,
    codemap: &'a codemap::CodeMap,
}

impl<'a> Builder<'a> {
    pub fn new(config: Config, crate_name: String, codemap: &'a codemap::CodeMap) -> Self {
        let tree = Tree::new_crate(crate_name);
        Builder {
            tree: tree,
            path: vec![],
            config: config,
            codemap: codemap,
        }
    }

    pub fn tree(&self) -> &Tree {
        &self.tree
    }

    fn find_orphan_candidates(path: &[String],
                              ignored_paths: &[path::PathBuf])
                              -> Result<Vec<String>, io::Error> {
        let mut dir_path = "./src/".to_string();
        for name in path.iter() {
            dir_path.push_str(name);
            dir_path.push_str("/");
        }
        fn is_mod(entry: &fs::DirEntry) -> bool {
            let path = entry.path();
            if path.is_file() {
                if path.extension().map_or(false, |ext| ext == "rs") {
                    return file_name(entry)
                        .map_or(false, |s| (s != "mod") && (s != "lib") && (s != "main"));
                }
            } else if path.join("mod.rs").exists() {
                return true;
            }
            false
        }
        fn file_name(entry: &fs::DirEntry) -> Option<String> {
            entry.path().file_stem().map_or(None, |s| s.to_str().map(|s| s.to_string()))
        }
        Ok(try!(fs::read_dir(&dir_path))
            .filter_map(|e| e.ok())
            .filter(is_mod)
            .filter(|e| !ignored_paths.contains(&e.path()))
            .filter_map(|e| file_name(&e))
            .collect::<Vec<_>>())
    }

    fn sanitize_condition(condition: String) -> String {
        let words: Vec<&str> = condition.split_whitespace().collect();
        words.join(" ")
    }
}

impl<'a> visit::Visitor<'a> for Builder<'a> {
    fn visit_item(&mut self, item: &'a ast::Item) {
        let condition = item.attrs
            .iter()
            .find(|attr| attr.check_name("cfg"))
            .map(|attr| {
                self.codemap
                    .span_to_snippet(attr.span)
                    .map(Builder::sanitize_condition)
                    .unwrap_or_else(|_| "".to_string())
            });
        if let ast::ItemKind::Mod(_) = item.node {
            let name = item.ident.to_string();
            {
                let tree = self.tree.subtree_at_path(&self.path).unwrap();
                let visibility = if item.vis == ast::Visibility::Public {
                    Visibility::Public
                } else {
                    Visibility::Private
                };
                tree.insert(Tree::new_module(name.clone(), visibility, condition));
            }
            self.path.push(name);
            visit::walk_item(self, item);
            let _ = self.path.pop();
        } else {
            visit::walk_item(self, item);
        }
    }

    fn visit_mod(&mut self, m: &'a ast::Mod, _s: codemap::Span, _attrs: &[ast::Attribute],
_n: ast::NodeId) {
        visit::walk_mod(self, m);
        if !self.config.include_orphans {
            return;
        }
        let path = &self.path;
        if let Ok(candidates) = Builder::find_orphan_candidates(path, &self.config.ignored_files) {
            let tree = self.tree.subtree_at_path(path).unwrap();
            let names: Vec<_> = tree.subtree_names();
            for candidate in candidates {
                if !names.contains(&candidate) {
                    tree.insert(Tree::new_orphan(candidate.clone()));
                }
            }
        }
    }

    fn visit_mac(&mut self, mac: &ast::Mac) {
        visit::walk_mac(self, mac);
    }
}
<commit_msg>Fix for latest libsyntax<commit_after>use std::{fs, io, path};

use syntax::{ast, visit, codemap};

use tree::{Tree, Visibility};

pub struct Config {
    pub include_orphans: bool,
    pub ignored_files: Vec<path::PathBuf>,
}

pub struct Builder<'a> {
    tree: Tree,
    path: Vec<String>,
    config: Config,
    codemap: &'a codemap::CodeMap,
}

impl<'a> Builder<'a> {
    pub fn new(config: Config, crate_name: String, codemap: &'a codemap::CodeMap) -> Self {
        let tree = Tree::new_crate(crate_name);
        Builder {
            tree: tree,
            path: vec![],
            config: config,
            codemap: codemap,
        }
    }

    pub fn tree(&self) -> &Tree {
        &self.tree
    }

    fn find_orphan_candidates(path: &[String],
                              ignored_paths: &[path::PathBuf])
                              -> Result<Vec<String>, io::Error> {
        let mut dir_path = "./src/".to_string();
        for name in path.iter() {
            dir_path.push_str(name);
            dir_path.push_str("/");
        }
        fn is_mod(entry: &fs::DirEntry) -> bool {
            let path = entry.path();
            if path.is_file() {
                if path.extension().map_or(false, |ext| ext == "rs") {
                    return file_name(entry)
                        .map_or(false, |s| (s != "mod") && (s != "lib") && (s != "main"));
                }
            } else if path.join("mod.rs").exists() {
                return true;
            }
            false
        }
        fn file_name(entry: &fs::DirEntry) -> Option<String> {
            entry.path().file_stem().map_or(None, |s| s.to_str().map(|s| s.to_string()))
        }
        Ok(try!(fs::read_dir(&dir_path))
            .filter_map(|e| e.ok())
            .filter(is_mod)
            .filter(|e| !ignored_paths.contains(&e.path()))
            .filter_map(|e| file_name(&e))
            .collect::<Vec<_>>())
    }

    fn sanitize_condition(condition: String) -> String {
        let words: Vec<&str> = condition.split_whitespace().collect();
        words.join(" ")
    }
}

impl<'a> visit::Visitor<'a> for Builder<'a> {
    fn visit_item(&mut self, item: &'a ast::Item) {
        let condition = item.attrs
            .iter()
            .find(|attr| attr.check_name("cfg"))
            .map(|attr| {
                self.codemap
                    .span_to_snippet(attr.span)
                    .map(Builder::sanitize_condition)
                    .unwrap_or_else(|_| "".to_string())
            });
        if let ast::ItemKind::Mod(_) = item.node {
            let name = item.ident.to_string();
            {
                let tree = self.tree.subtree_at_path(&self.path).unwrap();
                let visibility = if item.vis.node == ast::VisibilityKind::Public {
                    Visibility::Public
                } else {
                    Visibility::Private
                };
                tree.insert(Tree::new_module(name.clone(), visibility, condition));
            }
            self.path.push(name);
            visit::walk_item(self, item);
            let _ = self.path.pop();
        } else {
            visit::walk_item(self, item);
        }
    }

    fn visit_mod(&mut self, m: &'a ast::Mod, _s: codemap::Span, _attrs: &[ast::Attribute],
_n: ast::NodeId) {
        visit::walk_mod(self, m);
        if !self.config.include_orphans {
            return;
        }
        let path = &self.path;
        if let Ok(candidates) = Builder::find_orphan_candidates(path, &self.config.ignored_files) {
            let tree = self.tree.subtree_at_path(path).unwrap();
            let names: Vec<_> = tree.subtree_names();
            for candidate in candidates {
                if !names.contains(&candidate) {
                    tree.insert(Tree::new_orphan(candidate.clone()));
                }
            }
        }
    }

    fn visit_mac(&mut self, mac: &ast::Mac) {
        visit::walk_mac(self, mac);
    }
}
<|endoftext|>


<commit_before><commit_msg>Auto merge of #1563 - nical:min-max-texture-size, r=kvark,glennw<commit_after><|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    auth::with_auth,
    clients::humio::{CHAIN_ID_TAG_NAME, EPOCH_FIELD_NAME, PEER_ID_FIELD_NAME, PEER_ROLE_TAG_NAME},
    constants::MAX_CONTENT_LENGTH,
    context::Context,
    errors::{LogIngestError, ServiceError},
    metrics::LOG_INGEST_BACKEND_REQUEST_DURATION,
    types::{auth::Claims, common::NodeType, humio::UnstructuredLog},
};
use crate::{debug, error};
use flate2::bufread::GzDecoder;
use reqwest::{header::CONTENT_ENCODING, StatusCode};
use std::collections::HashMap;
use tokio::time::Instant;
use warp::{filters::BoxedFilter, reject, reply, Buf, Filter, Rejection, Reply};

/// TODO: Cleanup after v1 API is ramped up
pub fn log_ingest_legacy(context: Context) -> BoxedFilter<(impl Reply,)> {
    warp::path!("log_ingest")
        .and(warp::post())
        .and(context.clone().filter())
        .and(with_auth(
            context,
            vec![
                NodeType::Validator,
                NodeType::ValidatorFullNode,
                NodeType::PublicFullNode,
            ],
        ))
        .and(warp::header::optional(CONTENT_ENCODING.as_str()))
        .and(warp::body::content_length_limit(MAX_CONTENT_LENGTH))
        .and(warp::body::aggregate())
        .and_then(handle_log_ingest)
        .boxed()
}

pub fn log_ingest(context: Context) -> BoxedFilter<(impl Reply,)> {
    warp::path!("ingest" / "logs")
        .and(warp::post())
        .and(context.clone().filter())
        .and(with_auth(
            context,
            vec![
                NodeType::Validator,
                NodeType::ValidatorFullNode,
                NodeType::PublicFullNode,
            ],
        ))
        .and(warp::header::optional(CONTENT_ENCODING.as_str()))
        .and(warp::body::content_length_limit(MAX_CONTENT_LENGTH))
        .and(warp::body::aggregate())
        .and_then(handle_log_ingest)
        .boxed()
}

pub async fn handle_log_ingest(
    context: Context,
    claims: Claims,
    encoding: Option<String>,
    body: impl Buf,
) -> anyhow::Result<impl Reply, Rejection> {
    debug!("handling log ingest");

    let log_messages: Vec<String> = if let Some(encoding) = encoding {
        if encoding.eq_ignore_ascii_case("gzip") {
            let decoder = GzDecoder::new(body.reader());
            serde_json::from_reader(decoder).map_err(|e| {
                debug!("unable to decode and deserialize body: {}", e);
                ServiceError::bad_request(LogIngestError::UnexpectedPayloadBody.into())
            })?
        } else {
            return Err(reject::custom(ServiceError::bad_request(
                LogIngestError::UnexpectedContentEncoding.into(),
            )));
        }
    } else {
        serde_json::from_reader(body.reader()).map_err(|e| {
            error!("unable to deserialize body: {}", e);
            ServiceError::bad_request(LogIngestError::UnexpectedPayloadBody.into())
        })?
    };

    let mut fields = HashMap::new();
    fields.insert(PEER_ID_FIELD_NAME.into(), claims.peer_id.to_string());
    fields.insert(EPOCH_FIELD_NAME.into(), claims.epoch.to_string());

    let mut tags = HashMap::new();
    tags.insert(CHAIN_ID_TAG_NAME.into(), claims.chain_id.to_string());
    tags.insert(PEER_ROLE_TAG_NAME.into(), claims.node_type.to_string());

    let unstructured_log = UnstructuredLog {
        fields,
        tags,
        messages: log_messages,
    };

    debug!("ingesting to humio: {:?}", unstructured_log);

    let start_timer = Instant::now();

    let res = context
        .humio_client()
        .ingest_unstructured_log(unstructured_log)
        .await;

    match res {
        Ok(res) => {
            LOG_INGEST_BACKEND_REQUEST_DURATION
                .with_label_values(&[res.status().as_str()])
                .observe(start_timer.elapsed().as_secs_f64());
            if res.status().is_success() {
                debug!("log ingested into humio succeessfully");
            } else {
                error!(
                    "humio log ingestion failed: {}",
                    res.error_for_status().err().unwrap()
                );
                return Err(reject::custom(ServiceError::bad_request(
                    LogIngestError::IngestionError.into(),
                )));
            }
        }
        Err(err) => {
            LOG_INGEST_BACKEND_REQUEST_DURATION
                .with_label_values(&["Unknown"])
                .observe(start_timer.elapsed().as_secs_f64());
            error!("error sending log ingest request: {}", err);
            return Err(reject::custom(ServiceError::bad_request(
                LogIngestError::IngestionError.into(),
            )));
        }
    }

    Ok(reply::with_status(reply::reply(), StatusCode::CREATED))
}
<commit_msg>[telemetry-service] fix log tag for chain ID 3<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    auth::with_auth,
    clients::humio::{CHAIN_ID_TAG_NAME, EPOCH_FIELD_NAME, PEER_ID_FIELD_NAME, PEER_ROLE_TAG_NAME},
    constants::MAX_CONTENT_LENGTH,
    context::Context,
    errors::{LogIngestError, ServiceError},
    metrics::LOG_INGEST_BACKEND_REQUEST_DURATION,
    types::{auth::Claims, common::NodeType, humio::UnstructuredLog},
};
use crate::{debug, error};
use flate2::bufread::GzDecoder;
use reqwest::{header::CONTENT_ENCODING, StatusCode};
use std::collections::HashMap;
use tokio::time::Instant;
use warp::{filters::BoxedFilter, reject, reply, Buf, Filter, Rejection, Reply};

/// TODO: Cleanup after v1 API is ramped up
pub fn log_ingest_legacy(context: Context) -> BoxedFilter<(impl Reply,)> {
    warp::path!("log_ingest")
        .and(warp::post())
        .and(context.clone().filter())
        .and(with_auth(
            context,
            vec![
                NodeType::Validator,
                NodeType::ValidatorFullNode,
                NodeType::PublicFullNode,
            ],
        ))
        .and(warp::header::optional(CONTENT_ENCODING.as_str()))
        .and(warp::body::content_length_limit(MAX_CONTENT_LENGTH))
        .and(warp::body::aggregate())
        .and_then(handle_log_ingest)
        .boxed()
}

pub fn log_ingest(context: Context) -> BoxedFilter<(impl Reply,)> {
    warp::path!("ingest" / "logs")
        .and(warp::post())
        .and(context.clone().filter())
        .and(with_auth(
            context,
            vec![
                NodeType::Validator,
                NodeType::ValidatorFullNode,
                NodeType::PublicFullNode,
            ],
        ))
        .and(warp::header::optional(CONTENT_ENCODING.as_str()))
        .and(warp::body::content_length_limit(MAX_CONTENT_LENGTH))
        .and(warp::body::aggregate())
        .and_then(handle_log_ingest)
        .boxed()
}

pub async fn handle_log_ingest(
    context: Context,
    claims: Claims,
    encoding: Option<String>,
    body: impl Buf,
) -> anyhow::Result<impl Reply, Rejection> {
    debug!("handling log ingest");

    let log_messages: Vec<String> = if let Some(encoding) = encoding {
        if encoding.eq_ignore_ascii_case("gzip") {
            let decoder = GzDecoder::new(body.reader());
            serde_json::from_reader(decoder).map_err(|e| {
                debug!("unable to decode and deserialize body: {}", e);
                ServiceError::bad_request(LogIngestError::UnexpectedPayloadBody.into())
            })?
        } else {
            return Err(reject::custom(ServiceError::bad_request(
                LogIngestError::UnexpectedContentEncoding.into(),
            )));
        }
    } else {
        serde_json::from_reader(body.reader()).map_err(|e| {
            error!("unable to deserialize body: {}", e);
            ServiceError::bad_request(LogIngestError::UnexpectedPayloadBody.into())
        })?
    };

    let mut fields = HashMap::new();
    fields.insert(PEER_ID_FIELD_NAME.into(), claims.peer_id.to_string());
    fields.insert(EPOCH_FIELD_NAME.into(), claims.epoch.to_string());

    let mut tags = HashMap::new();
    let chain_name = if claims.chain_id.id() == 3 {
        format!("{}", claims.chain_id.id())
    } else {
        format!("{}", claims.chain_id)
    };
    tags.insert(CHAIN_ID_TAG_NAME.into(), chain_name);
    tags.insert(PEER_ROLE_TAG_NAME.into(), claims.node_type.to_string());

    let unstructured_log = UnstructuredLog {
        fields,
        tags,
        messages: log_messages,
    };

    debug!("ingesting to humio: {:?}", unstructured_log);

    let start_timer = Instant::now();

    let res = context
        .humio_client()
        .ingest_unstructured_log(unstructured_log)
        .await;

    match res {
        Ok(res) => {
            LOG_INGEST_BACKEND_REQUEST_DURATION
                .with_label_values(&[res.status().as_str()])
                .observe(start_timer.elapsed().as_secs_f64());
            if res.status().is_success() {
                debug!("log ingested into humio succeessfully");
            } else {
                error!(
                    "humio log ingestion failed: {}",
                    res.error_for_status().err().unwrap()
                );
                return Err(reject::custom(ServiceError::bad_request(
                    LogIngestError::IngestionError.into(),
                )));
            }
        }
        Err(err) => {
            LOG_INGEST_BACKEND_REQUEST_DURATION
                .with_label_values(&["Unknown"])
                .observe(start_timer.elapsed().as_secs_f64());
            error!("error sending log ingest request: {}", err);
            return Err(reject::custom(ServiceError::bad_request(
                LogIngestError::IngestionError.into(),
            )));
        }
    }

    Ok(reply::with_status(reply::reply(), StatusCode::CREATED))
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use crate::completion::{CompletionContext, Completions};

/// Completes constats and paths in patterns.
pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
    if !ctx.is_pat_binding_or_const {
        return;
    }
    if ctx.record_pat_syntax.is_some() {
        return;
    }

    // FIXME: ideally, we should look at the type we are matching against and
    // suggest variants + auto-imports
    ctx.scope().process_all_names(&mut |name, res| {
        match &res {
            hir::ScopeDef::ModuleDef(def) => match def {
                hir::ModuleDef::Adt(hir::Adt::Enum(..))
                | hir::ModuleDef::Adt(hir::Adt::Struct(..))
                | hir::ModuleDef::EnumVariant(..)
                | hir::ModuleDef::Const(..)
                | hir::ModuleDef::Module(..) => (),
                _ => return,
            },
            hir::ScopeDef::MacroDef(_) => (),
            _ => return,
        };

        acc.add_resolution(ctx, name.to_string(), &res)
    });
}

#[cfg(test)]
mod tests {
    use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Reference)
    }

    #[test]
    fn completes_enum_variants_and_modules() {
        let completions = complete(
            r"
            enum E { X }
            use self::E::X;
            const Z: E = E::X;
            mod m {}

            static FOO: E = E::X;
            struct Bar { f: u32 }

            fn foo() {
               match E::X {
                   <|>
               }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "Bar",
                source_range: 137..137,
                delete: 137..137,
                insert: "Bar",
                kind: Struct,
            },
            CompletionItem {
                label: "E",
                source_range: 137..137,
                delete: 137..137,
                insert: "E",
                kind: Enum,
            },
            CompletionItem {
                label: "X",
                source_range: 137..137,
                delete: 137..137,
                insert: "X",
                kind: EnumVariant,
                detail: "()",
            },
            CompletionItem {
                label: "Z",
                source_range: 137..137,
                delete: 137..137,
                insert: "Z",
                kind: Const,
            },
            CompletionItem {
                label: "m",
                source_range: 137..137,
                delete: 137..137,
                insert: "m",
                kind: Module,
            },
        ]
        "###);
    }

    #[test]
    fn completes_in_simple_macro_call() {
        let completions = complete(
            r"
            macro_rules! m { ($e:expr) => { $e } }
            enum E { X }

            fn foo() {
               m!(match E::X {
                   <|>
               })
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "E",
                source_range: 90..90,
                delete: 90..90,
                insert: "E",
                kind: Enum,
            },
            CompletionItem {
                label: "m!(…)",
                source_range: 90..90,
                delete: 90..90,
                insert: "m!($0)",
                kind: Macro,
                lookup: "m!",
                detail: "macro_rules! m",
            },
        ]
        "###);
    }
}
<commit_msg>Modernize pattern completion tests<commit_after>//! FIXME: write short doc here

use crate::completion::{CompletionContext, Completions};

/// Completes constats and paths in patterns.
pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
    if !ctx.is_pat_binding_or_const {
        return;
    }
    if ctx.record_pat_syntax.is_some() {
        return;
    }

    // FIXME: ideally, we should look at the type we are matching against and
    // suggest variants + auto-imports
    ctx.scope().process_all_names(&mut |name, res| {
        match &res {
            hir::ScopeDef::ModuleDef(def) => match def {
                hir::ModuleDef::Adt(hir::Adt::Enum(..))
                | hir::ModuleDef::Adt(hir::Adt::Struct(..))
                | hir::ModuleDef::EnumVariant(..)
                | hir::ModuleDef::Const(..)
                | hir::ModuleDef::Module(..) => (),
                _ => return,
            },
            hir::ScopeDef::MacroDef(_) => (),
            _ => return,
        };

        acc.add_resolution(ctx, name.to_string(), &res)
    });
}

#[cfg(test)]
mod tests {
    use expect::{expect, Expect};

    use crate::completion::{test_utils::completion_list, CompletionKind};

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = completion_list(ra_fixture, CompletionKind::Reference);
        expect.assert_eq(&actual)
    }

    #[test]
    fn completes_enum_variants_and_modules() {
        check(
            r#"
enum E { X }
use self::E::X;
const Z: E = E::X;
mod m {}

static FOO: E = E::X;
struct Bar { f: u32 }

fn foo() {
   match E::X { <|> }
}
"#,
            expect![[r#"
                st Bar
                en E
                ev X ()
                ct Z
                md m
            "#]],
        );
    }

    #[test]
    fn completes_in_simple_macro_call() {
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
enum E { X }

fn foo() {
   m!(match E::X { <|> })
}
"#,
            expect![[r#"
                en E
                ma m!(…) macro_rules! m
            "#]],
        );
    }
}
<|endoftext|>


<commit_before>fn main() {
    // PARAMETERS
    let context_lines = 2;
    let needle = "oo";
    let haystack = "Every face, every shop,
    bedroom window, public-house, and
    dark square is a picture
    feverishly turned--in search of what?
    It is the same with books.
    what do we seek
    through millions of pages?";

    // INITIALIZATINO
    let mut tags: Vec<usize> = Vec::new();
    let mut ctx: Vec<Vec<(usize, String)>> = Vec::new();

    // PASS 1
    for (i, line) in haystack.lines().enumerate() {
        if line.contains(needle) {
            tags.push(i);

            let v = Vec::with_capacity(2*context_lines + 1);
            ctx.push(v)
        }
    }

    if tags.len() == 0 {
        return;
    }

    // PASS 2
    for (i, line) in haystack.lines().enumerate() {
        for (j, tag) in tags.iter().enumerate() {
            let lower_bound = tag.saturating_sub(context_lines);
            let upper_bound = tag + context_lines;

            if (i >= lower_bound) && (i <= upper_bound) {
                let line_as_string = String::from(line);
                let local_ctx = (i, line_as_string);
                ctx[j].push(local_ctx);
            }
        }
    }

    // OUTPUT
    for local_ctx in ctx.iter() {
        for &(i, ref line) in local_ctx.iter() {
            let line_num = i + 1;
            println!("{}: {}", line_num, line);
        }
    }
}
<commit_msg>bringing in grep lite from previous project<commit_after>fn main() {
    // PARAMETERS
    let context_lines = 2;
    let needle = "oo";
    let haystack = "Every face, every shop,
    bedroom window, public-house, and
    dark square is a picture
    feverishly turned--in search of what?
    It is the same with books.
    what do we seek
    through millions of pages?";

    // INITIALIZATINO
    let mut tags: Vec<usize> = Vec::new();
    let mut ctx: Vec<Vec<(usize, String)>> = Vec::new();

    // PASS 1
    for (i, line) in haystack.lines().enumerate() {
        if line.contains(needle) {
            tags.push(i);

            let v = Vec::with_capacity(2*context_lines + 1);
            ctx.push(v)
        }
    }

    if tags.len() == 0 {
        return;
    }

    // PASS 2
    for (i, line) in haystack.lines().enumerate() {
        for (j, tag) in tags.iter().enumerate() {
            let lower_bound = tag.saturating_sub(context_lines);
            let upper_bound = tag + context_lines;

            if (i >= lower_bound) && (i <= upper_bound) {
                let line_as_string = String::from(line);
                let local_ctx = (i, line_as_string);
                ctx[j].push(local_ctx);
            }
        }
    }

    // OUTPUT
    for local_ctx in ctx.iter() {
        for &(i, ref line) in local_ctx.iter() {
            let line_num = i + 1;
            println!("{}: {}", line_num, line);
        }
    }
    println!();

    let search_term = "picture";
    let quote = "Every face, every shop, bedroom window, public-house, and
    dark square is a picture feverishly turned--in search of what?
    It is the same with books. What do we seek through millions of pages?";

    for (idx, line) in quote.lines().enumerate() {
        if line.contains(search_term) {
            let line_num = idx + 1;
            println!("{}: {}", line_num, line);
        }
    }
}
<|endoftext|>