<commit_before>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream
 {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
  producer: P,
}

fn parser<'a>(input: &'a [u8], is_start: &mut bool)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;

  if *is_start {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice     = i;
    *is_start = false;
  }

  metadata_parser(slice)
}

impl
 Stream
 where P: StreamProducer {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer(mut producer: P, error_str: &str)
                          -> io::Result<Self> {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                      => break,
        Err(ErrorKind::EndOfInput) => break,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  /// Returns an iterator over the decoded samples.
  pub fn iter(&mut self) -> Iter
 {
    let samples_left = self.info.total_samples;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream
,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let frame_index = self.stream.frame_index;

      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream

 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<commit_msg>Refactor `from_stream_producer`<commit_after>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream
 {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
  producer: P,
}

fn parser<'a>(input: &'a [u8], is_start: &mut bool)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;

  if *is_start {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice     = i;
    *is_start = false;
  }

  metadata_parser(slice)
}

impl
 Stream
 where P: StreamProducer {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer(mut producer: P, error_str: &str)
                          -> io::Result<Self> {
    let mut is_start    = true;
    let mut is_error    = false;
    let mut stream_info = StreamInfo::new();
    let mut metadata    = Vec::new();

    loop {
      match producer.parse(|i| parser(i, &mut is_start)) {
        Ok(block)                  => {
          let is_last = block.is_last;

          if let metadata::Data::StreamInfo(info) = block.data {
            stream_info = info;
          } else {
            metadata.push(block);
          }

          if is_last {
            break;
          }
        }
        Err(ErrorKind::EndOfInput) => break,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream_info.channels as usize;
      let block_size  = stream_info.max_block_size as usize;
      let output_size = block_size * channels;
      let mut output  = Vec::with_capacity(output_size);

      unsafe { output.set_len(output_size) }

      Ok(Stream {
        info: stream_info,
        metadata: metadata,
        frames: Vec::new(),
        state: ParserState::Marker,
        output: output,
        frame_index: 0,
        producer: producer,
      })
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  /// Returns an iterator over the decoded samples.
  pub fn iter(&mut self) -> Iter
 {
    let samples_left = self.info.total_samples;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream
,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let frame_index = self.stream.frame_index;

      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream

 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<|endoftext|>


<commit_before>use flowgger::config::Config;
use openssl::bn::BigNum;
use openssl::dh::DH;
use openssl::ssl::*;
use openssl::x509::X509FileType;
use std::path::{Path, PathBuf};
use std::sync::Arc;

pub mod tls_input;
#[cfg(feature = "coroutines")]
pub mod tlsco_input;

pub use super::Input;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
const DEFAULT_FRAMING: &'static str = "line";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";
#[cfg(feature = "coroutines")]
const DEFAULT_THREADS: usize = 1;
const DEFAULT_TIMEOUT: u64 = 3600;
const DEFAULT_TLS_METHOD: &'static str = "TLSv1.2";
const DEFAULT_VERIFY_PEER: bool = false;
const DEFAULT_COMPRESSION: bool = false;
const TLS_VERIFY_DEPTH: u32 = 6;

#[derive(Clone)]
pub struct TlsConfig {
    framing: String,
    threads: usize,
    arc_ctx: Arc<SslContext>
}

#[cfg(feature = "ecdh")]
fn set_ecdh(ctx: &mut SslContext) {
    ctx.set_ecdh_auto(true).unwrap();
}

#[cfg(not(feature = "ecdh"))]
fn set_ecdh(ctx: &mut SslContext) {
    let _ = ctx;
}

fn set_fs(ctx: &mut SslContext) {
    let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597").unwrap();
    let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659").unwrap();
    let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3").unwrap();
    let dh = DH::from_params(p, g, q).unwrap();
    ctx.set_tmp_dh(dh).unwrap();
    set_ecdh(ctx);
}

#[cfg(feature = "coroutines")]
fn get_default_threads(config: &Config) -> usize {
    config.lookup("input.tls_threads").map_or(DEFAULT_THREADS, |x| x.as_integer().
        expect("input.tls_threads must be an unsigned integer") as usize)
}

#[cfg(not(feature = "coroutines"))]
fn get_default_threads(_config: &Config) -> usize {
    1
}

pub fn config_parse(config: &Config) -> (TlsConfig, String, u64) {
    let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().
        expect("input.listen must be an ip:port string")).to_owned();
    let threads = get_default_threads(&config);
    let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().
        expect("input.tls_cert must be a path to a .pem file")).to_owned();
    let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().
        expect("input.tls_key must be a path to a .pem file")).to_owned();
    let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().
        expect("input.tls_ciphers must be a string with a cipher suite")).to_owned();
    let tls_method = match config.lookup("input.tls_method").map_or(DEFAULT_TLS_METHOD, |x| x.as_str().
        expect("input.tls_method must be a string with the TLS method")).to_lowercase().as_ref() {
            "sslv23" => SslMethod::Sslv23,
            "tlsv1" | "tlsv1.0" => SslMethod::Tlsv1,
            "tlsv1.1" => SslMethod::Tlsv1_1,
            "tlsv1.2" => SslMethod::Tlsv1_2,
            _ => panic!(r#"TLS method must be "SSLv23", "TLSv1.0", "TLSv1.1" or "TLSv1.2""#)
    };
    let verify_peer = config.lookup("input.tls_verify_peer").map_or(DEFAULT_VERIFY_PEER, |x| x.as_bool().
        expect("input.tls_verify_peer must be a boolean"));
    let ca_file: Option<PathBuf> = config.lookup("input.tls_ca_file").map_or(None, |x|
        Some(PathBuf::from(x.as_str().expect("input.tls_ca_file must be a path to a file"))));
    let compression = config.lookup("input.tls_compression").map_or(DEFAULT_COMPRESSION, |x| x.as_bool().
        expect("input.tls_compression must be a boolean"));
    let timeout = config.lookup("input.timeout").map_or(DEFAULT_TIMEOUT, |x| x.as_integer().
        expect("input.timeout must be an integer") as u64);
    let framing = if config.lookup("input.framed").map_or(false, |x| x.as_bool().
        expect("input.framed must be a boolean")) {
        "syslen"
    } else {
        DEFAULT_FRAMING
    };
    let framing = config.lookup("input.framing").map_or(framing, |x| x.as_str().
        expect(r#"input.framing must be a string set to "line", "nul" or "syslen""#)).to_owned();
    let mut ctx = SslContext::new(tls_method).unwrap();
    if verify_peer == false {
        ctx.set_verify(SSL_VERIFY_NONE, None);
    } else {
        ctx.set_verify_depth(TLS_VERIFY_DEPTH);
        ctx.set_verify(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, None);
        if let Some(ca_file) = ca_file {
            if ctx.set_CA_file(&ca_file).is_err() {
                panic!("Unable to read the trusted CA file");
            }
        }
    }
    let mut opts = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
    if compression == false {
        opts = opts | SSL_OP_NO_COMPRESSION;
    }
    ctx.set_options(opts);
    set_fs(&mut ctx);
    ctx.set_certificate_file(&Path::new(&cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&ciphers).unwrap();
    let arc_ctx = Arc::new(ctx);
    let tls_config = TlsConfig {
        framing: framing,
        threads: threads,
        arc_ctx: arc_ctx
    };
    (tls_config, listen, timeout)
}
<commit_msg>Remove support for SSLv23. TLS v1.0 was released in 1999. Windows 98 was the new hotness at that time. If your applications still requires SSLv3, we need to talk. You might be smoking something really strong.<commit_after>use flowgger::config::Config;
use openssl::bn::BigNum;
use openssl::dh::DH;
use openssl::ssl::*;
use openssl::x509::X509FileType;
use std::path::{Path, PathBuf};
use std::sync::Arc;

pub mod tls_input;
#[cfg(feature = "coroutines")]
pub mod tlsco_input;

pub use super::Input;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
const DEFAULT_FRAMING: &'static str = "line";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";
#[cfg(feature = "coroutines")]
const DEFAULT_THREADS: usize = 1;
const DEFAULT_TIMEOUT: u64 = 3600;
const DEFAULT_TLS_METHOD: &'static str = "TLSv1.2";
const DEFAULT_VERIFY_PEER: bool = false;
const DEFAULT_COMPRESSION: bool = false;
const TLS_VERIFY_DEPTH: u32 = 6;

#[derive(Clone)]
pub struct TlsConfig {
    framing: String,
    threads: usize,
    arc_ctx: Arc<SslContext>
}

#[cfg(feature = "ecdh")]
fn set_ecdh(ctx: &mut SslContext) {
    ctx.set_ecdh_auto(true).unwrap();
}

#[cfg(not(feature = "ecdh"))]
fn set_ecdh(ctx: &mut SslContext) {
    let _ = ctx;
}

fn set_fs(ctx: &mut SslContext) {
    let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597").unwrap();
    let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659").unwrap();
    let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3").unwrap();
    let dh = DH::from_params(p, g, q).unwrap();
    ctx.set_tmp_dh(dh).unwrap();
    set_ecdh(ctx);
}

#[cfg(feature = "coroutines")]
fn get_default_threads(config: &Config) -> usize {
    config.lookup("input.tls_threads").map_or(DEFAULT_THREADS, |x| x.as_integer().
        expect("input.tls_threads must be an unsigned integer") as usize)
}

#[cfg(not(feature = "coroutines"))]
fn get_default_threads(_config: &Config) -> usize {
    1
}

pub fn config_parse(config: &Config) -> (TlsConfig, String, u64) {
    let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().
        expect("input.listen must be an ip:port string")).to_owned();
    let threads = get_default_threads(&config);
    let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().
        expect("input.tls_cert must be a path to a .pem file")).to_owned();
    let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().
        expect("input.tls_key must be a path to a .pem file")).to_owned();
    let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().
        expect("input.tls_ciphers must be a string with a cipher suite")).to_owned();
    let tls_method = match config.lookup("input.tls_method").map_or(DEFAULT_TLS_METHOD, |x| x.as_str().
        expect("input.tls_method must be a string with the TLS method")).to_lowercase().as_ref() {
            "tlsv1" | "tlsv1.0" => SslMethod::Tlsv1,
            "tlsv1.1" => SslMethod::Tlsv1_1,
            "tlsv1.2" => SslMethod::Tlsv1_2,
            _ => panic!(r#"TLS method must be "TLSv1.0", "TLSv1.1" or "TLSv1.2""#)
    };
    let verify_peer = config.lookup("input.tls_verify_peer").map_or(DEFAULT_VERIFY_PEER, |x| x.as_bool().
        expect("input.tls_verify_peer must be a boolean"));
    let ca_file: Option<PathBuf> = config.lookup("input.tls_ca_file").map_or(None, |x|
        Some(PathBuf::from(x.as_str().expect("input.tls_ca_file must be a path to a file"))));
    let compression = config.lookup("input.tls_compression").map_or(DEFAULT_COMPRESSION, |x| x.as_bool().
        expect("input.tls_compression must be a boolean"));
    let timeout = config.lookup("input.timeout").map_or(DEFAULT_TIMEOUT, |x| x.as_integer().
        expect("input.timeout must be an integer") as u64);
    let framing = if config.lookup("input.framed").map_or(false, |x| x.as_bool().
        expect("input.framed must be a boolean")) {
        "syslen"
    } else {
        DEFAULT_FRAMING
    };
    let framing = config.lookup("input.framing").map_or(framing, |x| x.as_str().
        expect(r#"input.framing must be a string set to "line", "nul" or "syslen""#)).to_owned();
    let mut ctx = SslContext::new(tls_method).unwrap();
    if verify_peer == false {
        ctx.set_verify(SSL_VERIFY_NONE, None);
    } else {
        ctx.set_verify_depth(TLS_VERIFY_DEPTH);
        ctx.set_verify(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, None);
        if let Some(ca_file) = ca_file {
            if ctx.set_CA_file(&ca_file).is_err() {
                panic!("Unable to read the trusted CA file");
            }
        }
    }
    let mut opts = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
    if compression == false {
        opts = opts | SSL_OP_NO_COMPRESSION;
    }
    ctx.set_options(opts);
    set_fs(&mut ctx);
    ctx.set_certificate_file(&Path::new(&cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&ciphers).unwrap();
    let arc_ctx = Arc::new(ctx);
    let tls_config = TlsConfig {
        framing: framing,
        threads: threads,
        arc_ctx: arc_ctx
    };
    (tls_config, listen, timeout)
}
<|endoftext|>


<commit_before>extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S, arr2};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
};

use itertools::assert_equal;

#[test]
fn double_ended()
{
    let a = Array::range(0.0, 8.0f32);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
}

#[test]
fn indexed()
{
    let a = Array::range(0.0, 8.0f32);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::range(0., 8.);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.view().slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}
<commit_msg>Silence warnings<commit_after>extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
};

use itertools::assert_equal;

#[test]
fn double_ended()
{
    let a = Array::range(0.0, 8.0f32);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
}

#[test]
fn indexed()
{
    let a = Array::range(0.0, 8.0f32);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::range(0., 8.);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.view().slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}
<|endoftext|>


<commit_before>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagentryview;
#[macro_use] extern crate libimagerror;

use std::result::Result as RResult;
use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::store::FileLockEntry;
use libimagerror::trace::{trace_error, trace_error_exit};
use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::viewer::Viewer;

mod ui;

use error::{ViewError, ViewErrorKind};
use ui::build_ui;

type Result<T> = RResult<T, ViewError>;

fn main() {
    let rt = generate_runtime_setup( "imag-view",
                                     &version!()[..],
                                     "View entries (readonly)",
                                     build_ui);

    let entry_id = rt.cli().value_of("id").unwrap(); // enforced by clap

    if entry_id.contains("~") {
        error!("The --id argument does not need the version part");
        exit(1);
    }

    if rt.cli().is_present("versions") {
        if let Err(e) = view_versions_of(entry_id, &rt) {
            trace_error_exit(&e, 1);
        }
    } else {
        let entry_version   = rt.cli().value_of("version");
        let view_header     = rt.cli().is_present("view-header");
        let view_content    = rt.cli().is_present("view-content");

        let scmd = rt.cli().subcommand_matches("view-in");
        if scmd.is_none() {
            debug!("No commandline call");
            exit(1); // we can afford not-executing destructors here
        }
        let scmd = scmd.unwrap();

        let viewer = {
            if scmd.is_present("view-in-stdout") {
            } else if scmd.is_present("view-in-ui") {
                warn!("Viewing in UI is currently not supported, switch to stdout");
            } else if scmd.is_present("view-in-browser") {
                warn!("Viewing in browser is currently not supported, switch to stdout");
            } else if scmd.is_present("view-in-texteditor") {
                warn!("Viewing in texteditor is currently not supported, switch to stdout");
            } else if scmd.is_present("view-in-custom") {
                warn!("Viewing in custom is currently not supported, switch to stdout");
            }

            StdoutViewer::new(view_header, view_content)
        };

        let entry = load_entry(entry_id, entry_version, &rt);
        if entry.is_err() {
            trace_error_exit(&entry.unwrap_err(), 1);
        }
        let entry = entry.unwrap();

        if let Err(e) = viewer.view_entry(&entry) {
            trace_error(&e);
            exit(1);
        }
    }
}

// TODO: This is a shameless adaption of imag-store/src/util.rs
fn load_entry<'a>(id: &str,
                  version: Option<&str>,
                  rt: &'a Runtime)
    -> Result<FileLockEntry<'a>>
{
    debug!("Checking path element for version");

    let version = {
        if version.is_none() {
            let r = id.split('~').last();
            if r.is_none() {
                warn!("No version");
                return Err(ViewError::new(ViewErrorKind::NoVersion, None));
            } else {
                r.unwrap()
            }
        } else {
            version.unwrap()
        }
    };

    debug!("Building path from {:?} and {:?}", id, version);
    let mut path = rt.store().path().clone();

    if id.starts_with('/') {
        path.push(format!("{}~{}", &id[1..id.len()], version));
    } else {
        path.push(format!("{}~{}", id, version));
    }

    // the above is the adaption...

    rt.store().retrieve(path)
        .map_err(|e| ViewError::new(ViewErrorKind::StoreError, Some(Box::new(e))))
}

fn view_versions_of(id: &str, rt: &Runtime) -> Result<()> {
    use glob::glob;

    let mut path = rt.store().path().clone();

    if id.starts_with('/') {
        path.push(format!("{}~*", &id[1..id.len()]));
    } else {
        path.push(format!("{}~*", id));
    }

    if let Some(path) = path.to_str() {
        match glob(path) {
            Ok(paths) => {
                for entry in paths {
                    match entry {
                        Ok(path) => println!("{}", path.file_name().and_then(|s| s.to_str()).unwrap()),
                        Err(e)   => trace_error(e.error()),
                    }
                }
                Ok(())
            },
            Err(e) => {
                debug!("Error in pattern");
                Err(ViewError::new(ViewErrorKind::PatternError, Some(Box::new(e))))
            },
        }
    } else {
        warn!("Could not build glob() argument!");
        Err(ViewError::new(ViewErrorKind::GlobBuildError, None))
    }
}

<commit_msg>Rewrite main()<commit_after>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagentryview;
#[macro_use] extern crate libimagerror;

use std::process::exit;
use std::path::PathBuf;

use libimagrt::setup::generate_runtime_setup;
use libimagerror::trace::trace_error;
use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::builtin::versions::VersionsViewer;
use libimagentryview::viewer::Viewer;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup( "imag-view",
                                     &version!()[..],
                                     "View entries (readonly)",
                                     build_ui);

    let entry_id     = rt.cli().value_of("id").unwrap(); // enforced by clap
    let view_header  = rt.cli().is_present("view-header");
    let view_content = rt.cli().is_present("view-content");

    let scmd = match rt.cli().subcommand_matches("view-in") {
        None => {
            debug!("No commandline call");
            exit(1); // we can afford not-executing destructors here
        }
        Some(s) => s,
    };

    let entry = match rt.store().retrieve(PathBuf::from(entry_id)) {
        Ok(fle) => fle,
        Err(e) => {
            trace_error(&e);
            exit(1); // we can afford not-executing destructors here
        }
    };

    let res = if rt.cli().is_present("versions") {
        VersionsViewer::new(rt.store()).view_entry(&entry)
    } else {
        if scmd.is_present("view-in-stdout") {
        } else if scmd.is_present("view-in-ui") {
            warn!("Viewing in UI is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-browser") {
            warn!("Viewing in browser is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-texteditor") {
            warn!("Viewing in texteditor is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-custom") {
            warn!("Viewing in custom is currently not supported, switch to stdout");
        }

        StdoutViewer::new(view_header, view_content).view_entry(&entry)
    };

    if let Err(e) = res {
        trace_error(&e);
        exit(1);
    }
}

<|endoftext|>


<commit_before>//! Fundamental traits

use ndarray::*;
use ndarray_linalg::*;

pub trait ModelSize {
    type Dim: Dimension;
    fn model_size(&self) -> <Self::Dim as Dimension>::Pattern;
}

/// Calculate with mutable buffer to keep `&self` interface
///
/// `&mut self` interface is too limited since it cannot be combined
/// with other `&self` functions even if re-generate the caluculation buffer.
pub trait WithBuffer {
    /// mutable state of caluculation
    type Buffer;
    /// Generate new calculate buffer
    fn new_buffer(&self) -> Self::Buffer;
}

/// Interface for time-step
pub trait TimeStep {
    type Time: RealScalar;
    fn get_dt(&self) -> Self::Time;
    fn set_dt(&mut self, dt: Self::Time);
}

/// EoM for explicit schemes
pub trait Explicit: ModelSize {
    type Scalar: Scalar;
    /// calculate right hand side (rhs) of Explicit from current state
    fn rhs<'a, S>(&self, &'a mut ArrayBase<S, Self::Dim>) -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}

/// EoM for semi-implicit schemes
pub trait SemiImplicit: ModelSize {
    type Scalar: Scalar;
    /// non-linear part of stiff equation
    fn nlin<'a, S>(&self, &'a mut ArrayBase<S, Self::Dim>) -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}

/// EoM whose stiff linear part is diagonal
pub trait StiffDiagonal: SemiImplicit {
    /// diagonal elements of stiff linear part
    fn diag(&self) -> Array<Self::Scalar, Self::Dim>;
}

/// Time-evolution operator with buffer
pub trait TimeEvolution: WithBuffer + ModelSize {
    type Scalar: Scalar;
    /// calculate next step
    fn iterate<'a, S>(&self,
                      &'a mut ArrayBase<S, Self::Dim>,
                      &mut Self::Buffer)
                      -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}
<commit_msg>Add SemiImplicitBuf<commit_after>//! Fundamental traits

use ndarray::*;
use ndarray_linalg::*;

pub trait ModelSize {
    type Dim: Dimension;
    fn model_size(&self) -> <Self::Dim as Dimension>::Pattern;
}

/// Calculate with mutable buffer to keep `&self` interface
///
/// `&mut self` interface is too limited since it cannot be combined
/// with other `&self` functions even if re-generate the caluculation buffer.
pub trait WithBuffer {
    /// mutable state of caluculation
    type Buffer;
    /// Generate new calculate buffer
    fn new_buffer(&self) -> Self::Buffer;
}

/// Calculation can be done without buffer
pub type NoBuffer = ();

/// Interface for time-step
pub trait TimeStep {
    type Time: RealScalar;
    fn get_dt(&self) -> Self::Time;
    fn set_dt(&mut self, dt: Self::Time);
}

/// EoM for explicit schemes
pub trait Explicit: ModelSize {
    type Scalar: Scalar;
    /// calculate right hand side (rhs) of Explicit from current state
    fn rhs<'a, S>(&self, &'a mut ArrayBase<S, Self::Dim>) -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}

/// EoM for semi-implicit schemes
pub trait SemiImplicit: ModelSize {
    type Scalar: Scalar;
    /// non-linear part of stiff equation
    fn nlin<'a, S>(&self, &'a mut ArrayBase<S, Self::Dim>) -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}

/// EoM for semi-implicit schemes
pub trait SemiImplicitBuf: ModelSize + WithBuffer {
    type Scalar: Scalar;
    /// non-linear part of stiff equation
    fn nlin<'a, S>(&self,
                   &'a mut ArrayBase<S, Self::Dim>,
                   &mut Self::Buffer)
                   -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}

impl<F> SemiImplicitBuf for F
    where F: SemiImplicit + WithBuffer<Buffer = NoBuffer>
{
    type Scalar = F::Scalar;

    fn nlin<'a, S>(&self,
                   x: &'a mut ArrayBase<S, Self::Dim>,
                   _: &mut Self::Buffer)
                   -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>
    {
        self.nlin(x)
    }
}

/// EoM whose stiff linear part is diagonal
pub trait StiffDiagonal: SemiImplicit {
    /// diagonal elements of stiff linear part
    fn diag(&self) -> Array<Self::Scalar, Self::Dim>;
}

/// Time-evolution operator with buffer
pub trait TimeEvolution: WithBuffer + ModelSize {
    type Scalar: Scalar;
    /// calculate next step
    fn iterate<'a, S>(&self,
                      &'a mut ArrayBase<S, Self::Dim>,
                      &mut Self::Buffer)
                      -> &'a mut ArrayBase<S, Self::Dim>
        where S: DataMut<Elem = Self::Scalar>;
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

extern crate arguments;
extern crate hiredis;
extern crate mcpat;
extern crate sql;
extern crate sqlite;

/// Raise an error.
#[macro_export]
macro_rules! raise(
    ($message:expr) => (return Err($crate::Error::new($message)));
);

/// Unwrap a result or raise an error.
#[macro_export]
macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(result) => result,
            Err(error) => raise!(error),
        }
    );
);

mod result;
mod system;

pub mod database;
pub mod server;

pub use result::{Error, Result};
pub use system::System;
<commit_msg>A cosmetic change<commit_after>extern crate arguments;
extern crate hiredis;
extern crate mcpat;
extern crate sql;
extern crate sqlite;

#[macro_use]
extern crate log;

/// Raise an error.
#[macro_export]
macro_rules! raise(
    ($message:expr) => (return Err($crate::Error::new($message)));
);

/// Unwrap a result or raise an error.
#[macro_export]
macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(result) => result,
            Err(error) => raise!(error),
        }
    );
);

mod result;
mod system;

pub mod database;
pub mod server;

pub use result::{Error, Result};
pub use system::System;
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! dox

#![unstable(issue = "32838", feature = "allocator_api")]

#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
#[doc(inline)] pub use alloc_system::System;
#[doc(inline)] pub use core::alloc::*;

#[cfg(not(test))]
#[doc(hidden)]
#[lang = "oom"]
pub extern fn rust_oom(_: Layout) -> ! {
    rtabort!("memory allocation failed");
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
pub mod __default_lib_allocator {
    use super::{System, Layout, GlobalAlloc, Opaque};
    // for symbol names src/librustc/middle/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc(layout) as *mut u8
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
                                       size: usize,
                                       align: usize) {
        System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align))
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
                                       old_size: usize,
                                       align: usize,
                                       new_size: usize) -> *mut u8 {
        let old_layout = Layout::from_size_align_unchecked(old_size, align);
        System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc_zeroed(layout) as *mut u8
    }
}
<commit_msg>Add hooks allowing to override the `oom` behavior<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! dox

#![unstable(issue = "32838", feature = "allocator_api")]

#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
#[doc(inline)] pub use alloc_system::System;
#[doc(inline)] pub use core::alloc::*;

use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom OOM hook, replacing any that was previously registered.
///
/// The OOM hook is invoked when an infallible memory allocation fails.
/// The default hook prints a message to standard error and aborts the
/// execution, but this behavior can be customized with the [`set_oom_hook`]
/// and [`take_oom_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The OOM hook is a global resource.
pub fn set_oom_hook(hook: fn(Layout) -> !) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current OOM hook, returning it.
///
/// *See also the function [`set_oom_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
pub fn take_oom_hook() -> fn(Layout) -> ! {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() {
        default_oom_hook
    } else {
        unsafe { mem::transmute(hook) }
    }
}

fn default_oom_hook(layout: Layout) -> ! {
    rtabort!("memory allocation of {} bytes failed", layout.size())
}

#[cfg(not(test))]
#[doc(hidden)]
#[lang = "oom"]
pub extern fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) -> ! = if hook.is_null() {
        default_oom_hook
    } else {
        unsafe { mem::transmute(hook) }
    };
    hook(layout)
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
pub mod __default_lib_allocator {
    use super::{System, Layout, GlobalAlloc, Opaque};
    // for symbol names src/librustc/middle/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc(layout) as *mut u8
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
                                       size: usize,
                                       align: usize) {
        System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align))
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
                                       old_size: usize,
                                       align: usize,
                                       new_size: usize) -> *mut u8 {
        let old_layout = Layout::from_size_align_unchecked(old_size, align);
        System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc_zeroed(layout) as *mut u8
    }
}
<|endoftext|>


<commit_before>use glfw;
use std::libc;
use std::sys;
use std::str;
use std::ptr;
use std::cast;
use std::hashmap::HashMap;
// use glcore::*;
use glcore::consts::GL_VERSION_1_1::*;
use glcore::consts::GL_VERSION_1_5::*;
use glcore::consts::GL_VERSION_2_0::*;
use glcore::functions::GL_VERSION_1_0::*;
use glcore::functions::GL_VERSION_1_5::*;
use glcore::functions::GL_VERSION_2_0::*;
use glcore::functions::GL_VERSION_3_0::*;
use glcore::functions::GL_ARB_vertex_array_object::*;
use glcore::types::GL_VERSION_1_5::*;
use glcore::types::GL_VERSION_1_0::*;
use nalgebra::traits::transpose::Transpose;
use nalgebra::mat::Mat4;
use nalgebra::vec::Vec3;
use camera::{Camera, ArcBall};
use object::{GeometryIndices, Object};
use builtins::sphere_obj;
use builtins::cube_obj;
use builtins::cone_obj;
use builtins::cylinder_obj;
use obj;
use shaders::*;

pub enum Light
{
  Absolute(Vec3<GLfloat>),
  StickToCamera
}

pub struct Window
{
  priv objects:       ~[@mut Object],
  priv light:         i32,
  priv light_mode:    Light,
  priv window:        @mut glfw::Window,
  priv camera:        Camera,
  priv geometries:    HashMap<~str, GeometryIndices>,
  priv loop_callback: @fn(&mut Window)
}

impl Window
{
  pub fn add_cube(&mut self, wx: GLfloat, wy: GLfloat, wz: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"cube").unwrap(),
                               1.0, 1.0, 1.0,
                               wx, wy, wz);

    self.objects.push(res);

    res
  }

  pub fn add_sphere(&mut self, r: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"sphere").unwrap(),
                               0.3, 0.3, 0.3,
                               r / 0.5, r / 0.5, r / 0.5);

    self.objects.push(res);

    res
  }

  pub fn add_cone(&mut self, h: GLfloat, r: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"cone").unwrap(),
                               0.3, 0.3, 0.3,
                               r / 0.5, h, r / 0.5);

    self.objects.push(res);

    res
  }

  pub fn add_cylinder(&mut self, h: GLfloat, r: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"cylinder").unwrap(),
                               0.3, 0.3, 0.3,
                               r / 0.5, h, r / 0.5);

    self.objects.push(res);

    res
  }

  pub fn objects<'r>(&'r self) -> &'r ~[@mut Object]
  { &self.objects }

  pub fn exec_callback(&mut self)
  { (self.loop_callback)(self) }

  pub fn set_loop_callback(&mut self, callback: @fn(&mut Window))
  { self.loop_callback = callback }

  pub fn set_light(&mut self, pos: Light)
  {
    let camera_pos = self.camera.position();
    match pos
    {
      Absolute(p)   => self.set_light_pos(&p),
      StickToCamera => self.set_light_pos(&camera_pos)
    }

    self.light_mode = pos;
  }

  fn set_light_pos(&mut self, pos: &Vec3<GLfloat>)
  { unsafe { glUniform3f(self.light, pos.at[0], pos.at[1], pos.at[2]) } }

  // FIXME: this is not very well supported yet
  // FIXME: pub fn set_camera(&mut self, mode: CameraMode)
  // FIXME: { self.camera.set_mode(mode) }

  fn parse_builtins() -> (HashMap<~str, GeometryIndices>,
                          ~[GLfloat],
                          ~[GLfloat],
                          ~[GLuint])
  {
    // FIXME: this function is _really_ uggly.

    // load
    let (cv, cn, icv) = obj::parse(cube_obj::CUBE_OBJ);
    let (sv, sn, isv) = obj::parse(sphere_obj::SPHERE_OBJ);
    let (pv, pn, ipv) = obj::parse(cone_obj::CONE_OBJ);
    let (yv, yn, iyv) = obj::parse(cylinder_obj::CYLINDER_OBJ);

    let shift_isv = isv.map(|i| i + cv.len() / 3 as GLuint);
    let shift_ipv = ipv.map(|i| i + (sv.len() + cv.len()) / 3 as GLuint);
    let shift_iyv = iyv.map(|i| i + (sv.len() + cv.len() + pv.len()) / 3 as GLuint);

    // register draw informations
    let mut hmap = HashMap::new();

    hmap.insert(~"cube",   GeometryIndices::new(0, icv.len() as i32));
    hmap.insert(~"sphere", GeometryIndices::new(icv.len(), isv.len() as i32));
    hmap.insert(~"cone",   GeometryIndices::new(icv.len() + isv.len(), ipv.len() as i32));
    hmap.insert(~"cylinder", GeometryIndices::new(
        icv.len() + isv.len() + ipv.len(),
        iyv.len() as i32)
    );

    // concatenate everything
    (hmap,
     cv + sv + pv + yv,
     cn + sn + pn + yn,
     icv + shift_isv + shift_ipv + shift_iyv)
  }

  pub fn spawn(callback: ~fn(&mut Window))
  {
    glfw::set_error_callback(error_callback);

    do glfw::spawn {
      // The initialization is not really my code (see README)
      let window = @mut glfw::Window::create(800, 600, "kiss3d", glfw::Windowed).unwrap();

      window.make_context_current();

      unsafe {
        glFrontFace(GL_CCW);
        glEnable(GL_CULL_FACE);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
      }

      // Create Vertex Array Object
      let vao: GLuint = 0;
      unsafe {
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
      }

      let (builtins, vbuf, nbuf, vibuf) = Window::parse_builtins();

      // Create a Vertex Buffer Object and copy the vertex data to it
      let vertices_buf: GLuint = 0;
      unsafe {
        glGenBuffers(1, &vertices_buf);
        glBindBuffer(GL_ARRAY_BUFFER, vertices_buf);
        glBufferData(GL_ARRAY_BUFFER,
                     (vbuf.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                     cast::transmute(&vbuf[0]),
                     GL_STATIC_DRAW);
      }

      let vertices_index_buf: GLuint = 0;
      unsafe {
        glGenBuffers(1, &vertices_index_buf);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertices_index_buf);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                     (vibuf.len() * sys::size_of::<GLuint>()) as GLsizeiptr,
                     cast::transmute(&vibuf[0]),
                     GL_STATIC_DRAW);
      }

      // Create a Vertex Buffer Object and copy the vertex data to it
      let normals_buf: GLuint = 0;
      unsafe {
        glGenBuffers(1, &normals_buf);
        glBindBuffer(GL_ARRAY_BUFFER, normals_buf);
        glBufferData(GL_ARRAY_BUFFER,
                     (nbuf.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                     cast::transmute(&nbuf[0]),
                     GL_STATIC_DRAW);
      }

      // Create and compile the vertex shader
      let vertex_shader = unsafe { glCreateShader(GL_VERTEX_SHADER) };
      unsafe {
        glShaderSource(vertex_shader, 1, &str::as_c_str(VERTEX_SRC, |s|s), ptr::null());
        glCompileShader(vertex_shader);
      }

      // Create and compile the fragment shader
      let fragment_shader = unsafe { glCreateShader(GL_FRAGMENT_SHADER) };
      unsafe {
        glShaderSource(fragment_shader, 1, &str::as_c_str(FRAGMENT_SRC, |s|s), ptr::null());
        glCompileShader(fragment_shader);
      }

      // Link the vertex and fragment shader into a shader program
      let shader_program = unsafe { glCreateProgram() };
      unsafe {
        glAttachShader(shader_program, vertex_shader);
        glAttachShader(shader_program, fragment_shader);
        glBindFragDataLocation(shader_program, 0, str::as_c_str("outColor", |s|s));
        glLinkProgram(shader_program);
        glUseProgram(shader_program);
      }

      // Specify the layout of the vertex data
      let pos_attrib = unsafe { glGetAttribLocation(shader_program, str::as_c_str("position", |s| s)) } as GLuint;
      unsafe {
        glEnableVertexAttribArray(pos_attrib);
        glBindBuffer(GL_ARRAY_BUFFER, vertices_buf);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertices_index_buf);
        glVertexAttribPointer(pos_attrib,
                              3,
                              GL_FLOAT,
                              GL_FALSE,
                              3 * sys::size_of::<GLfloat>() as GLsizei,
                              ptr::null());
      }

      let normal_attrib = unsafe { glGetAttribLocation(shader_program, str::as_c_str("normal", |s| s)) } as GLuint;
      unsafe {
        glEnableVertexAttribArray(normal_attrib);
        glBindBuffer(GL_ARRAY_BUFFER, normals_buf);
        glVertexAttribPointer(normal_attrib,
                              3,
                              GL_FLOAT,
                              GL_FALSE,
                              3 * sys::size_of::<GLfloat>() as GLsizei,
                              ptr::null());
      }

      let light_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("light_position", |s| s))
      };

      let usr_window = @mut Window {
        objects:       ~[],
        window:        window,
        camera:        Camera::new(
                          ArcBall(Vec3::new([2.0, 2.0, 2.0]),
                                  Vec3::new([0.0, 0.0, 0.0]),
                                  40.0)
                       ),
        loop_callback: |_| {},
        light:         light_location,
        light_mode:    Absolute(Vec3::new([0.0, 10.0, 0.0])),
        geometries:    builtins
      };

      callback(usr_window);

      usr_window.set_light(usr_window.light_mode);

      let color_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("color", |s| s))
      };

      let transform_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("transform", |s| s))
      };

      let scale_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("scale", |s| s))
      };

      let normal_transform_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("ntransform", |s| s))
      };

      let proj_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("projection", |s| s))
      };

      let view_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("view", |s| s))
      };

      // setup callbacks
      window.set_size_callback(|win, w, h| { resize_callback(win, w as i32, h as i32, proj_location) });
      window.set_key_callback(|_, a, b, c, d| usr_window.key_callback(a, b, c, d));
      window.set_mouse_button_callback(|_, b, a, m| usr_window.mouse_button_callback(b, a, m));
      window.set_cursor_pos_callback(|_, xpos, ypos| usr_window.cursor_pos_callback(xpos, ypos));
      window.set_scroll_callback(|_, xoff, yoff| usr_window.scroll_callback(xoff, yoff));

      // unsafe { glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); }
      while !window.should_close() {
        // Poll events
        glfw::poll_events();

        usr_window.exec_callback();
        usr_window.camera.upload(view_location);

        match usr_window.light_mode
        {
          StickToCamera => usr_window.set_light(StickToCamera),
          _             => { }
        }

        // Clear the screen to black
        unsafe {
          glClearColor(0.0, 0.0, 0.0, 1.0);
          glClear(GL_COLOR_BUFFER_BIT);
          glClear(GL_DEPTH_BUFFER_BIT);

          for usr_window.objects.iter().advance |o|
          {
            o.upload(color_location,
                     transform_location,
                     scale_location,
                     normal_transform_location)
          }
        }

        // Swap buffers
        window.swap_buffers();
      }

      unsafe {
        glDeleteProgram(shader_program);
        glDeleteShader(fragment_shader);
        glDeleteShader(vertex_shader);

        glDeleteBuffers(1, &vertices_buf);
        glDeleteBuffers(1, &normals_buf);

        glDeleteVertexArrays(1, &vao);
      }
    }
  }

  fn key_callback(&mut self,
                  key:    libc::c_int,
                  _:      libc::c_int,
                  action: libc::c_int,
                  _:      libc::c_int)
  {
      if action == glfw::PRESS && key == glfw::KEY_ESCAPE
      { self.window.set_should_close(true); }

      self.camera.handle_keyboard(key as int, action as int);
  }

  fn cursor_pos_callback(&mut self, xpos: float, ypos: float)
  { self.camera.handle_cursor_pos(xpos, ypos); }

  fn scroll_callback(&mut self, xoff: float, yoff: float)
  { self.camera.handle_scroll(xoff, yoff); }

  fn mouse_button_callback(&mut self,
                           button: libc::c_int,
                           action: libc::c_int,
                           mods:   libc::c_int)
  { self.camera.handle_mouse_button(button as int, action as int, mods as int); }
}

fn resize_callback(_: &glfw::Window, w: i32, h: i32, proj_location: i32)
{
  let fov    = (90.0 as GLfloat).to_radians();
  let aspect = w as GLfloat / (h as GLfloat);
  let zfar   = 1024.0;
  let znear  = 0.1;

  // adjust the viewport to the full window
  unsafe { glViewport(0, 0, w, h) }

  // adjust the projection transformation
  let mut proj = Mat4::new::<GLfloat>(
    [
      fov / aspect, 0.0,  0.0                            , 0.0,
      0.0         , fov, 0.0                             , 0.0,
      0.0         , 0.0,  (zfar + znear) / (znear - zfar), 2.0 * zfar * znear / (znear - zfar),
      0.0         , 0.0,  -1.0                           , 0.0
    ]);

  proj.transpose();

  unsafe {
    glUniformMatrix4fv(proj_location,
                       1,
                       GL_FALSE,
                       ptr::to_unsafe_ptr(&proj.mij[0]));
  }
}

fn error_callback(_: libc::c_int, description: ~str)
{ println(fmt!("Kiss3d Error: %s", description)); }
<commit_msg>Fix black display due to missing window resizing at the beginning.<commit_after>use glfw;
use std::libc;
use std::sys;
use std::str;
use std::ptr;
use std::cast;
use std::hashmap::HashMap;
// use glcore::*;
use glcore::consts::GL_VERSION_1_1::*;
use glcore::consts::GL_VERSION_1_5::*;
use glcore::consts::GL_VERSION_2_0::*;
use glcore::functions::GL_VERSION_1_0::*;
use glcore::functions::GL_VERSION_1_5::*;
use glcore::functions::GL_VERSION_2_0::*;
use glcore::functions::GL_VERSION_3_0::*;
use glcore::functions::GL_ARB_vertex_array_object::*;
use glcore::types::GL_VERSION_1_5::*;
use glcore::types::GL_VERSION_1_0::*;
use nalgebra::traits::transpose::Transpose;
use nalgebra::mat::Mat4;
use nalgebra::vec::Vec3;
use camera::{Camera, ArcBall};
use object::{GeometryIndices, Object};
use builtins::sphere_obj;
use builtins::cube_obj;
use builtins::cone_obj;
use builtins::cylinder_obj;
use obj;
use shaders::*;

pub enum Light
{
  Absolute(Vec3<GLfloat>),
  StickToCamera
}

pub struct Window
{
  priv objects:       ~[@mut Object],
  priv light:         i32,
  priv light_mode:    Light,
  priv window:        @mut glfw::Window,
  priv camera:        Camera,
  priv geometries:    HashMap<~str, GeometryIndices>,
  priv loop_callback: @fn(&mut Window)
}

impl Window
{
  pub fn add_cube(&mut self, wx: GLfloat, wy: GLfloat, wz: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"cube").unwrap(),
                               1.0, 1.0, 1.0,
                               wx, wy, wz);

    self.objects.push(res);

    res
  }

  pub fn add_sphere(&mut self, r: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"sphere").unwrap(),
                               0.3, 0.3, 0.3,
                               r / 0.5, r / 0.5, r / 0.5);

    self.objects.push(res);

    res
  }

  pub fn add_cone(&mut self, h: GLfloat, r: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"cone").unwrap(),
                               0.3, 0.3, 0.3,
                               r / 0.5, h, r / 0.5);

    self.objects.push(res);

    res
  }

  pub fn add_cylinder(&mut self, h: GLfloat, r: GLfloat) -> @mut Object
  {
    let res = @mut Object::new(*self.geometries.find(&~"cylinder").unwrap(),
                               0.3, 0.3, 0.3,
                               r / 0.5, h, r / 0.5);

    self.objects.push(res);

    res
  }

  pub fn objects<'r>(&'r self) -> &'r ~[@mut Object]
  { &self.objects }

  pub fn exec_callback(&mut self)
  { (self.loop_callback)(self) }

  pub fn set_loop_callback(&mut self, callback: @fn(&mut Window))
  { self.loop_callback = callback }

  pub fn set_light(&mut self, pos: Light)
  {
    let camera_pos = self.camera.position();
    match pos
    {
      Absolute(p)   => self.set_light_pos(&p),
      StickToCamera => self.set_light_pos(&camera_pos)
    }

    self.light_mode = pos;
  }

  fn set_light_pos(&mut self, pos: &Vec3<GLfloat>)
  { unsafe { glUniform3f(self.light, pos.at[0], pos.at[1], pos.at[2]) } }

  // FIXME: this is not very well supported yet
  // FIXME: pub fn set_camera(&mut self, mode: CameraMode)
  // FIXME: { self.camera.set_mode(mode) }

  fn parse_builtins() -> (HashMap<~str, GeometryIndices>,
                          ~[GLfloat],
                          ~[GLfloat],
                          ~[GLuint])
  {
    // FIXME: this function is _really_ uggly.

    // load
    let (cv, cn, icv) = obj::parse(cube_obj::CUBE_OBJ);
    let (sv, sn, isv) = obj::parse(sphere_obj::SPHERE_OBJ);
    let (pv, pn, ipv) = obj::parse(cone_obj::CONE_OBJ);
    let (yv, yn, iyv) = obj::parse(cylinder_obj::CYLINDER_OBJ);

    let shift_isv = isv.map(|i| i + cv.len() / 3 as GLuint);
    let shift_ipv = ipv.map(|i| i + (sv.len() + cv.len()) / 3 as GLuint);
    let shift_iyv = iyv.map(|i| i + (sv.len() + cv.len() + pv.len()) / 3 as GLuint);

    // register draw informations
    let mut hmap = HashMap::new();

    hmap.insert(~"cube",   GeometryIndices::new(0, icv.len() as i32));
    hmap.insert(~"sphere", GeometryIndices::new(icv.len(), isv.len() as i32));
    hmap.insert(~"cone",   GeometryIndices::new(icv.len() + isv.len(), ipv.len() as i32));
    hmap.insert(~"cylinder", GeometryIndices::new(
        icv.len() + isv.len() + ipv.len(),
        iyv.len() as i32)
    );

    // concatenate everything
    (hmap,
     cv + sv + pv + yv,
     cn + sn + pn + yn,
     icv + shift_isv + shift_ipv + shift_iyv)
  }

  pub fn spawn(callback: ~fn(&mut Window))
  {
    glfw::set_error_callback(error_callback);

    do glfw::spawn {
      // The initialization is not really my code (see README)
      let window = @mut glfw::Window::create(800, 600, "kiss3d", glfw::Windowed).unwrap();

      window.make_context_current();

      unsafe {
        glFrontFace(GL_CCW);
        glEnable(GL_CULL_FACE);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
      }

      // Create Vertex Array Object
      let vao: GLuint = 0;
      unsafe {
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
      }

      let (builtins, vbuf, nbuf, vibuf) = Window::parse_builtins();

      // Create a Vertex Buffer Object and copy the vertex data to it
      let vertices_buf: GLuint = 0;
      unsafe {
        glGenBuffers(1, &vertices_buf);
        glBindBuffer(GL_ARRAY_BUFFER, vertices_buf);
        glBufferData(GL_ARRAY_BUFFER,
                     (vbuf.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                     cast::transmute(&vbuf[0]),
                     GL_STATIC_DRAW);
      }

      let vertices_index_buf: GLuint = 0;
      unsafe {
        glGenBuffers(1, &vertices_index_buf);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertices_index_buf);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                     (vibuf.len() * sys::size_of::<GLuint>()) as GLsizeiptr,
                     cast::transmute(&vibuf[0]),
                     GL_STATIC_DRAW);
      }

      // Create a Vertex Buffer Object and copy the vertex data to it
      let normals_buf: GLuint = 0;
      unsafe {
        glGenBuffers(1, &normals_buf);
        glBindBuffer(GL_ARRAY_BUFFER, normals_buf);
        glBufferData(GL_ARRAY_BUFFER,
                     (nbuf.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                     cast::transmute(&nbuf[0]),
                     GL_STATIC_DRAW);
      }

      // Create and compile the vertex shader
      let vertex_shader = unsafe { glCreateShader(GL_VERTEX_SHADER) };
      unsafe {
        glShaderSource(vertex_shader, 1, &str::as_c_str(VERTEX_SRC, |s|s), ptr::null());
        glCompileShader(vertex_shader);
      }

      // Create and compile the fragment shader
      let fragment_shader = unsafe { glCreateShader(GL_FRAGMENT_SHADER) };
      unsafe {
        glShaderSource(fragment_shader, 1, &str::as_c_str(FRAGMENT_SRC, |s|s), ptr::null());
        glCompileShader(fragment_shader);
      }

      // Link the vertex and fragment shader into a shader program
      let shader_program = unsafe { glCreateProgram() };
      unsafe {
        glAttachShader(shader_program, vertex_shader);
        glAttachShader(shader_program, fragment_shader);
        glBindFragDataLocation(shader_program, 0, str::as_c_str("outColor", |s|s));
        glLinkProgram(shader_program);
        glUseProgram(shader_program);
      }

      // Specify the layout of the vertex data
      let pos_attrib = unsafe { glGetAttribLocation(shader_program, str::as_c_str("position", |s| s)) } as GLuint;
      unsafe {
        glEnableVertexAttribArray(pos_attrib);
        glBindBuffer(GL_ARRAY_BUFFER, vertices_buf);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertices_index_buf);
        glVertexAttribPointer(pos_attrib,
                              3,
                              GL_FLOAT,
                              GL_FALSE,
                              3 * sys::size_of::<GLfloat>() as GLsizei,
                              ptr::null());
      }

      let normal_attrib = unsafe { glGetAttribLocation(shader_program, str::as_c_str("normal", |s| s)) } as GLuint;
      unsafe {
        glEnableVertexAttribArray(normal_attrib);
        glBindBuffer(GL_ARRAY_BUFFER, normals_buf);
        glVertexAttribPointer(normal_attrib,
                              3,
                              GL_FLOAT,
                              GL_FALSE,
                              3 * sys::size_of::<GLfloat>() as GLsizei,
                              ptr::null());
      }

      let light_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("light_position", |s| s))
      };

      let usr_window = @mut Window {
        objects:       ~[],
        window:        window,
        camera:        Camera::new(
                          ArcBall(Vec3::new([2.0, 2.0, 2.0]),
                                  Vec3::new([0.0, 0.0, 0.0]),
                                  40.0)
                       ),
        loop_callback: |_| {},
        light:         light_location,
        light_mode:    Absolute(Vec3::new([0.0, 10.0, 0.0])),
        geometries:    builtins
      };

      callback(usr_window);

      usr_window.set_light(usr_window.light_mode);

      let color_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("color", |s| s))
      };

      let transform_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("transform", |s| s))
      };

      let scale_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("scale", |s| s))
      };

      let normal_transform_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("ntransform", |s| s))
      };

      let proj_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("projection", |s| s))
      };

      let view_location = unsafe {
        glGetUniformLocation(shader_program, str::as_c_str("view", |s| s))
      };

      // setup callbacks
      window.set_size_callback(|win, w, h| { resize_callback(win, w as i32, h as i32, proj_location) });
      window.set_key_callback(|_, a, b, c, d| usr_window.key_callback(a, b, c, d));
      window.set_mouse_button_callback(|_, b, a, m| usr_window.mouse_button_callback(b, a, m));
      window.set_cursor_pos_callback(|_, xpos, ypos| usr_window.cursor_pos_callback(xpos, ypos));
      window.set_scroll_callback(|_, xoff, yoff| usr_window.scroll_callback(xoff, yoff));

      resize_callback(window, 800, 600, proj_location);

      // unsafe { glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); }
      while !window.should_close() {
        // Poll events
        glfw::poll_events();

        usr_window.exec_callback();
        usr_window.camera.upload(view_location);

        match usr_window.light_mode
        {
          StickToCamera => usr_window.set_light(StickToCamera),
          _             => { }
        }

        // Clear the screen to black
        unsafe {
          glClearColor(0.0, 0.0, 0.0, 1.0);
          glClear(GL_COLOR_BUFFER_BIT);
          glClear(GL_DEPTH_BUFFER_BIT);

          for usr_window.objects.iter().advance |o|
          {
            o.upload(color_location,
                     transform_location,
                     scale_location,
                     normal_transform_location)
          }
        }

        // Swap buffers
        window.swap_buffers();
      }

      unsafe {
        glDeleteProgram(shader_program);
        glDeleteShader(fragment_shader);
        glDeleteShader(vertex_shader);

        glDeleteBuffers(1, &vertices_buf);
        glDeleteBuffers(1, &normals_buf);

        glDeleteVertexArrays(1, &vao);
      }
    }
  }

  fn key_callback(&mut self,
                  key:    libc::c_int,
                  _:      libc::c_int,
                  action: libc::c_int,
                  _:      libc::c_int)
  {
      if action == glfw::PRESS && key == glfw::KEY_ESCAPE
      { self.window.set_should_close(true); }

      self.camera.handle_keyboard(key as int, action as int);
  }

  fn cursor_pos_callback(&mut self, xpos: float, ypos: float)
  { self.camera.handle_cursor_pos(xpos, ypos); }

  fn scroll_callback(&mut self, xoff: float, yoff: float)
  { self.camera.handle_scroll(xoff, yoff); }

  fn mouse_button_callback(&mut self,
                           button: libc::c_int,
                           action: libc::c_int,
                           mods:   libc::c_int)
  { self.camera.handle_mouse_button(button as int, action as int, mods as int); }
}

fn resize_callback(_: &glfw::Window, w: i32, h: i32, proj_location: i32)
{
  let fov    = (90.0 as GLfloat).to_radians();
  let aspect = w as GLfloat / (h as GLfloat);
  let zfar   = 1024.0;
  let znear  = 0.1;

  // adjust the viewport to the full window
  unsafe { glViewport(0, 0, w, h) }

  // adjust the projection transformation
  let mut proj = Mat4::new::<GLfloat>(
    [
      fov / aspect, 0.0,  0.0                            , 0.0,
      0.0         , fov, 0.0                             , 0.0,
      0.0         , 0.0,  (zfar + znear) / (znear - zfar), 2.0 * zfar * znear / (znear - zfar),
      0.0         , 0.0,  -1.0                           , 0.0
    ]);

  proj.transpose();

  unsafe {
    glUniformMatrix4fv(proj_location,
                       1,
                       GL_FALSE,
                       ptr::to_unsafe_ptr(&proj.mij[0]));
  }
}

fn error_callback(_: libc::c_int, description: ~str)
{ println(fmt!("Kiss3d Error: %s", description)); }
<|endoftext|>