<commit_before>use std::io::prelude::*;
use std::io::BufReader;
use std::error::Error;
use std::io::{Error as IOError, ErrorKind as IOErrorKind};
use std::path::Path;
use std::fs::File;
use std::char;

use parser::tokens::Token;
use lexer::result::{LexerResult, LexerError};

pub trait Reader {
  fn next_token(&mut self) -> LexerResult<Token>;
  fn peek_token(&mut self) -> LexerResult<Token>;
}

pub struct FileReader {
  pub file_name     : String,
  pub line_number   : u32,

  source_line       : String,
  line_pos          : usize,
  source_file       : BufReader<File>,
  peek_tok          : Option<Token>
}

impl FileReader {
  pub fn new(filename : &str) -> LexerResult<FileReader> {
    let f = try!(File::open(Path::new(filename)));
    let mut b = BufReader::new(f);
    let mut s = String::new();
    try!(b.read_line(&mut s));

    Ok(FileReader {
      file_name: filename.to_string(),
      line_number: 1,

      source_line: s,
      line_pos: 0,
      source_file: b,
      peek_tok: None
    })
  }

  // Advance the lexer state ahead one character
  fn bump(&mut self) -> LexerResult<()> {
    if self.line_pos >= self.source_line.len() - 1 {
      self.bump_line()
    } else {
      let c = self.current();
      self.line_pos += c.len_utf8();
      Ok(())
    }
  }

  // Advance the lexer state ahead one line
  fn bump_line(&mut self) -> LexerResult<()> {
    self.source_line.clear();
    let r = self.source_file.read_line(&mut self.source_line);
    match r {
      Ok(0) =>
        return Err(LexerError::from(IOError::new(IOErrorKind::Other, "EOF"))),
      Err(e) =>
        return Err(LexerError::from(e)),
      _ => ()
    }
    self.line_pos = 0;
    self.line_number += 1;
    Ok(())
  }

  // Get the character at the current lexer position
  fn current(&self) -> char {
    self.source_line[self.line_pos..].chars().next().unwrap()
  }

  // Skip n equals signs in a long string delimiter. Return n.
  fn skip_sep(&mut self) -> LexerResult<i8> {
    let mut n = 0;
    let s = self.current();
    if s != '[' && s != ']' {
      return Err(LexerError::GenericError("skip_sep"))
    }
    try!(self.bump());
    loop {
      if self.current() != '=' {
        break;
      }
      try!(self.bump());
      n += 1;
    }

    if self.current() == s {
      Ok(n)
    } else {
      Ok((-n) - 1)
    }
  }

  // Read a long string of the form [[str]], [=[str]=], ...
  fn read_long_string(&mut self, sep : i8) -> LexerResult<String> {
    let mut s = String::new();

    try!(self.bump());   // skip 2nd [
    if self.current() == '\r' || self.current() == '\n' {
      // Lua ignores an immediate newline for long strings
      // so that it will not be included in the string
      try!(self.bump_line());
    }

    loop {
      match self.current() {
        ']' => {
          let p = try!(self.skip_sep());
          if p == sep {
            try!(self.bump());  // skip 2nd ]
            return Ok(s);
          }
        },
        c => {
          s.push(c);
          try!(self.bump());
        }
      }
    }
  }

  // Read a normal form string in quotes
  fn read_string(&mut self) -> LexerResult<String> {
    let del = &self.current();
    let mut s = String::new();
    try!(self.bump());   // skip leading del

    while self.current() != *del {
      match self.current() {
        '\n' | '\r' =>
          return Err(LexerError::GenericError("unfinished string")),
        '\\' => {
          // TODO: I feel like this should be mut...
          let c : char;
          try!(self.bump());
          match self.current() {
            'a' => c = '\x07',
            'b' => c = '\x08',
            'f' => c = '\x0C',
            'n' => c = '\n',
            'r' => c = '\r',
            't' => c = '\t',
            'v' => c = '\x0B',
            x => {
              if !x.is_digit(10) {
                c = x;
              } else {
                let mut y : u32 = 0;
                let mut i : u8 = 0;
                loop {
                  y = 10*y + self.current().to_digit(10).unwrap();
                  try!(self.bump());
                  i += 1;
                  if i >= 3 || !self.current().is_digit(10) {
                    break;
                  }
                }
                c = char::from_u32(y).unwrap();
              }
            }
          }
          s.push(c);
        },
        c => s.push(c)
      }
      try!(self.bump());
    }
    try!(self.bump());   // skip final del

    Ok(s)
  }

  // Read a number... might be malformed...
  fn read_number(&mut self) -> LexerResult<String> {
    let mut s = String::new();

    loop {
      s.push(self.current());
      try!(self.bump());

      if !self.current().is_digit(10) && self.current() != '.' {
        break;
      }
    }

    if self.current() == 'E' || self.current() == 'e' {
      s.push(self.current());
      try!(self.bump());
      if self.current() == '+' || self.current() == '-' {
        s.push(self.current());
        try!(self.bump());
      }
    }

    while self.current().is_alphanumeric() || self.current() == '_' {
      s.push(self.current());
      try!(self.bump());
    }

    Ok(s)
  }

  // Read a keyword or identifier
  fn read_name(&mut self) -> LexerResult<Token> {
    let mut s = String::new();

    while self.current().is_alphanumeric() || self.current() == '_' {
      s.push(self.current());
      try!(self.bump());
    }

    match &s[0..] {
      "and" => Ok(Token::And),
      "break" => Ok(Token::Break),
      "do" => Ok(Token::Do),
      "else" => Ok(Token::Else),
      "elseif" => Ok(Token::Elseif),
      "end" => Ok(Token::End),
      "false" => Ok(Token::False),
      "for" => Ok(Token::For),
      "function" => Ok(Token::Function),
      "if" => Ok(Token::If),
      "in" => Ok(Token::In),
      "local" => Ok(Token::Local),
      "nil" => Ok(Token::Nil),
      "not" => Ok(Token::Not),
      "or" => Ok(Token::Or),
      "repeat" => Ok(Token::Repeat),
      "return" => Ok(Token::Return),
      "then" => Ok(Token::Then),
      "true" => Ok(Token::True),
      "until" => Ok(Token::Until),
      "while" => Ok(Token::While),
      _ => Ok(Token::Name(s))
    }
  }

  // Read an operator or the "operator or equal" form
  fn or_eq(&mut self, base : Token, eq : Token) -> LexerResult<Token> {
    try!(self.bump());
    if self.current() != '=' {
      return Ok(base);
    } else {
      try!(self.bump());
      return Ok(eq);
    }
  }

  // Real impl for next_token wrapped for EOF
  fn real_next_token(&mut self) -> LexerResult<Token> {
    match self.peek_tok.clone() {
      Some(tok) => {
        self.peek_tok = None;
        return Ok(tok);
      },
      None => ()
    }

    loop {
      match self.current() {
        '-' => {
          try!(self.bump());
          if self.current() != '-' {
            return Ok(Token::Minus);
          } else {
            // Lex a comment
            try!(self.bump());
            if self.current() == '[' {
              let sep = try!(self.skip_sep());
              if sep >= 0 {
                // Block comment
                try!(self.read_long_string(sep));
                continue;
              }
            } else {
              // Line comment
              try!(self.bump_line());
              continue;
            }
          }
        },

        '[' => {
          let sep = try!(self.skip_sep());
          if sep >= 0 {
            let s = try!(self.read_long_string(sep));
            return Ok(Token::String(s));
          } else if sep == -1 {
            // Just a single [
            return Ok(Token::LSquare);
          } else {
            return Err(LexerError::GenericError("invalid string delimiter"));
          }
        },

        // Comparison operators
        '=' => return self.or_eq(Token::Assign, Token::Eq),
        '<' => return self.or_eq(Token::Lt, Token::Leq),
        '>' => return self.or_eq(Token::Gt, Token::Geq),
        '~' => return self.or_eq(Token::Not, Token::Neq),

        '"' | '\'' => {
          let s = try!(self.read_string());
          return Ok(Token::String(s));
        },

        '.' => {
          try!(self.bump());
          if self.current() == '.' {
            try!(self.bump());
            if self.current() == '.' {
              return Ok(Token::Dotdotdot);
            } else {
              return Ok(Token::Dotdot);
            }
          } else if !self.current().is_digit(10) {
            return Ok(Token::Dot);
          } else {
            let s = try!(self.read_number());
            return Ok(Token::Number(s));
          }
        },

        // The easy ones.  Unambiguous single-char tokens
        '+' => { try!(self.bump()); return Ok(Token::Plus) },
        '*' => { try!(self.bump()); return Ok(Token::Times) },
        '/' => { try!(self.bump()); return Ok(Token::Divide) },
        '%' => { try!(self.bump()); return Ok(Token::Mod) },
        '^' => { try!(self.bump()); return Ok(Token::Exp) },
        '#' => { try!(self.bump()); return Ok(Token::Len) },
        '(' => { try!(self.bump()); return Ok(Token::LParen) },
        ')' => { try!(self.bump()); return Ok(Token::RParen) },
        '{' => { try!(self.bump()); return Ok(Token::LBrace) },
        '}' => { try!(self.bump()); return Ok(Token::RBrace) },
        ']' => { try!(self.bump()); return Ok(Token::RSquare) },
        ';' => { try!(self.bump()); return Ok(Token::Semi) },
        ':' => { try!(self.bump()); return Ok(Token::Colon) },
        ',' => { try!(self.bump()); return Ok(Token::Comma) },

        _ => {
          if self.current().is_whitespace() {
            // Skip white space
            try!(self.bump());
            continue;
          } else if self.current().is_digit(10) {
            let s = try!(self.read_number());
            return Ok(Token::Number(s));
          } else if self.current().is_alphabetic() || self.current() == '_' {
            return self.read_name();
          } else {
            return Err(LexerError::GenericError("unexpected character"));
          }
        }
      }
    }
  }
}

impl Reader for FileReader {
  /// Get the next token.  Advances the lexer state.
  fn next_token(&mut self) -> LexerResult<Token> {
    let tok = self.real_next_token();
    match tok {
      Ok(t) => Ok(t),
      Err(e) => match e.description() {
        "EOF" => Ok(Token::EOF),
        _ => Err(e)
      }
    }
  }

  /// Have a look at the next token.  May advance lexer state, may not.
  fn peek_token(&mut self) -> LexerResult<Token> {
    match self.peek_tok.clone() {
      Some(tok) => Ok(tok),
      None => {
        let tok = try!(self.next_token());
        self.peek_tok = Some(tok.clone());
        Ok(tok)
      }
    }
  }
}
<commit_msg>Add column number tracking to lexer.<commit_after>use std::io::prelude::*;
use std::io::BufReader;
use std::error::Error;
use std::io::{Error as IOError, ErrorKind as IOErrorKind};
use std::path::Path;
use std::fs::File;
use std::char;

use parser::tokens::Token;
use lexer::result::{LexerResult, LexerError};

pub trait Reader {
  fn next_token(&mut self) -> LexerResult<Token>;
  fn peek_token(&mut self) -> LexerResult<Token>;
}

pub struct FileReader {
  pub file_name     : String,
  pub line_number   : u32,
  pub column_number : u32,

  source_line       : String,
  line_pos          : usize,
  source_file       : BufReader<File>,
  peek_tok          : Option<Token>
}

impl FileReader {
  pub fn new(filename : &str) -> LexerResult<FileReader> {
    let f = try!(File::open(Path::new(filename)));
    let mut b = BufReader::new(f);
    let mut s = String::new();
    try!(b.read_line(&mut s));

    Ok(FileReader {
      file_name: filename.to_string(),
      line_number: 1,
      column_number: 1,

      source_line: s,
      line_pos: 0,
      source_file: b,
      peek_tok: None
    })
  }

  // Advance the lexer state ahead one character
  fn bump(&mut self) -> LexerResult<()> {
    if self.line_pos >= self.source_line.len() - 1 {
      self.bump_line()
    } else {
      let c = self.current();
      self.line_pos += c.len_utf8();
      self.column_number += 1;
      Ok(())
    }
  }

  // Advance the lexer state ahead one line
  fn bump_line(&mut self) -> LexerResult<()> {
    self.source_line.clear();
    let r = self.source_file.read_line(&mut self.source_line);
    match r {
      Ok(0) =>
        return Err(LexerError::from(IOError::new(IOErrorKind::Other, "EOF"))),
      Err(e) =>
        return Err(LexerError::from(e)),
      _ => ()
    }
    self.line_pos = 0;
    self.line_number += 1;
    self.column_number = 1;
    Ok(())
  }

  // Get the character at the current lexer position
  fn current(&self) -> char {
    self.source_line[self.line_pos..].chars().next().unwrap()
  }

  // Skip n equals signs in a long string delimiter. Return n.
  fn skip_sep(&mut self) -> LexerResult<i8> {
    let mut n = 0;
    let s = self.current();
    if s != '[' && s != ']' {
      return Err(LexerError::GenericError("skip_sep"))
    }
    try!(self.bump());
    loop {
      if self.current() != '=' {
        break;
      }
      try!(self.bump());
      n += 1;
    }

    if self.current() == s {
      Ok(n)
    } else {
      Ok((-n) - 1)
    }
  }

  // Read a long string of the form [[str]], [=[str]=], ...
  fn read_long_string(&mut self, sep : i8) -> LexerResult<String> {
    let mut s = String::new();

    try!(self.bump());   // skip 2nd [
    if self.current() == '\r' || self.current() == '\n' {
      // Lua ignores an immediate newline for long strings
      // so that it will not be included in the string
      try!(self.bump_line());
    }

    loop {
      match self.current() {
        ']' => {
          let p = try!(self.skip_sep());
          if p == sep {
            try!(self.bump());  // skip 2nd ]
            return Ok(s);
          }
        },
        c => {
          s.push(c);
          try!(self.bump());
        }
      }
    }
  }

  // Read a normal form string in quotes
  fn read_string(&mut self) -> LexerResult<String> {
    let del = &self.current();
    let mut s = String::new();
    try!(self.bump());   // skip leading del

    while self.current() != *del {
      match self.current() {
        '\n' | '\r' =>
          return Err(LexerError::GenericError("unfinished string")),
        '\\' => {
          // TODO: I feel like this should be mut...
          let c : char;
          try!(self.bump());
          match self.current() {
            'a' => c = '\x07',
            'b' => c = '\x08',
            'f' => c = '\x0C',
            'n' => c = '\n',
            'r' => c = '\r',
            't' => c = '\t',
            'v' => c = '\x0B',
            x => {
              if !x.is_digit(10) {
                c = x;
              } else {
                let mut y : u32 = 0;
                let mut i : u8 = 0;
                loop {
                  y = 10*y + self.current().to_digit(10).unwrap();
                  try!(self.bump());
                  i += 1;
                  if i >= 3 || !self.current().is_digit(10) {
                    break;
                  }
                }
                c = char::from_u32(y).unwrap();
              }
            }
          }
          s.push(c);
        },
        c => s.push(c)
      }
      try!(self.bump());
    }
    try!(self.bump());   // skip final del

    Ok(s)
  }

  // Read a number... might be malformed...
  fn read_number(&mut self) -> LexerResult<String> {
    let mut s = String::new();

    loop {
      s.push(self.current());
      try!(self.bump());

      if !self.current().is_digit(10) && self.current() != '.' {
        break;
      }
    }

    if self.current() == 'E' || self.current() == 'e' {
      s.push(self.current());
      try!(self.bump());
      if self.current() == '+' || self.current() == '-' {
        s.push(self.current());
        try!(self.bump());
      }
    }

    while self.current().is_alphanumeric() || self.current() == '_' {
      s.push(self.current());
      try!(self.bump());
    }

    Ok(s)
  }

  // Read a keyword or identifier
  fn read_name(&mut self) -> LexerResult<Token> {
    let mut s = String::new();

    while self.current().is_alphanumeric() || self.current() == '_' {
      s.push(self.current());
      try!(self.bump());
    }

    match &s[0..] {
      "and" => Ok(Token::And),
      "break" => Ok(Token::Break),
      "do" => Ok(Token::Do),
      "else" => Ok(Token::Else),
      "elseif" => Ok(Token::Elseif),
      "end" => Ok(Token::End),
      "false" => Ok(Token::False),
      "for" => Ok(Token::For),
      "function" => Ok(Token::Function),
      "if" => Ok(Token::If),
      "in" => Ok(Token::In),
      "local" => Ok(Token::Local),
      "nil" => Ok(Token::Nil),
      "not" => Ok(Token::Not),
      "or" => Ok(Token::Or),
      "repeat" => Ok(Token::Repeat),
      "return" => Ok(Token::Return),
      "then" => Ok(Token::Then),
      "true" => Ok(Token::True),
      "until" => Ok(Token::Until),
      "while" => Ok(Token::While),
      _ => Ok(Token::Name(s))
    }
  }

  // Read an operator or the "operator or equal" form
  fn or_eq(&mut self, base : Token, eq : Token) -> LexerResult<Token> {
    try!(self.bump());
    if self.current() != '=' {
      return Ok(base);
    } else {
      try!(self.bump());
      return Ok(eq);
    }
  }

  // Real impl for next_token wrapped for EOF
  fn real_next_token(&mut self) -> LexerResult<Token> {
    match self.peek_tok.clone() {
      Some(tok) => {
        self.peek_tok = None;
        return Ok(tok);
      },
      None => ()
    }

    loop {
      match self.current() {
        '-' => {
          try!(self.bump());
          if self.current() != '-' {
            return Ok(Token::Minus);
          } else {
            // Lex a comment
            try!(self.bump());
            if self.current() == '[' {
              let sep = try!(self.skip_sep());
              if sep >= 0 {
                // Block comment
                try!(self.read_long_string(sep));
                continue;
              }
            } else {
              // Line comment
              try!(self.bump_line());
              continue;
            }
          }
        },

        '[' => {
          let sep = try!(self.skip_sep());
          if sep >= 0 {
            let s = try!(self.read_long_string(sep));
            return Ok(Token::String(s));
          } else if sep == -1 {
            // Just a single [
            return Ok(Token::LSquare);
          } else {
            return Err(LexerError::GenericError("invalid string delimiter"));
          }
        },

        // Comparison operators
        '=' => return self.or_eq(Token::Assign, Token::Eq),
        '<' => return self.or_eq(Token::Lt, Token::Leq),
        '>' => return self.or_eq(Token::Gt, Token::Geq),
        '~' => return self.or_eq(Token::Not, Token::Neq),

        '"' | '\'' => {
          let s = try!(self.read_string());
          return Ok(Token::String(s));
        },

        '.' => {
          try!(self.bump());
          if self.current() == '.' {
            try!(self.bump());
            if self.current() == '.' {
              return Ok(Token::Dotdotdot);
            } else {
              return Ok(Token::Dotdot);
            }
          } else if !self.current().is_digit(10) {
            return Ok(Token::Dot);
          } else {
            let s = try!(self.read_number());
            return Ok(Token::Number(s));
          }
        },

        // The easy ones.  Unambiguous single-char tokens
        '+' => { try!(self.bump()); return Ok(Token::Plus) },
        '*' => { try!(self.bump()); return Ok(Token::Times) },
        '/' => { try!(self.bump()); return Ok(Token::Divide) },
        '%' => { try!(self.bump()); return Ok(Token::Mod) },
        '^' => { try!(self.bump()); return Ok(Token::Exp) },
        '#' => { try!(self.bump()); return Ok(Token::Len) },
        '(' => { try!(self.bump()); return Ok(Token::LParen) },
        ')' => { try!(self.bump()); return Ok(Token::RParen) },
        '{' => { try!(self.bump()); return Ok(Token::LBrace) },
        '}' => { try!(self.bump()); return Ok(Token::RBrace) },
        ']' => { try!(self.bump()); return Ok(Token::RSquare) },
        ';' => { try!(self.bump()); return Ok(Token::Semi) },
        ':' => { try!(self.bump()); return Ok(Token::Colon) },
        ',' => { try!(self.bump()); return Ok(Token::Comma) },

        _ => {
          if self.current().is_whitespace() {
            // Skip white space
            try!(self.bump());
            continue;
          } else if self.current().is_digit(10) {
            let s = try!(self.read_number());
            return Ok(Token::Number(s));
          } else if self.current().is_alphabetic() || self.current() == '_' {
            return self.read_name();
          } else {
            return Err(LexerError::GenericError("unexpected character"));
          }
        }
      }
    }
  }
}

impl Reader for FileReader {
  /// Get the next token.  Advances the lexer state.
  fn next_token(&mut self) -> LexerResult<Token> {
    let tok = self.real_next_token();
    match tok {
      Ok(t) => Ok(t),
      Err(e) => match e.description() {
        "EOF" => Ok(Token::EOF),
        _ => Err(e)
      }
    }
  }

  /// Have a look at the next token.  May advance lexer state, may not.
  fn peek_token(&mut self) -> LexerResult<Token> {
    match self.peek_tok.clone() {
      Some(tok) => Ok(tok),
      None => {
        let tok = try!(self.next_token());
        self.peek_tok = Some(tok.clone());
        Ok(tok)
      }
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google 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,
// 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.

extern crate cgmath;
extern crate collision;
extern crate futures;
extern crate grpcio;
extern crate point_viewer;
extern crate point_viewer_grpc_proto_rust;
extern crate protobuf;

use cgmath::{Matrix4, Point3};
use collision::Aabb3;
use futures::{Future, Stream};
use grpcio::{ChannelBuilder, EnvBuilder};
use point_viewer::errors::*;
use point_viewer::math::Cube;
use point_viewer::octree::{NodeData, NodeId, NodeMeta, Octree, OnDiskOctree, PositionEncoding,
                           VisibleNode};
pub use point_viewer_grpc_proto_rust::proto;
pub use point_viewer_grpc_proto_rust::proto_grpc;
use proto_grpc::OctreeClient;
use std::path::PathBuf;
use std::sync::Arc;

pub struct GrpcOctree {
    client: OctreeClient,
    octree: OnDiskOctree,
}

impl GrpcOctree {
    pub fn new(addr: &str) -> Self {
        let env = Arc::new(EnvBuilder::new().build());
        let ch = ChannelBuilder::new(env).connect(addr);
        let client = OctreeClient::new(ch);

        let reply = client.get_meta(&proto::GetMetaRequest::new()).expect("rpc");
        // TODO(sirver): We pass a dummy directory and hope we never actually use it for anything.
        let octree = OnDiskOctree::from_meta(reply.meta.unwrap(), PathBuf::new()).unwrap();
        GrpcOctree { client, octree }
    }

    // TODO(tschiwietz): This function should return Result<> for error handling.
    pub fn get_points_in_box(&self, bounding_box: &Aabb3<f32>) -> Vec<Point3<f32>> {
        let mut req = proto::GetPointsInBoxRequest::new();
        req.mut_bounding_box().mut_min().set_x(bounding_box.min.x);
        req.mut_bounding_box().mut_min().set_y(bounding_box.min.y);
        req.mut_bounding_box().mut_min().set_z(bounding_box.min.z);
        req.mut_bounding_box().mut_max().set_x(bounding_box.max.x);
        req.mut_bounding_box().mut_max().set_y(bounding_box.max.y);
        req.mut_bounding_box().mut_max().set_z(bounding_box.max.z);
        let replies = self.client.get_points_in_box(&req).unwrap();
        let mut points = Vec::new();
        replies
            .for_each(|reply| {
                for point in reply.points.iter() {
                    points.push(Point3::new(point.x, point.y, point.z));
                }
                Ok(())
            })
            .wait()
            .unwrap();
        points
    }
}

impl Octree for GrpcOctree {
    fn get_visible_nodes(
        &self,
        projection_matrix: &Matrix4<f32>,
        width: i32,
        height: i32,
    ) -> Vec<VisibleNode> {
        self.octree
            .get_visible_nodes(projection_matrix, width, height)
    }

    fn get_node_data(&self, node_id: &NodeId) -> Result<NodeData> {
        let mut req = proto::GetNodeDataRequest::new();
        req.set_id(node_id.to_string());

        // TODO(sirver): This should most definitively not crash, but instead return an error.
        // Needs changes to the trait though.
        let reply = self.client.get_node_data(&req).expect("rpc");
        let node = reply.node.unwrap();
        let result = NodeData {
            position: reply.position,
            color: reply.color,
            meta: NodeMeta {
                num_points: node.num_points,
                position_encoding: PositionEncoding::from_proto(node.position_encoding).unwrap(),
                bounding_cube: node_id
                    .find_bounding_cube(&Cube::bounding(&self.octree.bounding_box())),
            },
        };
        Ok(result)
    }
}
<commit_msg>Accept large replices from the octree server. (#138)<commit_after>// Copyright 2018 Google 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,
// 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.

extern crate cgmath;
extern crate collision;
extern crate futures;
extern crate grpcio;
extern crate point_viewer;
extern crate point_viewer_grpc_proto_rust;
extern crate protobuf;

use cgmath::{Matrix4, Point3};
use collision::Aabb3;
use futures::{Future, Stream};
use grpcio::{ChannelBuilder, EnvBuilder};
use point_viewer::errors::*;
use point_viewer::math::Cube;
use point_viewer::octree::{NodeData, NodeId, NodeMeta, Octree, OnDiskOctree, PositionEncoding,
                           VisibleNode};
pub use point_viewer_grpc_proto_rust::proto;
pub use point_viewer_grpc_proto_rust::proto_grpc;
use proto_grpc::OctreeClient;
use std::path::PathBuf;
use std::sync::Arc;

pub struct GrpcOctree {
    client: OctreeClient,
    octree: OnDiskOctree,
}

impl GrpcOctree {
    pub fn new(addr: &str) -> Self {
        let env = Arc::new(EnvBuilder::new().build());
        let ch = ChannelBuilder::new(env).max_receive_message_len(::std::usize::MAX).connect(addr);
        let client = OctreeClient::new(ch);

        let reply = client.get_meta(&proto::GetMetaRequest::new()).expect("rpc");
        // TODO(sirver): We pass a dummy directory and hope we never actually use it for anything.
        let octree = OnDiskOctree::from_meta(reply.meta.unwrap(), PathBuf::new()).unwrap();
        GrpcOctree { client, octree }
    }

    // TODO(tschiwietz): This function should return Result<> for error handling.
    pub fn get_points_in_box(&self, bounding_box: &Aabb3<f32>) -> Vec<Point3<f32>> {
        let mut req = proto::GetPointsInBoxRequest::new();
        req.mut_bounding_box().mut_min().set_x(bounding_box.min.x);
        req.mut_bounding_box().mut_min().set_y(bounding_box.min.y);
        req.mut_bounding_box().mut_min().set_z(bounding_box.min.z);
        req.mut_bounding_box().mut_max().set_x(bounding_box.max.x);
        req.mut_bounding_box().mut_max().set_y(bounding_box.max.y);
        req.mut_bounding_box().mut_max().set_z(bounding_box.max.z);
        let replies = self.client.get_points_in_box(&req).unwrap();
        let mut points = Vec::new();
        replies
            .for_each(|reply| {
                for point in reply.points.iter() {
                    points.push(Point3::new(point.x, point.y, point.z));
                }
                Ok(())
            })
            .wait()
            .unwrap();
        points
    }
}

impl Octree for GrpcOctree {
    fn get_visible_nodes(
        &self,
        projection_matrix: &Matrix4<f32>,
        width: i32,
        height: i32,
    ) -> Vec<VisibleNode> {
        self.octree
            .get_visible_nodes(projection_matrix, width, height)
    }

    fn get_node_data(&self, node_id: &NodeId) -> Result<NodeData> {
        let mut req = proto::GetNodeDataRequest::new();
        req.set_id(node_id.to_string());

        // TODO(sirver): This should most definitively not crash, but instead return an error.
        // Needs changes to the trait though.
        let reply = self.client.get_node_data(&req).expect("rpc");
        let node = reply.node.unwrap();
        let result = NodeData {
            position: reply.position,
            color: reply.color,
            meta: NodeMeta {
                num_points: node.num_points,
                position_encoding: PositionEncoding::from_proto(node.position_encoding).unwrap(),
                bounding_cube: node_id
                    .find_bounding_cube(&Cube::bounding(&self.octree.bounding_box())),
            },
        };
        Ok(result)
    }
}
<|endoftext|>


<commit_before>use std;
import std::io;
import std::io::{writer_util, reader_util};
import result;

export rowreader, rowaccess, rowiter, new_reader, new_reader_readlen;

enum state {
    fieldstart(bool),
    infield(uint, uint),
    inescapedfield(uint, uint),
    inquote(uint, uint)
}

type rowreader = {
    readlen: uint,
    delim: char,
    quote: char,
    f : io::reader,
    mutable offset : uint,
    mutable buffers : [@[char]],
    mutable state : state
};

type row = {
    fields : [ fieldtype ]
};

type bufferdescr = {
    escaped: bool,
    buffers: [@[char]],
    start: uint,
    end: uint
};

enum fieldtype {
    emptyfield(),
    bufferfield(bufferdescr)
}

iface rowiter {
    fn readrow() -> result::t<row, str>;
}

iface rowaccess {
    fn len() -> uint;
    fn getchars(uint) -> [char];
    fn getstr(uint) -> str;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    {
        readlen: 1024u,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false)
    }
}

fn new_reader_readlen(+f: io::reader, +delim: char, +quote: char, rl: uint) -> rowreader {
    {
        readlen: rl,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false)
    }
}

impl of rowaccess for row {
    fn len() -> uint {
        vec::len(self.fields)
    }
    fn getchars(field: uint) -> [char] {
        fn unescape(escaped: [char]) -> [char] {
            let r : [char] = [];
            vec::reserve(r, vec::len(escaped));
            let in_q = false;
            for c in escaped {
                if in_q {
                    assert(c == '"');
                    in_q = false;
                } else {
                    in_q = c == '"';
                    r += [c];
                }
            }
            ret r;
        }
        alt self.fields[field] {
            emptyfield() { ret []; }
            bufferfield(desc) {
                let buf = [];
                {
                    let i = 0u;
                    while i < vec::len(desc.buffers) {
                        let from = if (i == 0u)
                            { desc.start } else { 0u };
                        let to = if (i == vec::len(desc.buffers) - 1u)
                            { desc.end } else { vec::len(*desc.buffers[i]) };
                        buf += vec::slice(*desc.buffers[i], from, to);
                        i = i + 1u;
                    }
                }
                if desc.escaped {
                    buf = unescape(buf);
                }
                ret buf;
            }
        };
    }
    fn getstr(field: uint) -> str {
        ret str::from_chars(self.getchars(field));
    }
}

impl of rowiter for rowreader {
    fn readrow() -> result::t<row, str> {
        fn row_from_buf(self: rowreader, &fields: [fieldtype]) -> bool {
            fn new_bufferfield(self: rowreader, escaped: bool, sb: uint, so: uint, eo: uint) -> fieldtype {
                let eb = vec::len(self.buffers);
                let sb = sb, so = so, eo = eo;
                if escaped {
                    so += 1u;
                    if so > vec::len(*self.buffers[sb]) {
                        sb += 1u;
                        so = vec::len(*self.buffers[sb]) - 1u;
                    }
                    if eo > 0u {
                        eo -= 1u;
                    } else {
                        eb -= 1u;
                        eo = vec::len(*self.buffers[sb]) - 1u;
                    }
                }
                bufferfield({ escaped: escaped, buffers: vec::slice(self.buffers, sb, eb), start: so, end: eo })
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf: @[char] = self.buffers[cbuffer];
            while self.offset < vec::len(*buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                self.offset += 1u;
                alt self.state {
                    fieldstart(after_delim) {
                        if c == self.quote {
                            self.state = inescapedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                fields += [emptyfield];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [emptyfield];
                        } else {
                            self.state = infield(cbuffer, coffset);
                        }
                    }
                    infield(b,o) {
                        if c == '\n' {
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                        }
                    }
                    inescapedfield(b, o) {
                        if c == self.quote {
                            self.state = inquote(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                        }
                    }
                    inquote(b, o) {
                        if c == '\n' {
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                            ret true;
                        } else if c == self.quote {
                            self.state = inescapedfield(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
            }
            ret false;
        }

        self.state = fieldstart(false);
        let do_read = vec::len(self.buffers) == 0u;
        let fields = [];
        while true {
            if do_read {
                let data: @[char] = @self.f.read_chars(self.readlen);
                if vec::len(*data) == 0u {
                    ret result::err("EOF");
                }
                self.buffers += [data];
                self.offset = 0u;
            }

            if row_from_buf(self, fields) {
                let r: row = { fields: fields };
                fields = [];
                if vec::len(self.buffers) > 1u {
                    self.buffers = vec::slice(self.buffers, vec::len(self.buffers) - 1u, vec::len(self.buffers));
                }
                ret result::ok(r);
            }
            do_read = true;
        }
        ret result::err("unreachable");
    }
}

#[cfg(test)]
mod test {
    fn rowmatch(testdata: str, expected: [[str]]) {
        let chk = fn@(mk: fn(io::reader) -> rowreader) {
            let f = io::string_reader(testdata);
            let r = mk(f);
            let i = 0u;
            while true {
                let res = r.readrow();
                if result::failure(res) {
                    break;
                }
                let row = result::get(res);
                let expect = expected[i];

                assert(row.len() == vec::len(expect));
                let j = 0u;
                while j < row.len() {
                    assert(row.getstr(j) == expect[j]);
                    j += 1u;
                }
                i += 1u;
            }
            assert(i == vec::len(expected));
        };
        // test default reader params
        chk({|inp| new_reader_readlen(inp, ',', '"', 2u) });
        // test continuations over read buffers
        let j = 1u;
        while j < str::len(testdata) {
            chk({|inp| new_reader_readlen(inp, ',', '"', j) });
            j += 1u;
        }
    }

    #[test]
    fn test_simple() {
        rowmatch("a,b,c,d\n1,2,3,4\n",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4"]]);
    }

    #[test]
    fn test_trailing_comma() {
        rowmatch("a,b,c,d\n1,2,3,4,\n",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4", ""]]);
    }

    #[test]
    fn test_leading_comma() {
        rowmatch("a,b,c,d\n,1,2,3,4\n",
                 [["a", "b", "c", "d"], ["", "1", "2", "3", "4"]]);
    }

    #[test]
    fn test_quote_simple() {
        rowmatch("\"Hello\",\"There\"\na,b,\"c\",d\n",
                 [["Hello", "There"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_quote_nested() {
        rowmatch("\"Hello\",\"There is a \"\"fly\"\" in my soup\"\na,b,\"c\",d\n",
                 [["Hello", "There is a \"fly\" in my soup"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_blank_line() {
        rowmatch("\n\n", [[], []]);
    }
}

<commit_msg>use syntactic sugar<commit_after>use std;
import std::io;
import std::io::{writer_util, reader_util};
import result;

export rowreader, rowaccess, rowiter, new_reader, new_reader_readlen;

enum state {
    fieldstart(bool),
    infield(uint, uint),
    inescapedfield(uint, uint),
    inquote(uint, uint)
}

type rowreader = {
    readlen: uint,
    delim: char,
    quote: char,
    f : io::reader,
    mutable offset : uint,
    mutable buffers : [@[char]],
    mutable state : state
};

type row = {
    fields : [ fieldtype ]
};

type bufferdescr = {
    escaped: bool,
    buffers: [@[char]],
    start: uint,
    end: uint
};

enum fieldtype {
    emptyfield(),
    bufferfield(bufferdescr)
}

iface rowiter {
    fn readrow() -> result::t<row, str>;
}

iface rowaccess {
    fn len() -> uint;
    fn getchars(uint) -> [char];
    fn getstr(uint) -> str;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    {
        readlen: 1024u,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false)
    }
}

fn new_reader_readlen(+f: io::reader, +delim: char, +quote: char, rl: uint) -> rowreader {
    {
        readlen: rl,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false)
    }
}

impl of rowaccess for row {
    fn len() -> uint {
        vec::len(self.fields)
    }
    fn getchars(field: uint) -> [char] {
        fn unescape(escaped: [char]) -> [char] {
            let r : [char] = [];
            vec::reserve(r, vec::len(escaped));
            let in_q = false;
            for c in escaped {
                if in_q {
                    assert(c == '"');
                    in_q = false;
                } else {
                    in_q = c == '"';
                    r += [c];
                }
            }
            ret r;
        }
        alt self.fields[field] {
            emptyfield() { ret []; }
            bufferfield(desc) {
                let buf = [];
                {
                    let i = 0u;
                    while i < vec::len(desc.buffers) {
                        let from = if (i == 0u)
                            { desc.start } else { 0u };
                        let to = if (i == vec::len(desc.buffers) - 1u)
                            { desc.end } else { vec::len(*desc.buffers[i]) };
                        buf += vec::slice(*desc.buffers[i], from, to);
                        i = i + 1u;
                    }
                }
                if desc.escaped {
                    buf = unescape(buf);
                }
                ret buf;
            }
        };
    }
    fn getstr(field: uint) -> str {
        ret str::from_chars(self.getchars(field));
    }
}

impl of rowiter for rowreader {
    fn readrow() -> result::t<row, str> {
        fn row_from_buf(self: rowreader, &fields: [fieldtype]) -> bool {
            fn new_bufferfield(self: rowreader, escaped: bool, sb: uint, so: uint, eo: uint) -> fieldtype {
                let eb = vec::len(self.buffers);
                let sb = sb, so = so, eo = eo;
                if escaped {
                    so += 1u;
                    if so > vec::len(*self.buffers[sb]) {
                        sb += 1u;
                        so = vec::len(*self.buffers[sb]) - 1u;
                    }
                    if eo > 0u {
                        eo -= 1u;
                    } else {
                        eb -= 1u;
                        eo = vec::len(*self.buffers[sb]) - 1u;
                    }
                }
                bufferfield({ escaped: escaped, buffers: vec::slice(self.buffers, sb, eb), start: so, end: eo })
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf: @[char] = self.buffers[cbuffer];
            while self.offset < vec::len(*buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                self.offset += 1u;
                alt self.state {
                    fieldstart(after_delim) {
                        if c == self.quote {
                            self.state = inescapedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                fields += [emptyfield];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [emptyfield];
                        } else {
                            self.state = infield(cbuffer, coffset);
                        }
                    }
                    infield(b,o) {
                        if c == '\n' {
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                        }
                    }
                    inescapedfield(b, o) {
                        if c == self.quote {
                            self.state = inquote(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                        }
                    }
                    inquote(b, o) {
                        if c == '\n' {
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                            ret true;
                        } else if c == self.quote {
                            self.state = inescapedfield(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
            }
            ret false;
        }

        self.state = fieldstart(false);
        let do_read = vec::len(self.buffers) == 0u;
        let fields = [];
        while true {
            if do_read {
                let data: @[char] = @self.f.read_chars(self.readlen);
                if vec::len(*data) == 0u {
                    ret result::err("EOF");
                }
                self.buffers += [data];
                self.offset = 0u;
            }

            if row_from_buf(self, fields) {
                let r: row = { fields: fields };
                fields = [];
                if vec::len(self.buffers) > 1u {
                    self.buffers = vec::slice(self.buffers, vec::len(self.buffers) - 1u, vec::len(self.buffers));
                }
                ret result::ok(r);
            }
            do_read = true;
        }
        ret result::err("unreachable");
    }
}

#[cfg(test)]
mod test {
    fn rowmatch(testdata: str, expected: [[str]]) {
        let chk = fn@(mk: fn(io::reader) -> rowreader) {
            let f = io::string_reader(testdata);
            let r = mk(f);
            let i = 0u;
            while true {
                let res = r.readrow();
                if result::failure(res) {
                    break;
                }
                let row = result::get(res);
                let expect = expected[i];

                assert(row.len() == vec::len(expect));
                let j = 0u;
                while j < row.len() {
                    assert(row.getstr(j) == expect[j]);
                    j += 1u;
                }
                i += 1u;
            }
            assert(i == vec::len(expected));
        };
        // test default reader params
        chk() { |inp|
            new_reader_readlen(inp, ',', '"', 2u)
        };
        // test continuations over read buffers
        let j = 1u;
        while j < str::len(testdata) {
            chk() { |inp|
                new_reader_readlen(inp, ',', '"', j)
            };
            j += 1u;
        }
    }

    #[test]
    fn test_simple() {
        rowmatch("a,b,c,d\n1,2,3,4\n",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4"]]);
    }

    #[test]
    fn test_trailing_comma() {
        rowmatch("a,b,c,d\n1,2,3,4,\n",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4", ""]]);
    }

    #[test]
    fn test_leading_comma() {
        rowmatch("a,b,c,d\n,1,2,3,4\n",
                 [["a", "b", "c", "d"], ["", "1", "2", "3", "4"]]);
    }

    #[test]
    fn test_quote_simple() {
        rowmatch("\"Hello\",\"There\"\na,b,\"c\",d\n",
                 [["Hello", "There"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_quote_nested() {
        rowmatch("\"Hello\",\"There is a \"\"fly\"\" in my soup\"\na,b,\"c\",d\n",
                 [["Hello", "There is a \"fly\" in my soup"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_blank_line() {
        rowmatch("\n\n", [[], []]);
    }
}

<|endoftext|>


<commit_before>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::new()), // TODO: with_capacity
			maximum_size: memory_type.limits().maximum()
				.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
				.unwrap_or(u32::MAX),
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
		}
		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let begin = offset as usize;
		let end = match begin.checked_add(size) {
			Some(end) => end,
			None => return Err(Error::Memory(format!("trying to read memory block of size {} from offset {}", size, offset))),
		};

		let buffer = self.buffer.read();
		if buffer.len() <= end {
			return Err(Error::Memory(format!("trying to read region [{}..{}] in memory [0..{}]", begin, end, buffer.len())));
		}

		Ok(buffer[begin..end].to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let size = value.len();
		let begin = offset as usize;
		let end = match begin.checked_add(size) {
			Some(end) => end,
			None => return Err(Error::Memory(format!("trying to update memory block of size {} from offset {}", size, offset))),
		};

		let mut buffer = self.buffer.write();
		if buffer.len() <= end {
			return Err(Error::Memory(format!("trying to update region [{}..{}] in memory [0..{}]", begin, end, buffer.len())));
		}

		let mut mut_buffer = buffer.as_mut_slice();
		mut_buffer[begin..end].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
			None => Ok(u32::MAX),
			Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
			Some(new_size) => {
				buffer.extend(vec![0; (new_size - old_size) as usize]);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}
}
<commit_msg>and working address.wast<commit_after>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::new()), // TODO: with_capacity
			maximum_size: memory_type.limits().maximum()
				.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
				.unwrap_or(u32::MAX),
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
		}
		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let begin = offset as usize;
		let end = match begin.checked_add(size) {
			Some(end) => end,
			None => return Err(Error::Memory(format!("trying to read memory block of size {} from offset {}", size, offset))),
		};

		let buffer = self.buffer.read();
		if buffer.len() < end {
			return Err(Error::Memory(format!("trying to read region [{}..{}] in memory [0..{}]", begin, end, buffer.len())));
		}

		Ok(buffer[begin..end].to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let size = value.len();
		let begin = offset as usize;
		let end = match begin.checked_add(size) {
			Some(end) => end,
			None => return Err(Error::Memory(format!("trying to update memory block of size {} from offset {}", size, offset))),
		};

		let mut buffer = self.buffer.write();
		if buffer.len() <= end {
			return Err(Error::Memory(format!("trying to update region [{}..{}] in memory [0..{}]", begin, end, buffer.len())));
		}

		let mut mut_buffer = buffer.as_mut_slice();
		mut_buffer[begin..end].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
			None => Ok(u32::MAX),
			Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
			Some(new_size) => {
				buffer.extend(vec![0; (new_size - old_size) as usize]);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Dawid Ciężarkiewicz <dpc@dpc.pw>
// See LICENSE-MPL2 file for more information.

//! # Mioco
//!
//! Scalable, coroutine-based, asynchronous IO handling library for Rust
//! programming language.
//!
//! Mioco uses asynchronous event loop, to cooperatively switch between
//! coroutines (aka. green threads), depending on data availability. You
//! can think of `mioco` as of *Node.js for Rust* or Rust *[green
//! threads][green threads] on top of [`mio`][mio]*.
//!
//! Mioco API mimics Rust standard library threading API, so it's easy
//! convert existing code to Mioco.
//!
//! Mioco coroutines should not use any native blocking-IO operations.  Any
//! long-running operations, or blocking IO should be executed in
//! `mioco::sync()` blocks.
//!
//! #  Features:
//!
//! ```norust
//! * multithreading support; (see `Config::set_thread_num()`)
//! * timers (see `timer` module);
//! * coroutine exit notification (see `JoinHandle`).
//! * synchronous operations support (see `MiocoHandle::sync()`).
//! * synchronization primitives (see `sync` module):
//!   * channels (see `sync::mpsc::channel()`);
//!   * support for synchronization with native environment (outside of Mioco instance)
//! * user-provided scheduling; (see `Config::set_scheduler()`);
//! ```
//!
//! #  Example:
//!
//! See `examples/echo.rs` for an example TCP echo server
//!

//! [green threads]: https://en.wikipedia.org/wiki/Green_threads
//! [mio]: https://github.com/carllerche/mio
//! [mio-api]: ../mioco/mio/index.html

#![feature(recover)]
#![feature(std_panic)]
#![feature(panic_propagate)]
#![feature(fnbox)]
#![feature(as_unsafe_cell)]
#![feature(reflect_marker)]
#![warn(missing_docs)]
#![allow(private_in_public)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#[cfg(test)]
extern crate env_logger;
#[cfg(test)]
extern crate net2;

extern crate thread_scoped;
extern crate libc;
extern crate spin;
extern crate mio as mio_orig;
extern crate context;
extern crate nix;
#[macro_use]
extern crate log;
extern crate time;
extern crate num_cpus;
extern crate slab;

#[macro_use]
mod src;

/// Some mio types that are part of mioco-API, re-exported
pub mod mio {
    pub use super::mio_orig::{EventLoop, Handler, Ipv4Addr};
}

/// Custom scheduling
pub mod sched {
    pub use super::src::{Scheduler, SchedulerThread};
    pub use super::src::CoroutineControl as Coroutine;
}

pub use src::{timer, tcp, udp, sync, unix};

pub use src::{Config, Event, EventSourceId, Handler, JoinHandle, MioAdapter, Mioco, RW, Evented};
pub use src::{get_userdata, set_userdata, set_children_userdata};
pub use src::{in_coroutine, select_wait, sleep, sleep_ms, spawn, start, shutdown};
pub use src::{start_threads, thread_num, yield_now};

#[cfg(test)]
mod tests;
<commit_msg>Fix Windows build.<commit_after>// Copyright 2015-2016 Dawid Ciężarkiewicz <dpc@dpc.pw>
// See LICENSE-MPL2 file for more information.

//! # Mioco
//!
//! Scalable, coroutine-based, asynchronous IO handling library for Rust
//! programming language.
//!
//! Mioco uses asynchronous event loop, to cooperatively switch between
//! coroutines (aka. green threads), depending on data availability. You
//! can think of `mioco` as of *Node.js for Rust* or Rust *[green
//! threads][green threads] on top of [`mio`][mio]*.
//!
//! Mioco API mimics Rust standard library threading API, so it's easy
//! convert existing code to Mioco.
//!
//! Mioco coroutines should not use any native blocking-IO operations.  Any
//! long-running operations, or blocking IO should be executed in
//! `mioco::sync()` blocks.
//!
//! #  Features:
//!
//! ```norust
//! * multithreading support; (see `Config::set_thread_num()`)
//! * timers (see `timer` module);
//! * coroutine exit notification (see `JoinHandle`).
//! * synchronous operations support (see `MiocoHandle::sync()`).
//! * synchronization primitives (see `sync` module):
//!   * channels (see `sync::mpsc::channel()`);
//!   * support for synchronization with native environment (outside of Mioco instance)
//! * user-provided scheduling; (see `Config::set_scheduler()`);
//! ```
//!
//! #  Example:
//!
//! See `examples/echo.rs` for an example TCP echo server
//!

//! [green threads]: https://en.wikipedia.org/wiki/Green_threads
//! [mio]: https://github.com/carllerche/mio
//! [mio-api]: ../mioco/mio/index.html

#![feature(recover)]
#![feature(std_panic)]
#![feature(panic_propagate)]
#![feature(fnbox)]
#![feature(as_unsafe_cell)]
#![feature(reflect_marker)]
#![warn(missing_docs)]
#![allow(private_in_public)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#[cfg(test)]
extern crate env_logger;
#[cfg(test)]
extern crate net2;

extern crate thread_scoped;
extern crate libc;
extern crate spin;
extern crate mio as mio_orig;
extern crate context;
extern crate nix;
#[macro_use]
extern crate log;
extern crate time;
extern crate num_cpus;
extern crate slab;

#[macro_use]
mod src;

/// Some mio types that are part of mioco-API, re-exported
pub mod mio {
    pub use super::mio_orig::{EventLoop, Handler, Ipv4Addr};
}

/// Custom scheduling
pub mod sched {
    pub use super::src::{Scheduler, SchedulerThread};
    pub use super::src::CoroutineControl as Coroutine;
}

#[cfg(not(windows))]
pub use src::{unix};

pub use src::{timer, tcp, udp, sync};

pub use src::{Config, Event, EventSourceId, Handler, JoinHandle, MioAdapter, Mioco, RW, Evented};
pub use src::{get_userdata, set_userdata, set_children_userdata};
pub use src::{in_coroutine, select_wait, sleep, sleep_ms, spawn, start, shutdown};
pub use src::{start_threads, thread_num, yield_now};

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


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

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

mod comdirect;

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

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

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

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

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

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

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

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

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

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

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

    Ok(())
}
<commit_msg>Fix unwrap bug in stocks<commit_after>use config::{Config, OutputFormat, Verbosity};
use errors::*;
use utils::console::*;
use utils::output;

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

mod comdirect;

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

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

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

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

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

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

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

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

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

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

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

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2014 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_must_use)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::{Command, FilePermission};
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::str;

#[deriving(PartialEq)]
struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl std::fmt::Show for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:u}.{:u}", self.major, self.minor)
    }
}

impl PartialOrd for Version {
    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match Command::new("pcre-config").arg("--prefix").output() {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(String::from_str(""))),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            String::from_str(prefix_str.as_slice().trim()).append("/lib")
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {:s}", versioncheck_rs_path.display(), e.to_str()),
            Ok(f) => f
        };
        let contents = format!("\
extern crate libc;

use std::c_str::{{CString}};
use libc::{{c_char, c_int, c_uchar, c_void}};
use std::ptr;
use std::ptr::{{RawPtr}};
use std::slice;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link(name = \"pcre\")]
extern {{
    static pcre_free: extern \"C\" fn(ptr: *const c_void);

    fn pcre_compile(pattern: *const c_char, options: options, errptr: *mut *const c_char, erroffset: *mut c_int, tableptr: *const c_uchar) -> *const pcre;
    fn pcre_exec(code: *const pcre, extra: *const pcre_extra, subject: *const c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *const c_char;
}}

fn main () {{
    unsafe {{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_string();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        pattern.with_c_str(|pattern_c_str| {{
            let mut err: *const c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if code.is_null() {{
                if code.is_null() {{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {{
                        None          => fail!(\"pcre_compile() failed at offset {{}}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset {{}}: {{}}\", erroffset as uint, err_str)
                    }}
                }}
            }}
            assert!(code.is_not_null());

            let ovecsize = 1 * 3;
            let mut ovector = Vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| {{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 {{
                    fail!(\"pcre_exec() failed\");
                }}

                print!(\"{{}}\", version_str.as_slice().slice_to(*ovector.get(1) as uint));
            }});

            pcre_free(code as *const c_void);
        }});
    }}
}}
");
        f.write_str(contents.as_slice()).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {:s}", versioncheck_rs_path.display(), e.to_str());
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match Command::new("rustc").arg("versioncheck.rs").arg("-L").arg(pcre_lib_path.display().to_str()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output.as_slice()));
        println!("{}", str::from_utf8(rustc_output.error.as_slice()));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match Command::new("./versioncheck").output() {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {:s}", e.to_str()),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output.as_slice()));
        println!("{}", str::from_utf8(versioncheck_output.error.as_slice()));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.as_slice().split('\n').rev();
    let version_str: String = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_string()
    };

    debug!("libpcre version {:s}", version_str.as_slice());

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str.as_slice()) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str.as_slice()),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str.as_slice(), min_required_version.to_str());
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match Command::new("rustc").arg("--out-dir").arg(lib_path.display().to_str()).arg("src/pcre/mod.rs").arg("-L").arg(pcre_lib_path.display().to_str()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match Command::new("rustc").arg("-o").arg(bin_path.join("pcredemo").display().to_str()).arg("src/pcredemo/main.rs").arg("-L").arg("lib").arg("-L").arg(pcre_lib_path.display().to_str()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<commit_msg>Update for RFC#28: Add PartialOrd::partial_cmp<commit_after>// Copyright 2014 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_must_use)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::{Command, FilePermission};
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::str;

#[deriving(Eq, PartialEq)]
struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl std::fmt::Show for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:u}.{:u}", self.major, self.minor)
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    fn cmp(&self, other: &Version) -> Ordering {
        (self.major, self.minor).cmp(&(other.major, other.minor))
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match Command::new("pcre-config").arg("--prefix").output() {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(String::from_str(""))),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e.to_str())
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            String::from_str(prefix_str.as_slice().trim()).append("/lib")
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {:s}", versioncheck_rs_path.display(), e.to_str()),
            Ok(f) => f
        };
        let contents = format!("\
extern crate libc;

use std::c_str::{{CString}};
use libc::{{c_char, c_int, c_uchar, c_void}};
use std::ptr;
use std::ptr::{{RawPtr}};
use std::slice;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link(name = \"pcre\")]
extern {{
    static pcre_free: extern \"C\" fn(ptr: *const c_void);

    fn pcre_compile(pattern: *const c_char, options: options, errptr: *mut *const c_char, erroffset: *mut c_int, tableptr: *const c_uchar) -> *const pcre;
    fn pcre_exec(code: *const pcre, extra: *const pcre_extra, subject: *const c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *const c_char;
}}

fn main () {{
    unsafe {{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_string();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        pattern.with_c_str(|pattern_c_str| {{
            let mut err: *const c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if code.is_null() {{
                if code.is_null() {{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {{
                        None          => fail!(\"pcre_compile() failed at offset {{}}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset {{}}: {{}}\", erroffset as uint, err_str)
                    }}
                }}
            }}
            assert!(code.is_not_null());

            let ovecsize = 1 * 3;
            let mut ovector = Vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| {{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 {{
                    fail!(\"pcre_exec() failed\");
                }}

                print!(\"{{}}\", version_str.as_slice().slice_to(*ovector.get(1) as uint));
            }});

            pcre_free(code as *const c_void);
        }});
    }}
}}
");
        f.write_str(contents.as_slice()).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {:s}", versioncheck_rs_path.display(), e.to_str());
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match Command::new("rustc").arg("versioncheck.rs").arg("-L").arg(pcre_lib_path.display().to_str()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output.as_slice()));
        println!("{}", str::from_utf8(rustc_output.error.as_slice()));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match Command::new("./versioncheck").output() {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {:s}", e.to_str()),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output.as_slice()));
        println!("{}", str::from_utf8(versioncheck_output.error.as_slice()));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.as_slice().split('\n').rev();
    let version_str: String = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_string()
    };

    debug!("libpcre version {:s}", version_str.as_slice());

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str.as_slice()) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str.as_slice()),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str.as_slice(), min_required_version.to_str());
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match Command::new("rustc").arg("--out-dir").arg(lib_path.display().to_str()).arg("src/pcre/mod.rs").arg("-L").arg(pcre_lib_path.display().to_str()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match Command::new("rustc").arg("-o").arg(bin_path.join("pcredemo").display().to_str()).arg("src/pcredemo/main.rs").arg("-L").arg("lib").arg("-L").arg(pcre_lib_path.display().to_str()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {:s}", e.to_str()),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name="html5ever_macros"]
#![crate_type="dylib"]

#![feature(macro_rules, plugin_registrar, quote, managed_boxes)]
#![deny(warnings)]

extern crate syntax;
extern crate rustc;
extern crate serialize;
extern crate debug;

use rustc::plugin::Registry;

// Internal macros for use in defining other macros.
mod internal;

// Make these public so that rustdoc will generate documentation for them.
pub mod named_entities;
pub mod match_token;

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("named_entities", named_entities::expand);
    reg.register_macro("match_token", match_token::expand);
}
<commit_msg>Drop the managed_boxes feature<commit_after>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name="html5ever_macros"]
#![crate_type="dylib"]

#![feature(macro_rules, plugin_registrar, quote)]
#![deny(warnings)]

extern crate syntax;
extern crate rustc;
extern crate serialize;
extern crate debug;

use rustc::plugin::Registry;

// Internal macros for use in defining other macros.
mod internal;

// Make these public so that rustdoc will generate documentation for them.
pub mod named_entities;
pub mod match_token;

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("named_entities", named_entities::expand);
    reg.register_macro("match_token", match_token::expand);
}
<|endoftext|>