<commit_before>use amq_protocol::frame::{GenError, Offset, gen_frame, parse_frame};
use log::{error, trace};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use parking_lot::Mutex;

use std::{
  io::{self, Read, Write},
  sync::{
    Arc,
    atomic::{AtomicBool, Ordering},
  },
  thread::{self, Builder as ThreadBuilder, JoinHandle},
  time::{Duration, Instant},
};

use crate::{
  buffer::Buffer,
  connection::Connection,
  connection_status::ConnectionState,
  error::{Error, ErrorKind},
};

const SOCKET:   Token = Token(1);
const DATA:     Token = Token(2);
const CONTINUE: Token = Token(3);

const FRAMES_STORAGE: usize = 32;

#[derive(Clone, Debug)]
pub(crate) struct IoLoopHandle {
  handle: Arc<Mutex<Option<JoinHandle<Result<(), Error>>>>>,
}

impl Default for IoLoopHandle {
  fn default() -> Self {
    Self { handle: Arc::new(Mutex::new(None)) }
  }
}

impl IoLoopHandle {
  pub(crate) fn register(&self, handle: JoinHandle<Result<(), Error>>) {
    *self.handle.lock() = Some(handle);
  }

  pub(crate) fn wait(&self) -> Result<(), Error> {
    if let Some(handle) = self.handle.lock().take() {
      handle.join().expect("io loop")?
    }
    Ok(())
  }
}

#[derive(Debug, PartialEq)]
enum Status {
  Initial,
  Setup,
  Stop,
}

pub struct IoLoop<T> {
  connection:     Connection,
  socket:         T,
  status:         Status,
  poll:           Poll,
  registration:   Registration,
  set_readiness:  SetReadiness,
  hb_handle:      Option<JoinHandle<()>>,
  frame_size:     usize,
  receive_buffer: Buffer,
  send_buffer:    Buffer,
  can_write:      bool,
  can_read:       bool,
  has_data:       bool,
  send_heartbeat: Arc<AtomicBool>,
  poll_timeout:   Option<Duration>,
}

impl<T: Evented + Read + Write + Send + 'static> IoLoop<T> {
  pub(crate) fn new(connection: Connection, socket: T) -> Result<Self, Error> {
    let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
    let (registration, set_readiness) = Registration::new2();
    let inner = Self {
      connection,
      socket,
      status:         Status::Initial,
      poll:           Poll::new().map_err(ErrorKind::IOError)?,
      registration,
      set_readiness,
      hb_handle:      None,
      frame_size,
      receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      send_buffer:    Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      can_write:      false,
      can_read:       false,
      has_data:       false,
      send_heartbeat: Arc::new(AtomicBool::new(false)),
      poll_timeout:   None,
    };
    inner.poll.register(&inner.socket, SOCKET, Ready::all(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.connection, DATA, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.registration, CONTINUE, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    Ok(inner)
  }

  fn start_heartbeat(&mut self, interval: Duration) -> Result<(), Error> {
    let connection    = self.connection.clone();
    let send_hartbeat = self.send_heartbeat.clone();
    let hb_handle = ThreadBuilder::new().name("heartbeat".to_owned()).spawn(move || {
      while connection.status().connected() {
        let start         = Instant::now();
        let mut remaining = interval;

        loop {
          thread::park_timeout(remaining);
          let elapsed = start.elapsed();
          if elapsed >= remaining {
            break
          }
          remaining -= interval - elapsed;
        }

        send_hartbeat.store(true, Ordering::Relaxed);
      }
    }).map_err(ErrorKind::IOError)?;
    self.hb_handle = Some(hb_handle);
    Ok(())
  }

  fn heartbeat(&mut self) -> Result<(), Error> {
    trace!("send heartbeat");
    self.connection.send_heartbeat()?;
    self.send_heartbeat.store(false, Ordering::Relaxed);
    Ok(())
  }

  fn ensure_setup(&mut self) -> Result<(), Error> {
    if self.status != Status::Setup && self.connection.status().connected() {
      let frame_max = self.connection.configuration().frame_max() as usize;
      self.frame_size = std::cmp::max(self.frame_size, frame_max);
      self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
      self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
      let heartbeat = self.connection.configuration().heartbeat();
      if heartbeat != 0 {
        trace!("io_loop: start heartbeat");
        let heartbeat = Duration::from_secs(heartbeat as u64);
        self.start_heartbeat(heartbeat)?;
        self.poll_timeout = Some(heartbeat);
        trace!("io_loop: heartbeat started");
      }
      self.status = Status::Setup;
    }
    Ok(())
  }

  fn wants_to_write(&self) -> bool {
    self.can_write && self.has_data
  }

  fn wants_to_read(&self) -> bool {
    self.can_read
  }

  fn should_continue(&self) -> bool {
    let connection_status = self.connection.status();
    (self.status == Status::Initial || connection_status.connected() || connection_status.closing()) && self.status != Status::Stop && !connection_status.errored()
  }

  pub fn run(mut self) -> Result<(), Error> {
    self.connection.clone().set_io_loop(ThreadBuilder::new().name("io_loop".to_owned()).spawn(move || {
      let mut events = Events::with_capacity(1024);
      while self.should_continue() {
        self.do_run(&mut events)?;
      }
      if let Some(hb_handle) = self.hb_handle.take() {
        hb_handle.thread().unpark();
        hb_handle.join().expect("heartbeat loop failed");
      }
      Ok(())
    }).map_err(ErrorKind::IOError)?);
    Ok(())
  }

  fn do_run(&mut self, events: &mut Events) -> Result<(), Error> {
    // First, update our internal state
    trace!("io_loop run");
    self.ensure_setup()?;
    trace!("io_loop poll");
    self.poll.poll(events, self.poll_timeout).map_err(ErrorKind::IOError)?;
    trace!("io_loop poll done");
    for event in events.iter() {
      match event.token() {
        SOCKET    => {
          if event.readiness().is_readable() {
            self.can_read = true;
          }
          if event.readiness().is_writable() {
            self.can_write = true;
          }
        },
        DATA      => self.has_data = true,
        _         => {},
      }
    }

    // Then, actually run an iteration of the event loop
    trace!("io_loop do_run; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
    loop {
      if self.send_heartbeat.load(Ordering::Relaxed) {
        self.heartbeat()?;
      }
      if self.wants_to_write() && !self.connection.status().blocked() {
        if let Err(e) = self.write_to_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_write = false,
            _ => {
              error!("error writing: {:?}", e);
              if let ConnectionState::SentProtocolHeader(wait_handle, ..) = self.connection.status().state() {
                wait_handle.error(ErrorKind::ConnectionRefused.into());
                self.status = Status::Stop;
              }
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.send_buffer.shift_unless_available(self.frame_size);
      }
      if self.connection.status().closed() {
        self.status = Status::Stop;
      }
      if self.should_continue() && self.wants_to_read() {
        if let Err(e) = self.read_from_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_read = false,
            _ => {
              error!("error reading: {:?}", e);
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.receive_buffer.shift_unless_available(self.frame_size);
      }
      if self.can_parse() {
        self.parse()?;
      }
      if !self.wants_to_read() || !self.wants_to_write() || self.status == Status::Stop || self.connection.status().errored() || self.connection.status().blocked() {
        if self.status != Status::Stop && !self.connection.status().blocked() && (self.wants_to_read() || self.can_parse() || self.wants_to_write()) {
          trace!("io_loop send continue; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
          self.set_readiness.set_readiness(Ready::readable()).map_err(ErrorKind::IOError)?;
        }
        break;
      }
    }
    trace!("io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}", self.can_read, self.can_write, self.has_data, self.status);
    Ok(())
  }

  fn can_parse(&self) -> bool {
    self.receive_buffer.available_data() > 0
  }

  fn write_to_stream(&mut self) -> Result<(), Error> {
    self.serialize()?;

    self.socket.write(&self.send_buffer.data()).map(|sz| {
      trace!("wrote {} bytes", sz);
      self.send_buffer.consume(sz);
    }).map_err(|e| ErrorKind::IOError(e).into())
  }

  fn read_from_stream(&mut self) -> Result<(), Error> {
    match self.connection.status().state() {
      ConnectionState::Closed => Ok(()),
      ConnectionState::Error  => Err(ErrorKind::InvalidConnectionState(ConnectionState::Error).into()),
      _                       => self.socket.read(&mut self.receive_buffer.space()).map(|sz| {
        trace!("read {} bytes", sz);
        self.receive_buffer.fill(sz);
      }).map_err(|e| ErrorKind::IOError(e).into()),
    }
  }

  fn serialize(&mut self) -> Result<(), Error> {
    if let Some((send_id, next_msg)) = self.connection.next_frame() {
      trace!("will write to buffer: {:?}", next_msg);
      match gen_frame(self.send_buffer.space(), &next_msg).map(|tup| tup.0) {
        Ok(sz) => {
          self.send_buffer.fill(sz);
          self.connection.mark_sent(send_id);
          Ok(())
        },
        Err(e) => {
          match e {
            GenError::BufferTooSmall(_) => {
              // Requeue msg
              self.connection.requeue_frame(send_id, next_msg)?;
              self.send_buffer.shift();
              Ok(())
            },
            GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
              error!("error generating frame: {:?}", e);
              self.connection.set_error()?;
              Err(ErrorKind::SerialisationError(e).into())
            }
          }
        }
      }
    } else {
      self.has_data = false;
      Ok(())
    }
  }

  fn parse(&mut self) -> Result<(), Error> {
    match parse_frame(self.receive_buffer.data()) {
      Ok((i, f)) => {
        let consumed = self.receive_buffer.data().offset(i);
        self.receive_buffer.consume(consumed);

        if let Err(e) = self.connection.handle_frame(f) {
          self.connection.set_error()?;
          Err(e)
        } else {
          Ok(())
        }
      },
      Err(e) => {
        if e.is_incomplete() {
          self.receive_buffer.shift();
          Ok(())
        } else {
          error!("parse error: {:?}", e);
          self.connection.set_error()?;
          Err(ErrorKind::ParsingError(format!("{:?}", e)).into())
        }
      }
    }
  }
}
<commit_msg>io_loop: refactor blocked connection handling and rename methods<commit_after>use amq_protocol::frame::{GenError, Offset, gen_frame, parse_frame};
use log::{error, trace};
use mio::{Evented, Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use parking_lot::Mutex;

use std::{
  io::{self, Read, Write},
  sync::{
    Arc,
    atomic::{AtomicBool, Ordering},
  },
  thread::{self, Builder as ThreadBuilder, JoinHandle},
  time::{Duration, Instant},
};

use crate::{
  buffer::Buffer,
  connection::Connection,
  connection_status::ConnectionState,
  error::{Error, ErrorKind},
};

const SOCKET:   Token = Token(1);
const DATA:     Token = Token(2);
const CONTINUE: Token = Token(3);

const FRAMES_STORAGE: usize = 32;

#[derive(Clone, Debug)]
pub(crate) struct IoLoopHandle {
  handle: Arc<Mutex<Option<JoinHandle<Result<(), Error>>>>>,
}

impl Default for IoLoopHandle {
  fn default() -> Self {
    Self { handle: Arc::new(Mutex::new(None)) }
  }
}

impl IoLoopHandle {
  pub(crate) fn register(&self, handle: JoinHandle<Result<(), Error>>) {
    *self.handle.lock() = Some(handle);
  }

  pub(crate) fn wait(&self) -> Result<(), Error> {
    if let Some(handle) = self.handle.lock().take() {
      handle.join().expect("io loop")?
    }
    Ok(())
  }
}

#[derive(Debug, PartialEq)]
enum Status {
  Initial,
  Setup,
  Stop,
}

pub struct IoLoop<T> {
  connection:     Connection,
  socket:         T,
  status:         Status,
  poll:           Poll,
  registration:   Registration,
  set_readiness:  SetReadiness,
  hb_handle:      Option<JoinHandle<()>>,
  frame_size:     usize,
  receive_buffer: Buffer,
  send_buffer:    Buffer,
  can_write:      bool,
  can_read:       bool,
  has_data:       bool,
  send_heartbeat: Arc<AtomicBool>,
  poll_timeout:   Option<Duration>,
}

impl<T: Evented + Read + Write + Send + 'static> IoLoop<T> {
  pub(crate) fn new(connection: Connection, socket: T) -> Result<Self, Error> {
    let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
    let (registration, set_readiness) = Registration::new2();
    let inner = Self {
      connection,
      socket,
      status:         Status::Initial,
      poll:           Poll::new().map_err(ErrorKind::IOError)?,
      registration,
      set_readiness,
      hb_handle:      None,
      frame_size,
      receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      send_buffer:    Buffer::with_capacity(FRAMES_STORAGE * frame_size),
      can_write:      false,
      can_read:       false,
      has_data:       false,
      send_heartbeat: Arc::new(AtomicBool::new(false)),
      poll_timeout:   None,
    };
    inner.poll.register(&inner.socket, SOCKET, Ready::all(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.connection, DATA, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    inner.poll.register(&inner.registration, CONTINUE, Ready::readable(), PollOpt::edge()).map_err(ErrorKind::IOError)?;
    Ok(inner)
  }

  fn start_heartbeat(&mut self, interval: Duration) -> Result<(), Error> {
    let connection    = self.connection.clone();
    let send_hartbeat = self.send_heartbeat.clone();
    let hb_handle = ThreadBuilder::new().name("heartbeat".to_owned()).spawn(move || {
      while connection.status().connected() {
        let start         = Instant::now();
        let mut remaining = interval;

        loop {
          thread::park_timeout(remaining);
          let elapsed = start.elapsed();
          if elapsed >= remaining {
            break
          }
          remaining -= interval - elapsed;
        }

        send_hartbeat.store(true, Ordering::Relaxed);
      }
    }).map_err(ErrorKind::IOError)?;
    self.hb_handle = Some(hb_handle);
    Ok(())
  }

  fn heartbeat(&mut self) -> Result<(), Error> {
    trace!("send heartbeat");
    self.connection.send_heartbeat()?;
    self.send_heartbeat.store(false, Ordering::Relaxed);
    Ok(())
  }

  fn ensure_setup(&mut self) -> Result<(), Error> {
    if self.status != Status::Setup && self.connection.status().connected() {
      let frame_max = self.connection.configuration().frame_max() as usize;
      self.frame_size = std::cmp::max(self.frame_size, frame_max);
      self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
      self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
      let heartbeat = self.connection.configuration().heartbeat();
      if heartbeat != 0 {
        trace!("io_loop: start heartbeat");
        let heartbeat = Duration::from_secs(heartbeat as u64);
        self.start_heartbeat(heartbeat)?;
        self.poll_timeout = Some(heartbeat);
        trace!("io_loop: heartbeat started");
      }
      self.status = Status::Setup;
    }
    Ok(())
  }

  fn can_write(&self) -> bool {
    self.can_write && self.has_data && !self.connection.status().blocked()
  }

  fn can_read(&self) -> bool {
    self.can_read
  }

  fn can_parse(&self) -> bool {
    self.receive_buffer.available_data() > 0
  }

  fn should_continue(&self) -> bool {
    let connection_status = self.connection.status();
    (self.status == Status::Initial || connection_status.connected() || connection_status.closing()) && self.status != Status::Stop && !connection_status.errored()
  }

  pub fn run(mut self) -> Result<(), Error> {
    self.connection.clone().set_io_loop(ThreadBuilder::new().name("io_loop".to_owned()).spawn(move || {
      let mut events = Events::with_capacity(1024);
      while self.should_continue() {
        self.do_run(&mut events)?;
      }
      if let Some(hb_handle) = self.hb_handle.take() {
        hb_handle.thread().unpark();
        hb_handle.join().expect("heartbeat loop failed");
      }
      Ok(())
    }).map_err(ErrorKind::IOError)?);
    Ok(())
  }

  fn do_run(&mut self, events: &mut Events) -> Result<(), Error> {
    // First, update our internal state
    trace!("io_loop run");
    self.ensure_setup()?;
    trace!("io_loop poll");
    self.poll.poll(events, self.poll_timeout).map_err(ErrorKind::IOError)?;
    trace!("io_loop poll done");
    for event in events.iter() {
      match event.token() {
        SOCKET    => {
          if event.readiness().is_readable() {
            self.can_read = true;
          }
          if event.readiness().is_writable() {
            self.can_write = true;
          }
        },
        DATA      => self.has_data = true,
        _         => {},
      }
    }

    // Then, actually run an iteration of the event loop
    trace!("io_loop do_run; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
    loop {
      if self.send_heartbeat.load(Ordering::Relaxed) {
        self.heartbeat()?;
      }
      if self.can_write() {
        if let Err(e) = self.write_to_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_write = false,
            _ => {
              error!("error writing: {:?}", e);
              if let ConnectionState::SentProtocolHeader(wait_handle, ..) = self.connection.status().state() {
                wait_handle.error(ErrorKind::ConnectionRefused.into());
                self.status = Status::Stop;
              }
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.send_buffer.shift_unless_available(self.frame_size);
      }
      if self.connection.status().closed() {
        self.status = Status::Stop;
      }
      if self.should_continue() && self.can_read() {
        if let Err(e) = self.read_from_stream() {
          match e.kind() {
            ErrorKind::IOError(e) if e.kind() == io::ErrorKind::WouldBlock => self.can_read = false,
            _ => {
              error!("error reading: {:?}", e);
              self.connection.set_error()?;
              return Err(e);
            }
          }
        }
        self.receive_buffer.shift_unless_available(self.frame_size);
      }
      if self.can_parse() {
        self.parse()?;
      }
      if !self.can_read() || !self.can_write() || self.status == Status::Stop || self.connection.status().errored() {
        if self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write()) {
          trace!("io_loop send continue; can_read={}, can_write={}, has_data={}", self.can_read, self.can_write, self.has_data);
          self.send_continue()?;
        }
        break;
      }
    }
    trace!("io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}", self.can_read, self.can_write, self.has_data, self.status);
    Ok(())
  }

  fn send_continue(&mut self) -> Result<(), Error> {
    self.set_readiness.set_readiness(Ready::readable()).map_err(ErrorKind::IOError)?;
    Ok(())
  }

  fn write_to_stream(&mut self) -> Result<(), Error> {
    self.serialize()?;

    self.socket.write(&self.send_buffer.data()).map(|sz| {
      trace!("wrote {} bytes", sz);
      self.send_buffer.consume(sz);
    }).map_err(|e| ErrorKind::IOError(e).into())
  }

  fn read_from_stream(&mut self) -> Result<(), Error> {
    match self.connection.status().state() {
      ConnectionState::Closed => Ok(()),
      ConnectionState::Error  => Err(ErrorKind::InvalidConnectionState(ConnectionState::Error).into()),
      _                       => self.socket.read(&mut self.receive_buffer.space()).map(|sz| {
        trace!("read {} bytes", sz);
        self.receive_buffer.fill(sz);
      }).map_err(|e| ErrorKind::IOError(e).into()),
    }
  }

  fn serialize(&mut self) -> Result<(), Error> {
    if let Some((send_id, next_msg)) = self.connection.next_frame() {
      trace!("will write to buffer: {:?}", next_msg);
      match gen_frame(self.send_buffer.space(), &next_msg).map(|tup| tup.0) {
        Ok(sz) => {
          self.send_buffer.fill(sz);
          self.connection.mark_sent(send_id);
          Ok(())
        },
        Err(e) => {
          match e {
            GenError::BufferTooSmall(_) => {
              // Requeue msg
              self.connection.requeue_frame(send_id, next_msg)?;
              self.send_buffer.shift();
              Ok(())
            },
            GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
              error!("error generating frame: {:?}", e);
              self.connection.set_error()?;
              Err(ErrorKind::SerialisationError(e).into())
            }
          }
        }
      }
    } else {
      self.has_data = false;
      Ok(())
    }
  }

  fn parse(&mut self) -> Result<(), Error> {
    match parse_frame(self.receive_buffer.data()) {
      Ok((i, f)) => {
        let consumed = self.receive_buffer.data().offset(i);
        self.receive_buffer.consume(consumed);

        if let Err(e) = self.connection.handle_frame(f) {
          self.connection.set_error()?;
          Err(e)
        } else {
          Ok(())
        }
      },
      Err(e) => {
        if e.is_incomplete() {
          self.receive_buffer.shift();
          Ok(())
        } else {
          error!("parse error: {:?}", e);
          self.connection.set_error()?;
          Err(ErrorKind::ParsingError(format!("{:?}", e)).into())
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>/// Utilities to work with Jansson JSON values, which are exposed in the Janus plugin API.
extern crate libc;

use jansson_sys;
use std::error::Error;
use std::fmt;
use std::ffi::{CStr, CString};
use std::mem;
use std::ops::Deref;
use std::slice;
use std::str;
use utils::LibcString;

/// A pointer to a raw Jansson value struct.
pub type RawJanssonValue = jansson_sys::json_t;

bitflags! {
    /// Flags that can be passed to JSON decoding functions.
    pub struct JanssonDecodingFlags: usize {
        const JSON_REJECT_DUPLICATES = 0x0001;
        const JSON_DISABLE_EOF_CHECK = 0x0002;
        const JSON_DECODE_ANY = 0x0004;
        const JSON_DECODE_INT_AS_REAL = 0x0008;
        const JSON_ALLOW_NUL = 0x0010;
    }
}

bitflags! {
    /// Flags that can be passed to JSON encoding functions.
    pub struct JanssonEncodingFlags: usize {
        const JSON_COMPACT = 0x0020;
        const JSON_ENSURE_ASCII = 0x0040;
        const JSON_SORT_KEYS = 0x0080;
        const JSON_PRESERVE_ORDER = 0x0100;
        const JSON_ENCODE_ANY = 0x0200;
        const JSON_ESCAPE_SLASH = 0x0400;
        const JSON_EMBED = 0x0800;
    }
}

/// A safe wrapper for a Jansson JSON value. Automatically increases and decreases the refcount
/// of the underlying value when cloned/dropped.
pub struct JanssonValue {
    ptr: *mut RawJanssonValue,
}

impl JanssonValue {
    /// Creates a `JanssonValue` owning the given raw pointer, incrementing the reference count.
    pub unsafe fn from_and_incref(ptr: *mut RawJanssonValue) -> Option<Self> {
        jansson_sys::json_incref(ptr);
        Self::from_raw(ptr)
    }

    /// Creates a `JanssonValue` owning the given raw pointer. Does not increment the reference count, but the
    /// `JanssonValue`'s destructor will decrement the reference count.
    pub unsafe fn from_raw(ptr: *mut RawJanssonValue) -> Option<Self> {
        ptr.as_mut().map(|p| Self { ptr: p })
    }

    /// Transfers ownership of this value to this pointer. The consumer of the pointer is responsible for calling
    /// json_decref on it later.
    pub fn into_raw(self) -> *mut RawJanssonValue {
        unsafe { jansson_sys::json_incref(self.ptr) };
        self.ptr
    }

    /// Gets the reference backing this value without taking ownership.
    pub fn as_mut_ref(&mut self) -> &mut RawJanssonValue {
        unsafe { self.ptr.as_mut().unwrap() }
    }

    /// Decodes a JSON string slice into a Jansson value, returning an error if decoding fails.
    pub fn from_str(input: &str, decoding_flags: JanssonDecodingFlags) -> Result<Self, Box<dyn Error + Send + Sync>> {
        Self::from_cstr(&CString::new(input)?, decoding_flags)
    }

    /// Decodes a JSON C-style string into a Jansson value, returning an error if decoding fails.
    pub fn from_cstr(input: &CStr, decoding_flags: JanssonDecodingFlags) -> Result<Self, Box<dyn Error + Send + Sync>> {
        unsafe {
            let mut error: jansson_sys::json_error_t = mem::uninitialized();
            let result = jansson_sys::json_loads(input.as_ptr(), decoding_flags.bits(), &mut error as *mut _);
            match Self::from_raw(result) {
                Some(val) => Ok(val),
                None => {
                    let ptr = &error.text as *const _;
                    let len = libc::strlen(ptr);
                    let sli = slice::from_raw_parts(ptr as *mut u8, len);
                    Err(From::from(str::from_utf8(sli)?))
                }
            }
        }
    }

    /// Encodes this Jansson value as a JSON owned C-style string.
    pub fn to_libcstring(&self, encoding_flags: JanssonEncodingFlags) -> LibcString {
        unsafe {
            let json = jansson_sys::json_dumps(self.ptr, encoding_flags.bits());
            LibcString::from_chars(json).expect("Error writing JSON output from Jansson value :(")
        }
    }
}

impl fmt::Debug for JanssonValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JanssonValue {{ {} }}", self.to_libcstring(JanssonEncodingFlags::empty()).to_string_lossy())
    }
}

impl Deref for JanssonValue {
    type Target = RawJanssonValue;

    fn deref(&self) -> &RawJanssonValue {
        unsafe { &*self.ptr }
    }
}

impl Clone for JanssonValue {
    fn clone(&self) -> Self {
        unsafe { jansson_sys::json_incref(self.ptr) };
        Self { ptr: self.ptr }
    }
}

impl Drop for JanssonValue {
    fn drop(&mut self) {
        unsafe { jansson_sys::json_decref(self.ptr) }
    }
}

unsafe impl Send for JanssonValue {}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn round_trip() {
        let json = r#"{"a": "alpha", "b": true, "c": false, "d": 42, "e": 1.25, "f": null, "g": [1, 2, 3]}"#;
        let result = JanssonValue::from_str(json, JanssonDecodingFlags::empty()).unwrap();
        assert_eq!(json, result.to_libcstring(JanssonEncodingFlags::JSON_SORT_KEYS).to_str().unwrap());
    }

    #[test]
    fn produce_jansson_errors() {
        let json = r#"{"a":"#;
        let result = JanssonValue::from_str(json, JanssonDecodingFlags::empty());
        assert!(result.is_err());
    }
}
<commit_msg>Use MaybeUninit instead of deprecated mem::uninitialized<commit_after>/// Utilities to work with Jansson JSON values, which are exposed in the Janus plugin API.
extern crate libc;

use jansson_sys;
use std::error::Error;
use std::fmt;
use std::ffi::{CStr, CString};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::slice;
use std::str;
use utils::LibcString;

/// A pointer to a raw Jansson value struct.
pub type RawJanssonValue = jansson_sys::json_t;

bitflags! {
    /// Flags that can be passed to JSON decoding functions.
    pub struct JanssonDecodingFlags: usize {
        const JSON_REJECT_DUPLICATES = 0x0001;
        const JSON_DISABLE_EOF_CHECK = 0x0002;
        const JSON_DECODE_ANY = 0x0004;
        const JSON_DECODE_INT_AS_REAL = 0x0008;
        const JSON_ALLOW_NUL = 0x0010;
    }
}

bitflags! {
    /// Flags that can be passed to JSON encoding functions.
    pub struct JanssonEncodingFlags: usize {
        const JSON_COMPACT = 0x0020;
        const JSON_ENSURE_ASCII = 0x0040;
        const JSON_SORT_KEYS = 0x0080;
        const JSON_PRESERVE_ORDER = 0x0100;
        const JSON_ENCODE_ANY = 0x0200;
        const JSON_ESCAPE_SLASH = 0x0400;
        const JSON_EMBED = 0x0800;
    }
}

/// A safe wrapper for a Jansson JSON value. Automatically increases and decreases the refcount
/// of the underlying value when cloned/dropped.
pub struct JanssonValue {
    ptr: *mut RawJanssonValue,
}

impl JanssonValue {
    /// Creates a `JanssonValue` owning the given raw pointer, incrementing the reference count.
    pub unsafe fn from_and_incref(ptr: *mut RawJanssonValue) -> Option<Self> {
        jansson_sys::json_incref(ptr);
        Self::from_raw(ptr)
    }

    /// Creates a `JanssonValue` owning the given raw pointer. Does not increment the reference count, but the
    /// `JanssonValue`'s destructor will decrement the reference count.
    pub unsafe fn from_raw(ptr: *mut RawJanssonValue) -> Option<Self> {
        ptr.as_mut().map(|p| Self { ptr: p })
    }

    /// Transfers ownership of this value to this pointer. The consumer of the pointer is responsible for calling
    /// json_decref on it later.
    pub fn into_raw(self) -> *mut RawJanssonValue {
        unsafe { jansson_sys::json_incref(self.ptr) };
        self.ptr
    }

    /// Gets the reference backing this value without taking ownership.
    pub fn as_mut_ref(&mut self) -> &mut RawJanssonValue {
        unsafe { self.ptr.as_mut().unwrap() }
    }

    /// Decodes a JSON string slice into a Jansson value, returning an error if decoding fails.
    pub fn from_str(input: &str, decoding_flags: JanssonDecodingFlags) -> Result<Self, Box<dyn Error + Send + Sync>> {
        Self::from_cstr(&CString::new(input)?, decoding_flags)
    }

    /// Decodes a JSON C-style string into a Jansson value, returning an error if decoding fails.
    pub fn from_cstr(input: &CStr, decoding_flags: JanssonDecodingFlags) -> Result<Self, Box<dyn Error + Send + Sync>> {
        unsafe {
            let mut error = MaybeUninit::<jansson_sys::json_error_t>::uninit();
            let result = jansson_sys::json_loads(input.as_ptr(), decoding_flags.bits(), error.as_mut_ptr());
            match Self::from_raw(result) {
                Some(val) => Ok(val),
                None => {
                    let ptr = &error.assume_init().text as *const _;
                    let len = libc::strlen(ptr);
                    let sli = slice::from_raw_parts(ptr as *mut u8, len);
                    Err(From::from(str::from_utf8(sli)?))
                }
            }
        }
    }

    /// Encodes this Jansson value as a JSON owned C-style string.
    pub fn to_libcstring(&self, encoding_flags: JanssonEncodingFlags) -> LibcString {
        unsafe {
            let json = jansson_sys::json_dumps(self.ptr, encoding_flags.bits());
            LibcString::from_chars(json).expect("Error writing JSON output from Jansson value :(")
        }
    }
}

impl fmt::Debug for JanssonValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JanssonValue {{ {} }}", self.to_libcstring(JanssonEncodingFlags::empty()).to_string_lossy())
    }
}

impl Deref for JanssonValue {
    type Target = RawJanssonValue;

    fn deref(&self) -> &RawJanssonValue {
        unsafe { &*self.ptr }
    }
}

impl Clone for JanssonValue {
    fn clone(&self) -> Self {
        unsafe { jansson_sys::json_incref(self.ptr) };
        Self { ptr: self.ptr }
    }
}

impl Drop for JanssonValue {
    fn drop(&mut self) {
        unsafe { jansson_sys::json_decref(self.ptr) }
    }
}

unsafe impl Send for JanssonValue {}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn round_trip() {
        let json = r#"{"a": "alpha", "b": true, "c": false, "d": 42, "e": 1.25, "f": null, "g": [1, 2, 3]}"#;
        let result = JanssonValue::from_str(json, JanssonDecodingFlags::empty()).unwrap();
        assert_eq!(json, result.to_libcstring(JanssonEncodingFlags::JSON_SORT_KEYS).to_str().unwrap());
    }

    #[test]
    fn produce_jansson_errors() {
        let json = r#"{"a":"#;
        let result = JanssonValue::from_str(json, JanssonDecodingFlags::empty());
        assert!(result.is_err());
    }
}
<|endoftext|>


<commit_before>// We add this `extern crate` here to ensure that bindgen is up-to-date and
// rebuilt, even though we aren't using any of its types or functions here, only
// indirectly calling the executable.
#[allow(dead_code)]
extern crate bindgen;

use std::env;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;

fn spawn_run_bindgen<P, Q, R>(run_bindgen: P, bindgen: Q, header: R) -> process::Child
    where P: AsRef<Path>,
          Q: AsRef<Path>,
          R: AsRef<Path>
{
    let run_bindgen = run_bindgen.as_ref();
    let bindgen = bindgen.as_ref();
    let header = header.as_ref();

    // Convert from "tests/headers/foo.hpp" to "tests/expectations/foo.rs" by
    // saving the filename, popping off "headers/foo.hpp", pushing
    // "expectations", pushing the saved filename, and finally modifying the
    // extension.

    let mut expected = PathBuf::from(header);
    let file_name = expected.file_name()
        .expect("Should have filename")
        .to_os_string();
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push(file_name);
    expected.set_extension("rs");

    let mut cmd = process::Command::new(run_bindgen);
    cmd.stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .arg(bindgen)
        .arg(header)
        .arg(expected);

    if cfg!(feature = "llvm_stable") {
        cmd.arg("--feature")
            .arg("llvm_stable");
    }

    cmd.spawn()
        .expect("Should be able to spawn run-bindgen.py child process")
}

#[test]
fn run_bindgen_tests() {
    let crate_root = env::var("CARGO_MANIFEST_DIR")
        .expect("should have CARGO_MANIFEST_DIR environment variable");

    let mut run_bindgen = PathBuf::from(&crate_root);
    run_bindgen.push("tests");
    run_bindgen.push("tools");
    run_bindgen.push("run-bindgen.py");

    let mut bindgen = PathBuf::from(&crate_root);
    bindgen.push("target");
    bindgen.push("debug");
    bindgen.push("bindgen");
    if !bindgen.is_file() {
        panic!("{} is not a file! Build bindgen before running tests.",
               bindgen.display());
    }

    let mut headers_dir = PathBuf::from(&crate_root);
    headers_dir.push("tests");
    headers_dir.push("headers");

    let entries = fs::read_dir(&headers_dir)
        .expect("Should read directory")
        .map(|result| result.expect("Should read directory entry"));

    let tests = entries.filter(|entry| {
        match entry.path().extension().map(|s| s.to_str()) {
            Some(Some("h")) |
            Some(Some("hpp")) => true,
            _ => false,
        }
    });

    // First spawn all child processes and collect them, then wait on each
    // one. This runs the tests in parallel rather than serially.

    let children: Vec<_> = tests.map(|entry| {
            let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path());
            (entry.path(), child)
        })
        .collect();

    let failures: Vec<_> = children.into_iter()
        .filter_map(|(path, mut child)| {
            let passed = child.wait()
                .expect("Should wait on child process")
                .success();

            if passed { None } else { Some((path, child)) }
        })
        .collect();

    let num_failures = failures.len();

    for (path, child) in failures {
        println!("FAIL: {}", path.display());

        let mut buf = String::new();

        child.stdout
            .expect("should have stdout piped")
            .read_to_string(&mut buf)
            .expect("should read child's stdout");
        for line in buf.lines() {
            println!("child stdout> {}", line);
        }

        child.stderr
            .expect("should have stderr piped")
            .read_to_string(&mut buf)
            .expect("should read child's stderr");
        for line in buf.lines() {
            println!("child stderr> {}", line);
        }
    }

    if num_failures > 0 {
        panic!("{} test failures!", num_failures);
    }
}
<commit_msg>Auto merge of #159 - jeanphilippeD:serial_tests, r=emilio<commit_after>// We add this `extern crate` here to ensure that bindgen is up-to-date and
// rebuilt, even though we aren't using any of its types or functions here, only
// indirectly calling the executable.
#[allow(dead_code)]
extern crate bindgen;

use std::env;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;

fn spawn_run_bindgen<P, Q, R>(run_bindgen: P, bindgen: Q, header: R) -> process::Child
    where P: AsRef<Path>,
          Q: AsRef<Path>,
          R: AsRef<Path>
{
    let run_bindgen = run_bindgen.as_ref();
    let bindgen = bindgen.as_ref();
    let header = header.as_ref();

    // Convert from "tests/headers/foo.hpp" to "tests/expectations/foo.rs" by
    // saving the filename, popping off "headers/foo.hpp", pushing
    // "expectations", pushing the saved filename, and finally modifying the
    // extension.

    let mut expected = PathBuf::from(header);
    let file_name = expected.file_name()
        .expect("Should have filename")
        .to_os_string();
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push(file_name);
    expected.set_extension("rs");

    let mut cmd = process::Command::new(run_bindgen);
    cmd.stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .arg(bindgen)
        .arg(header)
        .arg(expected);

    if cfg!(feature = "llvm_stable") {
        cmd.arg("--feature")
            .arg("llvm_stable");
    }

    cmd.spawn()
        .expect("Should be able to spawn run-bindgen.py child process")
}

#[test]
fn run_bindgen_tests() {
    let crate_root = env::var("CARGO_MANIFEST_DIR")
        .expect("should have CARGO_MANIFEST_DIR environment variable");

    let mut run_bindgen = PathBuf::from(&crate_root);
    run_bindgen.push("tests");
    run_bindgen.push("tools");
    run_bindgen.push("run-bindgen.py");

    let mut bindgen = PathBuf::from(&crate_root);
    bindgen.push("target");
    bindgen.push("debug");
    bindgen.push("bindgen");
    if !bindgen.is_file() {
        panic!("{} is not a file! Build bindgen before running tests.",
               bindgen.display());
    }

    let mut headers_dir = PathBuf::from(&crate_root);
    headers_dir.push("tests");
    headers_dir.push("headers");

    let entries = fs::read_dir(&headers_dir)
        .expect("Should read directory")
        .map(|result| result.expect("Should read directory entry"));

    let tests = entries.filter(|entry| {
        match entry.path().extension().map(|s| s.to_str()) {
            Some(Some("h")) |
            Some(Some("hpp")) => true,
            _ => false,
        }
    });

    // Spawn one child at a time and wait on it as number of process
    // is the number of test files.

    let children = tests.map(|entry| {
        let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path());
        (entry.path(), child)
    });

    let failures: Vec<_> = children
        .filter_map(|(path, mut child)| {
            let passed = child.wait()
                .expect("Should wait on child process")
                .success();

            if passed { None } else { Some((path, child)) }
        })
        .collect();

    let num_failures = failures.len();

    for (path, child) in failures {
        println!("FAIL: {}", path.display());

        let mut buf = String::new();

        child.stdout
            .expect("should have stdout piped")
            .read_to_string(&mut buf)
            .expect("should read child's stdout");
        for line in buf.lines() {
            println!("child stdout> {}", line);
        }

        child.stderr
            .expect("should have stderr piped")
            .read_to_string(&mut buf)
            .expect("should read child's stderr");
        for line in buf.lines() {
            println!("child stderr> {}", line);
        }
    }

    if num_failures > 0 {
        panic!("{} test failures!", num_failures);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .build_glium()
                    .unwrap();

    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();
    let mut transform_buffer = glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    let mut iteration = 0;
    let mut buf_num = 0;

    loop {
        // writing the commands
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();
            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transforms
        {
            let angle = iteration as f32 * 0.01;
            iteration += 1;
            if angle > 2.0 * 3.141592 {
                iteration = 0;
            }

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[0][0] = 2.0 * (x as isize - OBJECTS_X as isize) as f32;
                        mat[3][1] = 2.0 * (y as isize - OBJECTS_Y as isize) as f32;
                        mat[3][2] = 2.0 * (z as isize - OBJECTS_Z as isize) as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        let (w, h) = display.get_framebuffer_dimensions();
        let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);
        let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
        let at = dir.mul_s(-250.0);
        let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&at),
                                            &cgmath::Point3::from_vec(&dir),
                                            &cgmath::Vector3::new(0.0, 0.0, 1.0));
        let matrix = persp * view;

        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.1, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: matrix },
                    &params).unwrap();
        target.finish().unwrap();

        buf_num += 1;
        if buf_num >= 3 { buf_num = 0; }

        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Fix camera and gamma<commit_after>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .with_depth_buffer(24)
                    .build_glium()
                    .unwrap();

    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();
    let mut transform_buffer = glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    let mut iteration = 0;
    let mut buf_num = 0;

    loop {
        // writing the commands
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();
            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transforms
        {
            let angle = iteration as f32 * 0.01;
            iteration += 1;
            if angle > 2.0 * 3.141592 {
                iteration = 0;
            }

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[0][0] = 2.0 * (x as isize - OBJECTS_X as isize) as f32;
                        mat[3][1] = 2.0 * (y as isize - OBJECTS_Y as isize) as f32;
                        mat[3][2] = 2.0 * (z as isize - OBJECTS_Z as isize) as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        let (w, h) = display.get_framebuffer_dimensions();
        let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);
        let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
        let at = cgmath::Vector3::new(0.0, 0.0, 0.0);
        let eye = at - dir.mul_s(250.0);
        let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&eye),
                                            &cgmath::Point3::from_vec(&at),
                                            &cgmath::Vector3::new(0.0, 0.0, 1.0));
        let pos = cgmath::Matrix4::from_translation(&eye.mul_s(-1.0));
        let matrix = persp * view * pos;

        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.01, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: matrix },
                    &params).unwrap();
        target.finish().unwrap();

        buf_num += 1;
        if buf_num >= 3 { buf_num = 0; }

        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_imports)]

#![feature(plugin)]
#![plugin(interpolate_idents)]

extern crate libc;

#[macro_use]
extern crate apache2;

#[macro_use]
extern crate lazy_static;

use std::mem;
use libc::{c_void, c_char};
use apache2::{Request, Status, Server, ffi};
use apache2::wrapper::{Wrapper, CType, from_char_ptr};
use apache2::apr::Pool;

type CStringType = *const c_char;
type StringType<'a> = &'a str;

macro_rules! config_struct {
   ($name:ident { $( $field_name:ident: $field_type:ident ),* }) => {
      #[repr(C)]
      interpolate_idents! {
         config_define_c_struct!(
            [C $name] {
               $(
                  $field_name: [C $field_type]
               ),*
            }
         );
      }

      struct $name<'a> {
         pub raw: &'a mut <$name<'a> as CType>::c_type,
         pub pool: *mut ffi::apr_pool_t
      }

      impl<'a> $name<'a> {
         pub fn new(pool: &mut Pool) -> Result<Self, ()> {
            let c_config = unsafe {
               ffi::apr_pcalloc(
                  pool.raw,
                  mem::size_of::<<$name<'a> as CType>::c_type>() as ffi::apr_size_t
               ) as *mut <$name<'a> as CType>::c_type
            };

            $name::from_raw_ptr(c_config, pool.raw)
         }

         pub fn from_raw_ptr(ptr: *mut <$name<'a> as CType>::c_type, pool: *mut ffi::apr_pool_t) -> Result<Self, ()> {
            if ptr.is_null() {
               Err(())
            } else {
               let raw: &mut <$name<'a> as CType>::c_type = unsafe { &mut *ptr };
               Ok(
                  $name {
                     raw: raw,
                     pool: pool
                  }
               )
            }
         }

         $(
            config_wrapper_method!($field_name, $field_type);
         )*
      }

      interpolate_idents! {
         impl<'a> CType for $name<'a> {
            type c_type = [C $name];
         }
      }
   }
}

macro_rules! config_define_c_struct {
   ($c_name:ident { $( $field_name:ident: $field_type:ident ),* } ) => {
      #[repr(C)]
      struct $c_name {
         $(
            pub $field_name: $field_type,
         )*
      }
   }
}

macro_rules! config_wrapper_method {
   ($field_name:ident, StringType) => {
      pub fn $field_name(&self) -> Result<StringType, ()> {
         from_char_ptr(self.raw.$field_name)
      }

      interpolate_idents! {
         pub fn [set_ $field_name](&mut self, value: StringType) {
            self.raw.$field_name = ffi::strdup(self.pool, value);
         }
      }
   }
}

#[allow(unused_variables)]
pub extern "C" fn first_cmd(parms: *mut ffi::cmd_parms, p: *mut c_void, w: *const c_char) -> *const c_char {
   let config = unsafe { ffi::ap_get_module_config((*(*parms).server).module_config, &conf_module) as *mut CExampleConfig };

   let mut example_config = ExampleConfig::from_raw_ptr(config, unsafe { (*parms).pool }).unwrap();

   example_config.set_first_cmd(from_char_ptr(w).unwrap());

   std::ptr::null()
}

#[allow(unused_variables)]
pub extern "C" fn second_cmd(parms: *mut ffi::cmd_parms, p: *mut c_void, w: *const c_char) -> *const c_char {
   let config = unsafe { ffi::ap_get_module_config((*(*parms).server).module_config, &conf_module) as *mut CExampleConfig };

   let mut example_config = ExampleConfig::from_raw_ptr(config, unsafe { (*parms).pool }).unwrap();

   example_config.set_second_cmd(from_char_ptr(w).unwrap());

   std::ptr::null()
}

#[allow(unused_variables)]
pub extern "C" fn c_create_server_config(p: *mut ffi::apr_pool_t, s: *mut ffi::server_rec) -> *mut c_void {
   let mut pool = Pool::from_raw_ptr(p).unwrap();
   let config = create_server_config(&mut pool);

   config.raw as *mut CExampleConfig as *mut c_void
}

fn create_server_config<'a>(pool: &mut Pool) -> ExampleConfig<'a> {
   ExampleConfig::new(pool).unwrap()
}

config_struct!(
   ExampleConfig {
      first_cmd: StringType,
      second_cmd: StringType
   }
);

apache2_module!(conf, b"mod_conf\0", commands {
   None,
   None,
   Some(c_create_server_config),
   None,
   AP_INIT_TAKE1!(b"FirstCmd\0", first_cmd, apache2::ffi::RSRC_CONF, b"First cmd description\0");
   AP_INIT_TAKE1!(b"SecondCmd\0", second_cmd, apache2::ffi::RSRC_CONF, b"Second cmd description\0")
});

fn unwrap_str<'a>(wrapped: Result<&'a str, ()>) -> &'a str {
   wrapped.unwrap_or("--")
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   let config = unsafe { ffi::ap_get_module_config(try!(try!(r.server()).module_config()).raw, &conf_module) as *mut CExampleConfig };

   r.set_content_type("text/plain; charset=utf-8");

   try!(r.write("FIRST CMD: "));

   let first_cmd = unwrap_str(from_char_ptr(unsafe { (*config).first_cmd }));
   try!(r.write(first_cmd));

   try!(r.write("\n"));

   try!(r.write("SECOND CMD: "));

   let second_cmd = unwrap_str(from_char_ptr(unsafe { (*config).second_cmd }));
   try!(r.write(second_cmd));

   try!(r.write("\n"));

   Ok(Status::OK)
}
<commit_msg>Rewriting the conf module to use the new module declaration macro.<commit_after>#![feature(plugin)]
#![plugin(interpolate_idents)]

extern crate libc;

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, Pool, CmdParms, BoolType, StringType, RSRC_CONF};

new_module!(
   conf_new, b"mod_conf_new\0",
   config {
      server {
         ExampleConfig {
            enabled: BoolType,
            string_var: StringType
         },
         create_example_server_config
      }, [
         (FLAG, b"EnabledVar\0", enabled_var, RSRC_CONF, b"Example flag\0"),
         (TAKE1, b"StringVar\0", string_var, RSRC_CONF, b"Example string string directive\0")
      ]
   }
);

fn create_example_server_config<'a>(pool: &mut Pool) -> ExampleConfig<'a> {
   let mut config = ExampleConfig::new(pool).unwrap();

   config.set_enabled(false);

   config
}

fn enabled_var(parms: &mut CmdParms, on: bool) -> Result<(), ()> {
   let mut config = get_module_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_enabled(on);

   Ok(())
}

fn string_var<'a>(parms: &mut CmdParms, w: &'a str) -> Result<(), ()> {
   let mut config = get_module_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_string_var(w);

   Ok(())
}

fn conf_new_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   let config = get_module_config(
      &mut try!(r.pool()),
      &try!(try!(r.server()).module_config())
   );

   r.set_content_type("text/plain; charset=utf-8");

   let enabled = try!(config.enabled());
   try!(r.write(format!("EnabledVar: {:?}\n", enabled)));

   let string_var = try!(config.string_var());
   try!(r.write(format!("StringVar: {:?}\n", string_var)));

   Ok(Status::OK)
}
<|endoftext|>


<commit_before>//! This module deals with configuration data including the management of the list of secrets

#![allow(clippy::filter_map)]
extern crate rand;
use crate::image::CONF_LINE_IDENTIFIER__CONTROL;
use crate::image::CONF_LINE_IDENTIFIER__IMAGE;
use rand::Rng;
use thiserror::Error;

/// Tags comment lines in the configuration file.
pub const CONF_LINE_IDENTIFIER__COMMENT: char = '#';

/// Optionally tags secret strings in config-file. Can be omitted.
pub const CONF_LINE_IDENTIFIER__WORD: char = '-';

/// A tag to enclose parts of the secret to be visible from the start, e.g.
/// "guess_-me_" will be displayed in the game as "_ _ _ _ _ - m e"
pub const CONF_LINE_SECRET_MODIFIER__VISIBLE: char = '_';

// Custom error type used expressing potential syntax errors when parsing the configuration file.
#[derive(Error, Debug, PartialEq)]
pub enum ConfigParseError {
    #[error(
        "Syntax error in line {line_number:?}: `{line}`\n\n\
    The game modifier must be one of the following:\n\
        :traditional-rewarding\n\
        :success-rewarding\n\n\
        Edit config file and start again.\n"
    )]
    GameModifier { line_number: usize, line: String },
    #[error(
        "Syntax error in line {line_number:?}: `{line}`\n\n\
    The first character of every non-empty line has to be one of the following:\n\
        any letter or digit (secret string),\n\
        '#' (comment line),\n\
        '-' (secret string),\n\
        '|' (ASCII-Art image) or\n\
        ':' (game modifier).\n\n\
    Edit config file and start again.\n"
    )]
    LineIdentifier { line_number: usize, line: String },
    #[error["A config file must have a least one secret string, which is\
    a non-empty line starting with a letter, digit, '_' or '-'."]]
    NoSecretString,
}

/// A dictionary holding all secret sentences from among whom one is chosen randomly at the
/// beginning of the game.
#[derive(Debug, PartialEq)]
pub struct Dict {
    wordlist: Vec<String>,
}

impl Dict {
    /// Parses the configuration data, sets game modifier variables and populates the dictionary
    /// with secrets.
    pub fn new(lines: &str) -> Result<Self, ConfigParseError> {
        let mut file_syntax_test2: Result<(), ConfigParseError> = Ok(());

        let wordlist =
          // remove Unicode BOM if present (\u{feff} has in UTF8 3 bytes).
          if lines.starts_with('\u{feff}') { &lines[3..] } else { &lines[..] }
            // interpret identifier line
            .lines()
            .enumerate()
            .filter(|&(_,l)|!( l.trim().is_empty() ||
                          l.starts_with(CONF_LINE_IDENTIFIER__COMMENT) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__CONTROL) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__IMAGE)
                        )
            )
            .map(|(n,l)| if l.starts_with(CONF_LINE_IDENTIFIER__WORD) {
                             l[1..].trim().to_string()
                        } else {
                             // Lines starting alphanumerically are secret strings also.
                             // We can safely unwrap here since all empty lines had been filtered.
                             let c = l.trim().chars().next().unwrap();
                             if c.is_alphanumeric() || c == CONF_LINE_SECRET_MODIFIER__VISIBLE {
                                l.trim().to_string()
                             } else {
                                 // we only save the first error
                                 if file_syntax_test2.is_ok() {
                                    file_syntax_test2 = Err(ConfigParseError::LineIdentifier {
                                        line_number: n+1, line: l.to_string() });
                                 };
                                // This will never be used but we have to return something
                                "".to_string()
                             }
                        }
            )
            .collect::<Vec<String>>();

        if file_syntax_test2.is_err() {
            return Err(file_syntax_test2.unwrap_err());
        };

        if wordlist.is_empty() {
            return Err(ConfigParseError::NoSecretString {});
        }

        Ok(Dict { wordlist })
    }

    /// Chooses randomly one secret from the dictionary and removes the secret from list
    pub fn get_random_secret(&mut self) -> Option<String> {
        match self.wordlist.len() {
            0 => None,
            1 => Some(self.wordlist.swap_remove(0)),
            _ => {
                let mut rng = rand::thread_rng();
                let i = rng.gen_range(0, &self.wordlist.len() - 1);
                Some(self.wordlist.swap_remove(i))
            }
        }
    }

    /// Is there exactly one secret left?
    pub fn is_empty(&self) -> bool {
        self.wordlist.is_empty()
    }

    /// Add a secret to the list.
    pub fn add(&mut self, secret: String) {
        self.wordlist.push(secret);
    }
}

// ***********************

#[cfg(test)]
mod tests {
    use super::{ConfigParseError, Dict};

    /// parse all 3 data types in configuration file format
    #[test]
    fn test_dictionary_parser_syntax() {
        let config: &str = "
#  comment

guess me
hang_man_
_good l_uck
:traditional-rewarding
";
        let dict = Dict::new(&config);
        let expected = Ok(Dict {
            wordlist: vec![
                "guess me".to_string(),
                "hang_man_".to_string(),
                "_good l_uck".to_string(),
            ],
        });
        assert_eq!(dict, expected);
    }

    /// indent of secrets is allowed
    #[test]
    fn test_dictionary_parser_indent() {
        let config: &str = "   guess me";
        let dict = Dict::new(&config);
        let expected = Ok(Dict {
            wordlist: vec!["guess me".to_string()],
            // this is default
        });
        assert!(dict == expected);
    }

    /// indent of comments is not allowed
    #[test]
    fn test_dictionary_parser_error_indent() {
        let config = "\n\n\n   # comment";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::LineIdentifier {
            line_number: 4,
            line: "   # comment".to_string(),
        });
        assert!(dict == expected);
    }

    /// configuration must define at least one secret
    #[test]
    fn test_dictionary_parser_error_no_secrets() {
        let config = "# nothing but comment";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::NoSecretString {});
        assert!(dict == expected);
    }

    #[test]
    fn test_image_parser_error_indent() {
        let config = "one secret\n\n :traditional-rewarding";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::LineIdentifier {
            line_number: 3,
            line: " :traditional-rewarding".to_string(),
        });
        assert_eq!(dict, expected);
    }
}
<commit_msg>typo in error message<commit_after>//! This module deals with configuration data including the management of the list of secrets

#![allow(clippy::filter_map)]
extern crate rand;
use crate::image::CONF_LINE_IDENTIFIER__CONTROL;
use crate::image::CONF_LINE_IDENTIFIER__IMAGE;
use rand::Rng;
use thiserror::Error;

/// Tags comment lines in the configuration file.
pub const CONF_LINE_IDENTIFIER__COMMENT: char = '#';

/// Optionally tags secret strings in config-file. Can be omitted.
pub const CONF_LINE_IDENTIFIER__WORD: char = '-';

/// A tag to enclose parts of the secret to be visible from the start, e.g.
/// "guess_-me_" will be displayed in the game as "_ _ _ _ _ - m e"
pub const CONF_LINE_SECRET_MODIFIER__VISIBLE: char = '_';

// Custom error type used expressing potential syntax errors when parsing the configuration file.
#[derive(Error, Debug, PartialEq)]
pub enum ConfigParseError {
    #[error(
        "Syntax error in line {line_number:?}: `{line}`\n\n\
    The game modifier must be one of the following:\n\
        :traditional-rewarding\n\
        :success-rewarding\n\n\
        Edit config file and start again.\n"
    )]
    GameModifier { line_number: usize, line: String },
    #[error(
        "Syntax error in line {line_number:?}: `{line}`\n\n\
    The first character of every non-empty line has to be one of the following:\n\
        any letter or digit (secret string),\n\
        '#' (comment line),\n\
        '-' (secret string),\n\
        '|' (ASCII-Art image) or\n\
        ':' (game modifier).\n\n\
    Edit config file and start again.\n"
    )]
    LineIdentifier { line_number: usize, line: String },
    #[error["A config file must have a least one secret string, which is\n\
    a non-empty line starting with a letter, digit, '_' or '-'."]]
    NoSecretString,
}

/// A dictionary holding all secret sentences from among whom one is chosen randomly at the
/// beginning of the game.
#[derive(Debug, PartialEq)]
pub struct Dict {
    wordlist: Vec<String>,
}

impl Dict {
    /// Parses the configuration data, sets game modifier variables and populates the dictionary
    /// with secrets.
    pub fn new(lines: &str) -> Result<Self, ConfigParseError> {
        let mut file_syntax_test2: Result<(), ConfigParseError> = Ok(());

        let wordlist =
          // remove Unicode BOM if present (\u{feff} has in UTF8 3 bytes).
          if lines.starts_with('\u{feff}') { &lines[3..] } else { &lines[..] }
            // interpret identifier line
            .lines()
            .enumerate()
            .filter(|&(_,l)|!( l.trim().is_empty() ||
                          l.starts_with(CONF_LINE_IDENTIFIER__COMMENT) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__CONTROL) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__IMAGE)
                        )
            )
            .map(|(n,l)| if l.starts_with(CONF_LINE_IDENTIFIER__WORD) {
                             l[1..].trim().to_string()
                        } else {
                             // Lines starting alphanumerically are secret strings also.
                             // We can safely unwrap here since all empty lines had been filtered.
                             let c = l.trim().chars().next().unwrap();
                             if c.is_alphanumeric() || c == CONF_LINE_SECRET_MODIFIER__VISIBLE {
                                l.trim().to_string()
                             } else {
                                 // we only save the first error
                                 if file_syntax_test2.is_ok() {
                                    file_syntax_test2 = Err(ConfigParseError::LineIdentifier {
                                        line_number: n+1, line: l.to_string() });
                                 };
                                // This will never be used but we have to return something
                                "".to_string()
                             }
                        }
            )
            .collect::<Vec<String>>();

        if file_syntax_test2.is_err() {
            return Err(file_syntax_test2.unwrap_err());
        };

        if wordlist.is_empty() {
            return Err(ConfigParseError::NoSecretString {});
        }

        Ok(Dict { wordlist })
    }

    /// Chooses randomly one secret from the dictionary and removes the secret from list
    pub fn get_random_secret(&mut self) -> Option<String> {
        match self.wordlist.len() {
            0 => None,
            1 => Some(self.wordlist.swap_remove(0)),
            _ => {
                let mut rng = rand::thread_rng();
                let i = rng.gen_range(0, &self.wordlist.len() - 1);
                Some(self.wordlist.swap_remove(i))
            }
        }
    }

    /// Is there exactly one secret left?
    pub fn is_empty(&self) -> bool {
        self.wordlist.is_empty()
    }

    /// Add a secret to the list.
    pub fn add(&mut self, secret: String) {
        self.wordlist.push(secret);
    }
}

// ***********************

#[cfg(test)]
mod tests {
    use super::{ConfigParseError, Dict};

    /// parse all 3 data types in configuration file format
    #[test]
    fn test_dictionary_parser_syntax() {
        let config: &str = "
#  comment

guess me
hang_man_
_good l_uck
:traditional-rewarding
";
        let dict = Dict::new(&config);
        let expected = Ok(Dict {
            wordlist: vec![
                "guess me".to_string(),
                "hang_man_".to_string(),
                "_good l_uck".to_string(),
            ],
        });
        assert_eq!(dict, expected);
    }

    /// indent of secrets is allowed
    #[test]
    fn test_dictionary_parser_indent() {
        let config: &str = "   guess me";
        let dict = Dict::new(&config);
        let expected = Ok(Dict {
            wordlist: vec!["guess me".to_string()],
            // this is default
        });
        assert!(dict == expected);
    }

    /// indent of comments is not allowed
    #[test]
    fn test_dictionary_parser_error_indent() {
        let config = "\n\n\n   # comment";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::LineIdentifier {
            line_number: 4,
            line: "   # comment".to_string(),
        });
        assert!(dict == expected);
    }

    /// configuration must define at least one secret
    #[test]
    fn test_dictionary_parser_error_no_secrets() {
        let config = "# nothing but comment";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::NoSecretString {});
        assert!(dict == expected);
    }

    #[test]
    fn test_image_parser_error_indent() {
        let config = "one secret\n\n :traditional-rewarding";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::LineIdentifier {
            line_number: 3,
            line: " :traditional-rewarding".to_string(),
        });
        assert_eq!(dict, expected);
    }
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

The LICENSE file provided with the Software is included with all copies or
substantial portions of the Software.

The conditions in the LICENSE file provided with the Software are also in effect.
*/

#[allow(non_camel_case_types)]; // C types

use core::libc::{c_int, c_uint, c_void};

use ll::xproto;

pub struct connection;

pub struct extension;

pub struct generic_iterator {
    data : *u8,
    rem : int,
    index : int
}

pub struct generic_reply {
    response_type : u8,
    pad0 : u8,
    sequence : u16,
    length : u32
}

pub struct generic_event {
    response_type : u8,
    pad0 : u8,
    sequence : u16,
    pad : [u32,..7],
    full_sequence : u32
}

pub struct ge_event {
    response_type : u8,
    pad0 : u8,
    sequence : u16,
    length : u32,
    event_type : u16,
    pad1 : u16,
    pad : [u32,..5],
    full_sequence : u32
}

pub struct generic_error {
    response_type : u8,
    error_code : u8,
    sequence : u16,
    resource_id : u32,
    minor_code : u16,
    major_code : u8,
    pad0 : u8,
    pad : [u32,..5],
    full_sequence : u32
}

pub struct void_cookie {
    sequence : int
}

pub struct auth_info {
    namelen : int,
    name : *u8,
    datalen : int,
    data : *u8
}

#[link_args="-lxcb"]
pub extern {
    unsafe fn xcb_flush(c : *connection) -> c_int;

    unsafe fn xcb_get_maximum_request_length(c:*connection) -> u32;
    unsafe fn xcb_prefetch_maximum_request_length(c:*connection) -> c_void;

    unsafe fn xcb_wait_for_event(c:*connection) -> *generic_event;
    unsafe fn xcb_poll_for_event(c:*connection) -> *generic_event;
    unsafe fn xcb_poll_for_queued_event(c:*connection) -> *generic_event;
    unsafe fn xcb_request_check(c:*connection, cookie:void_cookie) -> *generic_error;
    unsafe fn xcb_discard_reply(c:*connection, sequence:c_uint) -> c_void;

    unsafe fn xcb_get_extension_data(c:*connection, ext:*extension) -> *xproto::query_extension_reply;
    unsafe fn xcb_prefetch_extension_data(c:*connection, ext:*extension) -> c_void;

    unsafe fn xcb_get_setup(c:*connection) -> *xproto::setup;
    unsafe fn xcb_get_file_descriptor(c:*connection) -> c_int;
    unsafe fn xcb_connection_has_error(c:*connection) -> c_int;
    unsafe fn xcb_connect_to_fd(fd:c_int, auth_info:*auth_info) -> *connection;
    unsafe fn xcb_disconnect(c:*connection) -> c_void;

    unsafe fn xcb_parse_display(name:*u8, host:**u8, display:*c_int, screen:*c_int) -> c_int;
    unsafe fn xcb_connect(displayname:*u8, screenp:*c_int) -> *connection;
    unsafe fn xcb_connect_to_display_with_auth_info(display:*u8, auth:*auth_info, screen:*c_int) -> *connection;

    unsafe fn xcb_generate_id(c:*connection) -> u32;
}

pub mod Xlib {
    use super::{connection};
    use core::libc::{c_void, c_uint};
    struct Display;

    type XEventQueueOwner = c_uint;
    static XlibOwnsEventQueue : XEventQueueOwner = 0;
    static XCBOwnsEventQueue : XEventQueueOwner  = 1;

    #[link_args="-lX11 -lX11-xcb"]
    pub extern {
        unsafe fn XGetXCBConnection(dpy:*Display) -> connection;
        unsafe fn XSetEventQueueOwner(dpy:*Display, owner:XEventQueueOwner) -> c_void;
    }

}
<commit_msg>Fixed typo in type signature<commit_after>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

The LICENSE file provided with the Software is included with all copies or
substantial portions of the Software.

The conditions in the LICENSE file provided with the Software are also in effect.
*/

#[allow(non_camel_case_types)]; // C types

use core::libc::{c_int, c_uint, c_void};

use ll::xproto;

pub struct connection;

pub struct extension;

pub struct generic_iterator {
    data : *u8,
    rem : int,
    index : int
}

pub struct generic_reply {
    response_type : u8,
    pad0 : u8,
    sequence : u16,
    length : u32
}

pub struct generic_event {
    response_type : u8,
    pad0 : u8,
    sequence : u16,
    pad : [u32,..7],
    full_sequence : u32
}

pub struct ge_event {
    response_type : u8,
    pad0 : u8,
    sequence : u16,
    length : u32,
    event_type : u16,
    pad1 : u16,
    pad : [u32,..5],
    full_sequence : u32
}

pub struct generic_error {
    response_type : u8,
    error_code : u8,
    sequence : u16,
    resource_id : u32,
    minor_code : u16,
    major_code : u8,
    pad0 : u8,
    pad : [u32,..5],
    full_sequence : u32
}

pub struct void_cookie {
    sequence : int
}

pub struct auth_info {
    namelen : int,
    name : *u8,
    datalen : int,
    data : *u8
}

#[link_args="-lxcb"]
pub extern {
    unsafe fn xcb_flush(c : *connection) -> c_int;

    unsafe fn xcb_get_maximum_request_length(c:*connection) -> u32;
    unsafe fn xcb_prefetch_maximum_request_length(c:*connection) -> c_void;

    unsafe fn xcb_wait_for_event(c:*connection) -> *generic_event;
    unsafe fn xcb_poll_for_event(c:*connection) -> *generic_event;
    unsafe fn xcb_poll_for_queued_event(c:*connection) -> *generic_event;
    unsafe fn xcb_request_check(c:*connection, cookie:void_cookie) -> *generic_error;
    unsafe fn xcb_discard_reply(c:*connection, sequence:c_uint) -> c_void;

    unsafe fn xcb_get_extension_data(c:*connection, ext:*extension) -> *xproto::query_extension_reply;
    unsafe fn xcb_prefetch_extension_data(c:*connection, ext:*extension) -> c_void;

    unsafe fn xcb_get_setup(c:*connection) -> *xproto::setup;
    unsafe fn xcb_get_file_descriptor(c:*connection) -> c_int;
    unsafe fn xcb_connection_has_error(c:*connection) -> c_int;
    unsafe fn xcb_connect_to_fd(fd:c_int, auth_info:*auth_info) -> *connection;
    unsafe fn xcb_disconnect(c:*connection) -> c_void;

    unsafe fn xcb_parse_display(name:*u8, host:**u8, display:*c_int, screen:*c_int) -> c_int;
    unsafe fn xcb_connect(displayname:*u8, screenp:*c_int) -> *connection;
    unsafe fn xcb_connect_to_display_with_auth_info(display:*u8, auth:*auth_info, screen:*c_int) -> *connection;

    unsafe fn xcb_generate_id(c:*connection) -> u32;
}

pub mod Xlib {
    use super::{connection};
    use core::libc::{c_void, c_uint};
    struct Display;

    type XEventQueueOwner = c_uint;
    static XlibOwnsEventQueue : XEventQueueOwner = 0;
    static XCBOwnsEventQueue : XEventQueueOwner  = 1;

    #[link_args="-lX11 -lX11-xcb"]
    pub extern {
        unsafe fn XGetXCBConnection(dpy:*Display) -> *connection;
        unsafe fn XSetEventQueueOwner(dpy:*Display, owner:XEventQueueOwner) -> c_void;
    }

}
<|endoftext|>


<commit_before>extern crate libc;

#[repr(C)]
pub struct SvmNode {
	pub index: libc::c_int,
	pub value: libc::c_float,
}

#[repr(C)]
pub struct SvmProblem {
	pub l: libc::c_int,
	pub y: *mut libc::c_double,
	pub x: *mut *mut SvmNode,
}

/* sum_type */
pub const C_SVC: libc::c_int        = 0;
pub const NU_SVC: libc::c_int       = 1;
pub const ONE_CLASS: libc::c_int    = 2;
pub const EPSILON_SVR: libc::c_int  = 3;
pub const NU_SVR: libc::c_int       = 4;

/* kernel_type */
pub const LINEAR: libc::c_int       = 0;
pub const POLY: libc::c_int         = 1;
pub const RBF: libc::c_int          = 2;
pub const SIGMOID: libc::c_int      = 3;
pub const PRECOMPUTED: libc::c_int  = 4;

#[repr(C)]
pub struct SvmParameter {
	pub svm_type: libc::c_int,
	pub kernel_type: libc::c_int,
	pub degree: libc::c_int,	/* for poly */
	pub gamma: libc::c_double,	/* for poly/rbf/sigmoid */
	pub coef0: libc::c_double,	/* for poly/sigmoid */

	/* these are for training only */
	pub cache_size: libc::c_double, /* in MB */
	pub eps: libc::c_double,	/* stopping criteria */
	pub c: libc::c_double,	/* for C_SVC, EPSILON_SVR and NU_SVR */
	pub nr_weight: libc::c_int,		/* for C_SVC */
	pub weight_label: *mut libc::c_int,	/* for C_SVC */
	pub weight: *mut libc::c_double,		/* for C_SVC */
	pub nu: libc::c_double,	/* for NU_SVC, ONE_CLASS, and NU_SVR */
	pub p: libc::c_double,	/* for EPSILON_SVR */
	pub shrinking: libc::c_int,         /* use the shrinking heuristics */
	pub probability: libc::c_int,       /* do probability estimates */
}

//
// svm_model
//
#[repr(C)]
pub struct SvmModel {
	param: SvmParameter, 	/* parameter */
	nr_class: libc::c_int,		/* number of classes, = 2 in regression/one class svm */
	l: libc::c_int,			/* total #SV */
	sv: *mut *mut SvmNode,		/* SVs (SV[l]) */
	sv_coef: *mut *mut libc::c_double,	/* coefficients for SVs in decision functions (sv_coef[k-1][l]) */
	rho: *mut libc::c_double,		/* constants in decision functions (rho[k*(k-1)/2]) */
	prob_a: *mut libc::c_double,		/* pariwise probability information */
	prob_b: *mut libc::c_double,
	sv_indices: *mut libc::c_int,        /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */

	/* for classification only */

	label: *mut libc::c_int,		/* label of each class (label[k]) */
	n_sv: *mut libc::c_int,		/* number of SVs for each class (nSV[k]) */
				/* nSV[0] + nSV[1] + ... + nSV[k-1] = l */
	/* XXX */
	free_sv: libc::c_int,		/* 1 if svm_model is created by svm_load_model*/
				/* 0 if svm_model is created by svm_train */
}

#[link(name = "svm")]
extern {

pub fn svm_train(prob: *const SvmProblem, param: *const SvmParameter) -> *mut SvmModel;
pub fn svm_cross_validation(prob: *const SvmProblem, param: *const SvmParameter, nr_fold: libc::c_int, target: *mut libc::c_double);

pub fn svm_save_model(model_file_name: *const libc::c_char, model: *const SvmModel) -> libc::c_int;
pub fn svm_load_model(model_file_name: *const libc::c_char) -> *mut SvmModel;

pub fn svm_get_svm_type(model: *const SvmModel) -> libc::c_int;
pub fn svm_get_nr_class(model: *const SvmModel) -> libc::c_int;
pub fn svm_get_labels(model: *const SvmModel, label: *mut libc::c_int);
pub fn svm_get_sv_indices(model: *const SvmModel, sv_indices: *mut libc::c_int);
pub fn svm_get_nr_sv(model: *const SvmModel) -> libc::c_int;
pub fn svm_get_svr_probability(model: *const SvmModel) -> libc::c_double;

pub fn svm_predict_values(model: *const SvmModel, x: *const SvmNode, dec_values: *mut libc::c_double) -> libc::c_double;
pub fn svm_predict(model: *const SvmModel, x: *const SvmNode) -> libc::c_double;
pub fn svm_predict_probability(model: *const SvmModel, x: *const SvmNode, prob_estimats: *mut libc::c_double) -> libc::c_double;

pub fn svm_free_model_content(model_ptr: *mut SvmModel);
pub fn svm_free_and_destroy_model(model_ptr_ptr: *mut *mut SvmModel);
pub fn svm_destroy_param(param: *mut SvmParameter);

pub fn svm_check_parameter(prob: *const SvmProblem, param: *const SvmParameter) -> *const libc::c_char;
pub fn svm_check_probability_model(model: *const SvmModel) -> libc::c_int;

pub fn svm_set_print_string_function(print_fn: extern fn (*const libc::c_char));

}
<commit_msg>Fix typo<commit_after>extern crate libc;

#[repr(C)]
pub struct SvmNode {
	pub index: libc::c_int,
	pub value: libc::c_double,
}

#[repr(C)]
pub struct SvmProblem {
	pub l: libc::c_int,
	pub y: *mut libc::c_double,
	pub x: *mut *mut SvmNode,
}

/* sum_type */
pub const C_SVC: libc::c_int        = 0;
pub const NU_SVC: libc::c_int       = 1;
pub const ONE_CLASS: libc::c_int    = 2;
pub const EPSILON_SVR: libc::c_int  = 3;
pub const NU_SVR: libc::c_int       = 4;

/* kernel_type */
pub const LINEAR: libc::c_int       = 0;
pub const POLY: libc::c_int         = 1;
pub const RBF: libc::c_int          = 2;
pub const SIGMOID: libc::c_int      = 3;
pub const PRECOMPUTED: libc::c_int  = 4;

#[repr(C)]
pub struct SvmParameter {
	pub svm_type: libc::c_int,
	pub kernel_type: libc::c_int,
	pub degree: libc::c_int,	/* for poly */
	pub gamma: libc::c_double,	/* for poly/rbf/sigmoid */
	pub coef0: libc::c_double,	/* for poly/sigmoid */

	/* these are for training only */
	pub cache_size: libc::c_double, /* in MB */
	pub eps: libc::c_double,	/* stopping criteria */
	pub c: libc::c_double,	/* for C_SVC, EPSILON_SVR and NU_SVR */
	pub nr_weight: libc::c_int,		/* for C_SVC */
	pub weight_label: *mut libc::c_int,	/* for C_SVC */
	pub weight: *mut libc::c_double,		/* for C_SVC */
	pub nu: libc::c_double,	/* for NU_SVC, ONE_CLASS, and NU_SVR */
	pub p: libc::c_double,	/* for EPSILON_SVR */
	pub shrinking: libc::c_int,         /* use the shrinking heuristics */
	pub probability: libc::c_int,       /* do probability estimates */
}

//
// svm_model
//
#[repr(C)]
pub struct SvmModel {
	param: SvmParameter, 	/* parameter */
	nr_class: libc::c_int,		/* number of classes, = 2 in regression/one class svm */
	l: libc::c_int,			/* total #SV */
	sv: *mut *mut SvmNode,		/* SVs (SV[l]) */
	sv_coef: *mut *mut libc::c_double,	/* coefficients for SVs in decision functions (sv_coef[k-1][l]) */
	rho: *mut libc::c_double,		/* constants in decision functions (rho[k*(k-1)/2]) */
	prob_a: *mut libc::c_double,		/* pariwise probability information */
	prob_b: *mut libc::c_double,
	sv_indices: *mut libc::c_int,        /* sv_indices[0,...,nSV-1] are values in [1,...,num_traning_data] to indicate SVs in the training set */

	/* for classification only */

	label: *mut libc::c_int,		/* label of each class (label[k]) */
	n_sv: *mut libc::c_int,		/* number of SVs for each class (nSV[k]) */
				/* nSV[0] + nSV[1] + ... + nSV[k-1] = l */
	/* XXX */
	free_sv: libc::c_int,		/* 1 if svm_model is created by svm_load_model*/
				/* 0 if svm_model is created by svm_train */
}

#[link(name = "svm")]
extern {

pub fn svm_train(prob: *const SvmProblem, param: *const SvmParameter) -> *mut SvmModel;
pub fn svm_cross_validation(prob: *const SvmProblem, param: *const SvmParameter, nr_fold: libc::c_int, target: *mut libc::c_double);

pub fn svm_save_model(model_file_name: *const libc::c_char, model: *const SvmModel) -> libc::c_int;
pub fn svm_load_model(model_file_name: *const libc::c_char) -> *mut SvmModel;

pub fn svm_get_svm_type(model: *const SvmModel) -> libc::c_int;
pub fn svm_get_nr_class(model: *const SvmModel) -> libc::c_int;
pub fn svm_get_labels(model: *const SvmModel, label: *mut libc::c_int);
pub fn svm_get_sv_indices(model: *const SvmModel, sv_indices: *mut libc::c_int);
pub fn svm_get_nr_sv(model: *const SvmModel) -> libc::c_int;
pub fn svm_get_svr_probability(model: *const SvmModel) -> libc::c_double;

pub fn svm_predict_values(model: *const SvmModel, x: *const SvmNode, dec_values: *mut libc::c_double) -> libc::c_double;
pub fn svm_predict(model: *const SvmModel, x: *const SvmNode) -> libc::c_double;
pub fn svm_predict_probability(model: *const SvmModel, x: *const SvmNode, prob_estimates: *mut libc::c_double) -> libc::c_double;

pub fn svm_free_model_content(model_ptr: *mut SvmModel);
pub fn svm_free_and_destroy_model(model_ptr_ptr: *mut *mut SvmModel);
pub fn svm_destroy_param(param: *mut SvmParameter);

pub fn svm_check_parameter(prob: *const SvmProblem, param: *const SvmParameter) -> *const libc::c_char;
pub fn svm_check_probability_model(model: *const SvmModel) -> libc::c_int;

pub fn svm_set_print_string_function(print_fn: extern fn (*const libc::c_char));

}
<|endoftext|>