<commit_before>use bson;
use byteorder;

use client::coll::options::WriteModel;
use std::{error, fmt, io, result, sync};

/// A type for results generated by MongoDB related functions, where the Err type is mongodb::Error.
pub type Result<T> = result::Result<T, Error>;

/// The error type for MongoDB operations.
#[derive(Debug)]
pub enum Error {
    /// I/O operation errors of `Read`, `Write`, `Seek`, and associated traits.
    IoError(io::Error),
    /// A BSON struct could not be encoded.
    EncoderError(bson::EncoderError),
    /// A BSON struct could not be decoded.
    DecoderError(bson::DecoderError),
    /// A single-write operation failed.
    WriteError(WriteException),
    /// A bulk-write operation failed due to one or more lower-level write-related errors.
    BulkWriteError(BulkWriteException),
    /// An invalid function or operational argument was provided.
    ArgumentError(String),
    /// A database operation failed to send or receive a reply.
    OperationError(String),
    /// A database operation returned an invalid reply.
    ResponseError(String),
    /// A cursor operation failed to return a cursor.
    CursorNotFoundError,
    /// The application failed to secure the client connection socket due to a poisoned lock.
    LockError,
    /// A standard error with a string description;
    /// a more specific error should generally be used.
    DefaultError(String),
}

/// The error type for Write-related MongoDB operations.
#[derive(Debug, Clone)]
pub struct WriteException {
    write_concern_error: Option<WriteConcernError>,
    write_error: Option<WriteError>,
    message: String,
}

/// The error struct for a write-concern related error.
#[derive(Debug, Clone)]
pub struct WriteConcernError {
    code: i32,
    details: bson::Document,
    message: String,
}

/// The error struct for a write-related error.
#[derive(Debug, Clone)]
pub struct WriteError {
    code: i32,
    message: String,
}

/// The error struct for Bulk-Write related MongoDB operations.
#[derive(Debug, Clone)]
pub struct BulkWriteException {
    processed_requests: Vec<WriteModel>,
    unprocessed_requests: Vec<WriteModel>,
    write_errors: Vec<BulkWriteError>,
    write_concern_error: Option<WriteConcernError>,
    message: String,
}

/// The error struct for a single bulk-write step, indicating the request
/// and its index in the original bulk-write request.
#[derive(Debug, Clone)]
pub struct BulkWriteError {
    index: i32,
    request: Option<WriteModel>,
}

impl<'a> From<&'a str> for Error {
    fn from(s: &str) -> Error {
        Error::DefaultError(s.to_owned())
    }
}

impl From<String> for Error {
    fn from(s: String) -> Error {
        Error::DefaultError(s.to_owned())
    }
}

impl From<WriteException> for Error {
    fn from(err: WriteException) -> Error {
        Error::WriteError(err)
    }
}

impl From<BulkWriteException> for Error {
    fn from(err: BulkWriteException) -> Error {
        Error::BulkWriteError(err)
    }
}

impl From<bson::EncoderError> for Error {
    fn from(err: bson::EncoderError) -> Error {
        Error::EncoderError(err)
    }
}

impl From<bson::DecoderError> for Error {
    fn from(err: bson::DecoderError) -> Error {
        Error::DecoderError(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        Error::IoError(From::from(err))
    }
}

impl<T> From<sync::PoisonError<T>> for Error {
    fn from(_: sync::PoisonError<T>) -> Error {
        Error::LockError
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::WriteError(ref inner) => inner.fmt(fmt),
            &Error::BulkWriteError(ref inner) => inner.fmt(fmt),
            &Error::EncoderError(ref inner) => inner.fmt(fmt),
            &Error::DecoderError(ref inner) => inner.fmt(fmt),
            &Error::IoError(ref inner) => inner.fmt(fmt),
            &Error::ArgumentError(ref inner) => inner.fmt(fmt),
            &Error::OperationError(ref inner) => inner.fmt(fmt),
            &Error::ResponseError(ref inner) => inner.fmt(fmt),
            &Error::CursorNotFoundError => write!(fmt, "No cursor found for cursor operation."),
            &Error::LockError => write!(fmt, "Socket lock poisoned while attempting to access."),
            &Error::DefaultError(ref inner) => inner.fmt(fmt),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::WriteError(ref inner) => inner.description(),
            &Error::BulkWriteError(ref inner) => inner.description(),
            &Error::EncoderError(ref inner) => inner.description(),
            &Error::DecoderError(ref inner) => inner.description(),
            &Error::IoError(ref inner) => inner.description(),
            &Error::ArgumentError(ref inner) => &inner,
            &Error::OperationError(ref inner) => &inner,
            &Error::ResponseError(ref inner) => &inner,
            &Error::CursorNotFoundError => "No cursor found for cursor operation.",
            &Error::LockError => "Socket lock poisoned while attempting to access.",
            &Error::DefaultError(ref inner) => &inner,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::WriteError(ref inner) => Some(inner),
            &Error::BulkWriteError(ref inner) => Some(inner),
            &Error::EncoderError(ref inner) => Some(inner),
            &Error::DecoderError(ref inner) => Some(inner),
            &Error::IoError(ref inner) => Some(inner),
            &Error::ArgumentError(_) => None,
            &Error::OperationError(_) => None,
            &Error::ResponseError(_) => None,
            &Error::CursorNotFoundError => None,
            &Error::LockError => None,
            &Error::DefaultError(_) => None,
        }
    }
}

impl error::Error for WriteException {
    fn description(&self) -> &str {
        &self.message
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl error::Error for BulkWriteException {
    fn description(&self) -> &str {
        &self.message
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for WriteException {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let ref wc_err = self.write_concern_error;
        let ref w_err = self.write_error;

        try!(write!(fmt, "WriteException:\n"));
        if wc_err.is_some() {
            try!(write!(fmt, "{:?}\n", wc_err));
        }

        if w_err.is_some() {
            try!(write!(fmt, "{:?}\n", w_err));
        }

        Ok(())
    }
}

impl fmt::Display for BulkWriteException {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "BulkWriteException:\n"));

        try!(write!(fmt, "Processed Requests:\n"));
        for v in &self.processed_requests {
            try!(write!(fmt, "{:?}\n", v));
        }

        try!(write!(fmt, "Unprocessed Requests:\n"));
        for v in &self.unprocessed_requests {
            try!(write!(fmt, "{:?}\n", v));
        }

        match self.write_concern_error {
            Some(ref error) => try!(write!(fmt, "{:?}\n", error)),
            None => (),
        }

        for v in &self.write_errors {
            try!(write!(fmt, "{:?}\n", v));
        }

        Ok(())
    }
}

impl fmt::Display for BulkWriteError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "BulkWriteError at index {}: ", self.index));
        match self.request {
            Some(ref request) => try!(write!(fmt, "Failed to execute request {:?}\n.", request)),
            None => try!(write!(fmt, "No additional error information was received.\n")),
        }
        Ok(())
    }
}

impl WriteException {
    pub fn new(wc_err: Option<WriteConcernError>, w_err: Option<WriteError>) -> WriteException {
        let s = if wc_err.is_some() && w_err.is_some() {
            format!("{}\n{}",
                    wc_err.as_ref().unwrap().message.to_owned(),
                    w_err.as_ref().unwrap().message.to_owned())
        } else if wc_err.is_some() {
            wc_err.as_ref().unwrap().message.to_owned()
        } else if w_err.is_some() {
            w_err.as_ref().unwrap().message.to_owned()
        } else {
            "No further information provided.".to_owned()
        };

        WriteException {
            write_concern_error: wc_err,
            write_error: w_err,
            message: s,
        }
    }
}

impl WriteConcernError {
    pub fn new<T: ToString>(code: i32, details: bson::Document, message: T) -> WriteConcernError {
        WriteConcernError {
            code: code,
            details: details,
            message: message.to_string(),
        }
    }
}

impl WriteError {
    pub fn new<T: ToString>(code: i32, message: T) -> WriteError {
        WriteError {
            code: code,
            message: message.to_string(),
        }
    }
}

impl BulkWriteException {
    pub fn new<T: ToString>(processed: Vec<WriteModel>, unprocessed: Vec<WriteModel>,
                            write_errors: Vec<BulkWriteError>, write_concern_error: Option<WriteConcernError>)
                            -> BulkWriteException {

        let mut s = match write_concern_error {
            Some(ref error) => format!("WriteConcernError: {:?}\n", error),
            None => "".to_owned(),
        };

        for v in &write_errors {
            s.push_str(&format!("WriteError: {:?}\n", v)[..]);
        }

        BulkWriteException {
            processed_requests: processed,
            unprocessed_requests: unprocessed,
            write_concern_error: write_concern_error,
            write_errors: write_errors,
            message: s.to_owned(),
        }
    }
}
<commit_msg>Rename LockError to PoisonLockError<commit_after>use bson;
use byteorder;

use client::coll::options::WriteModel;
use std::{error, fmt, io, result, sync};

/// A type for results generated by MongoDB related functions, where the Err type is mongodb::Error.
pub type Result<T> = result::Result<T, Error>;

/// The error type for MongoDB operations.
#[derive(Debug)]
pub enum Error {
    /// I/O operation errors of `Read`, `Write`, `Seek`, and associated traits.
    IoError(io::Error),
    /// A BSON struct could not be encoded.
    EncoderError(bson::EncoderError),
    /// A BSON struct could not be decoded.
    DecoderError(bson::DecoderError),
    /// A single-write operation failed.
    WriteError(WriteException),
    /// A bulk-write operation failed due to one or more lower-level write-related errors.
    BulkWriteError(BulkWriteException),
    /// An invalid function or operational argument was provided.
    ArgumentError(String),
    /// A database operation failed to send or receive a reply.
    OperationError(String),
    /// A database operation returned an invalid reply.
    ResponseError(String),
    /// A cursor operation failed to return a cursor.
    CursorNotFoundError,
    /// The application failed to secure the client connection socket due to a poisoned lock.
    PoisonLockError,
    /// A standard error with a string description;
    /// a more specific error should generally be used.
    DefaultError(String),
}

/// The error type for Write-related MongoDB operations.
#[derive(Debug, Clone)]
pub struct WriteException {
    write_concern_error: Option<WriteConcernError>,
    write_error: Option<WriteError>,
    message: String,
}

/// The error struct for a write-concern related error.
#[derive(Debug, Clone)]
pub struct WriteConcernError {
    code: i32,
    details: bson::Document,
    message: String,
}

/// The error struct for a write-related error.
#[derive(Debug, Clone)]
pub struct WriteError {
    code: i32,
    message: String,
}

/// The error struct for Bulk-Write related MongoDB operations.
#[derive(Debug, Clone)]
pub struct BulkWriteException {
    processed_requests: Vec<WriteModel>,
    unprocessed_requests: Vec<WriteModel>,
    write_errors: Vec<BulkWriteError>,
    write_concern_error: Option<WriteConcernError>,
    message: String,
}

/// The error struct for a single bulk-write step, indicating the request
/// and its index in the original bulk-write request.
#[derive(Debug, Clone)]
pub struct BulkWriteError {
    index: i32,
    request: Option<WriteModel>,
}

impl<'a> From<&'a str> for Error {
    fn from(s: &str) -> Error {
        Error::DefaultError(s.to_owned())
    }
}

impl From<String> for Error {
    fn from(s: String) -> Error {
        Error::DefaultError(s.to_owned())
    }
}

impl From<WriteException> for Error {
    fn from(err: WriteException) -> Error {
        Error::WriteError(err)
    }
}

impl From<BulkWriteException> for Error {
    fn from(err: BulkWriteException) -> Error {
        Error::BulkWriteError(err)
    }
}

impl From<bson::EncoderError> for Error {
    fn from(err: bson::EncoderError) -> Error {
        Error::EncoderError(err)
    }
}

impl From<bson::DecoderError> for Error {
    fn from(err: bson::DecoderError) -> Error {
        Error::DecoderError(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        Error::IoError(From::from(err))
    }
}

impl<T> From<sync::PoisonError<T>> for Error {
    fn from(_: sync::PoisonError<T>) -> Error {
        Error::PoisonLockError
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::WriteError(ref inner) => inner.fmt(fmt),
            &Error::BulkWriteError(ref inner) => inner.fmt(fmt),
            &Error::EncoderError(ref inner) => inner.fmt(fmt),
            &Error::DecoderError(ref inner) => inner.fmt(fmt),
            &Error::IoError(ref inner) => inner.fmt(fmt),
            &Error::ArgumentError(ref inner) => inner.fmt(fmt),
            &Error::OperationError(ref inner) => inner.fmt(fmt),
            &Error::ResponseError(ref inner) => inner.fmt(fmt),
            &Error::CursorNotFoundError => write!(fmt, "No cursor found for cursor operation."),
            &Error::PoisonLockError => write!(fmt, "Socket lock poisoned while attempting to access."),
            &Error::DefaultError(ref inner) => inner.fmt(fmt),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::WriteError(ref inner) => inner.description(),
            &Error::BulkWriteError(ref inner) => inner.description(),
            &Error::EncoderError(ref inner) => inner.description(),
            &Error::DecoderError(ref inner) => inner.description(),
            &Error::IoError(ref inner) => inner.description(),
            &Error::ArgumentError(ref inner) => &inner,
            &Error::OperationError(ref inner) => &inner,
            &Error::ResponseError(ref inner) => &inner,
            &Error::CursorNotFoundError => "No cursor found for cursor operation.",
            &Error::PoisonLockError => "Socket lock poisoned while attempting to access.",
            &Error::DefaultError(ref inner) => &inner,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::WriteError(ref inner) => Some(inner),
            &Error::BulkWriteError(ref inner) => Some(inner),
            &Error::EncoderError(ref inner) => Some(inner),
            &Error::DecoderError(ref inner) => Some(inner),
            &Error::IoError(ref inner) => Some(inner),
            &Error::ArgumentError(_) => None,
            &Error::OperationError(_) => None,
            &Error::ResponseError(_) => None,
            &Error::CursorNotFoundError => None,
            &Error::PoisonLockError => None,
            &Error::DefaultError(_) => None,
        }
    }
}

impl error::Error for WriteException {
    fn description(&self) -> &str {
        &self.message
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl error::Error for BulkWriteException {
    fn description(&self) -> &str {
        &self.message
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for WriteException {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let ref wc_err = self.write_concern_error;
        let ref w_err = self.write_error;

        try!(write!(fmt, "WriteException:\n"));
        if wc_err.is_some() {
            try!(write!(fmt, "{:?}\n", wc_err));
        }

        if w_err.is_some() {
            try!(write!(fmt, "{:?}\n", w_err));
        }

        Ok(())
    }
}

impl fmt::Display for BulkWriteException {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "BulkWriteException:\n"));

        try!(write!(fmt, "Processed Requests:\n"));
        for v in &self.processed_requests {
            try!(write!(fmt, "{:?}\n", v));
        }

        try!(write!(fmt, "Unprocessed Requests:\n"));
        for v in &self.unprocessed_requests {
            try!(write!(fmt, "{:?}\n", v));
        }

        match self.write_concern_error {
            Some(ref error) => try!(write!(fmt, "{:?}\n", error)),
            None => (),
        }

        for v in &self.write_errors {
            try!(write!(fmt, "{:?}\n", v));
        }

        Ok(())
    }
}

impl fmt::Display for BulkWriteError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "BulkWriteError at index {}: ", self.index));
        match self.request {
            Some(ref request) => try!(write!(fmt, "Failed to execute request {:?}\n.", request)),
            None => try!(write!(fmt, "No additional error information was received.\n")),
        }
        Ok(())
    }
}

impl WriteException {
    pub fn new(wc_err: Option<WriteConcernError>, w_err: Option<WriteError>) -> WriteException {
        let s = if wc_err.is_some() && w_err.is_some() {
            format!("{}\n{}",
                    wc_err.as_ref().unwrap().message.to_owned(),
                    w_err.as_ref().unwrap().message.to_owned())
        } else if wc_err.is_some() {
            wc_err.as_ref().unwrap().message.to_owned()
        } else if w_err.is_some() {
            w_err.as_ref().unwrap().message.to_owned()
        } else {
            "No further information provided.".to_owned()
        };

        WriteException {
            write_concern_error: wc_err,
            write_error: w_err,
            message: s,
        }
    }
}

impl WriteConcernError {
    pub fn new<T: ToString>(code: i32, details: bson::Document, message: T) -> WriteConcernError {
        WriteConcernError {
            code: code,
            details: details,
            message: message.to_string(),
        }
    }
}

impl WriteError {
    pub fn new<T: ToString>(code: i32, message: T) -> WriteError {
        WriteError {
            code: code,
            message: message.to_string(),
        }
    }
}

impl BulkWriteException {
    pub fn new<T: ToString>(processed: Vec<WriteModel>, unprocessed: Vec<WriteModel>,
                            write_errors: Vec<BulkWriteError>, write_concern_error: Option<WriteConcernError>)
                            -> BulkWriteException {

        let mut s = match write_concern_error {
            Some(ref error) => format!("WriteConcernError: {:?}\n", error),
            None => "".to_owned(),
        };

        for v in &write_errors {
            s.push_str(&format!("WriteError: {:?}\n", v)[..]);
        }

        BulkWriteException {
            processed_requests: processed,
            unprocessed_requests: unprocessed,
            write_concern_error: write_concern_error,
            write_errors: write_errors,
            message: s.to_owned(),
        }
    }
}
<|endoftext|>


<commit_before>pub use crate::wait::NotifyReady;

use std::fmt;

use crate:: {
  error::Error,
  wait::Wait,
};

pub struct Confirmation<T, I=()> {
  kind: ConfirmationKind<T, I>,
}

impl<T, I> Confirmation<T, I> {
  pub(crate) fn new(wait: Wait<T>) -> Self {
    Self { kind: ConfirmationKind::Wait(wait) }
  }

  pub(crate) fn new_error(error: Error) -> Self {
    let (wait, wait_handle) = Wait::new();
    wait_handle.error(error);
    Self::new(wait)
  }

  pub fn as_error(self) -> Result<(), Error> {
    self.try_wait().transpose().map(|_| ())
  }

  pub fn subscribe(&self, task: Box<dyn NotifyReady + Send>) {
    match &self.kind {
      ConfirmationKind::Wait(wait)   => wait.subscribe(task),
      ConfirmationKind::Map(wait, _) => wait.subscribe(task),
    }
  }

  pub fn has_subscriber(&self) -> bool {
    match &self.kind {
      ConfirmationKind::Wait(wait)   => wait.has_subscriber(),
      ConfirmationKind::Map(wait, _) => wait.has_subscriber(),
    }
  }

  pub fn try_wait(&self) -> Option<Result<T, Error>> {
    match &self.kind {
      ConfirmationKind::Wait(wait)   => wait.try_wait(),
      ConfirmationKind::Map(wait, f) => wait.try_wait().map(|res| res.map(f)),
    }
  }

  pub fn wait(self) -> Result<T, Error> {
    match self.kind {
      ConfirmationKind::Wait(wait)   => wait.wait(),
      ConfirmationKind::Map(wait, f) => wait.wait().map(f),
    }
  }
}

impl<T> Confirmation<T> {
  pub(crate) fn map<M>(self, f: Box<dyn Fn(T) -> M + Send + 'static>) -> Confirmation<M, T> {
    Confirmation { kind: ConfirmationKind::Map(Box::new(self), f) }
  }
}

enum ConfirmationKind<T, I> {
  Wait(Wait<T>),
  Map(Box<Confirmation<I>>, Box<dyn Fn(I) -> T + Send + 'static>)
}

impl<T> From<Result<Wait<T>, Error>> for Confirmation<T> {
  fn from(res: Result<Wait<T>, Error>) -> Self {
    match res {
      Ok(wait) => Confirmation::new(wait),
      Err(err) => Confirmation::new_error(err),
    }
  }
}

impl<T> fmt::Debug for Confirmation<T> {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "Confirmation")
  }
}

#[cfg(feature = "futures")]
mod futures {
  use super::*;

  use ::futures::{
    future::TryFuture,
    task::{Context, Poll, Waker},
  };

  use std::pin::Pin;

  impl<T, I> TryFuture for Confirmation<T, I> {
    type Ok = T;
    type Error = Error;

    fn try_poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<Self::Ok, Self::Error>> {
      if !self.has_subscriber() {
        self.subscribe(Box::new(Watcher(cx.waker().clone())));
      }
      self.try_wait().map(Poll::Ready).unwrap_or(Poll::Pending)
    }
  }

  struct Watcher(Waker);

  impl NotifyReady for Watcher {
    fn notify(&self) {
      self.0.wake_by_ref();
    }
  }
}
<commit_msg>confirmation: export Watcher internally<commit_after>pub use crate::wait::NotifyReady;

use std::fmt;

use crate:: {
  error::Error,
  wait::Wait,
};

pub struct Confirmation<T, I=()> {
  kind: ConfirmationKind<T, I>,
}

impl<T, I> Confirmation<T, I> {
  pub(crate) fn new(wait: Wait<T>) -> Self {
    Self { kind: ConfirmationKind::Wait(wait) }
  }

  pub(crate) fn new_error(error: Error) -> Self {
    let (wait, wait_handle) = Wait::new();
    wait_handle.error(error);
    Self::new(wait)
  }

  pub fn as_error(self) -> Result<(), Error> {
    self.try_wait().transpose().map(|_| ())
  }

  pub fn subscribe(&self, task: Box<dyn NotifyReady + Send>) {
    match &self.kind {
      ConfirmationKind::Wait(wait)   => wait.subscribe(task),
      ConfirmationKind::Map(wait, _) => wait.subscribe(task),
    }
  }

  pub fn has_subscriber(&self) -> bool {
    match &self.kind {
      ConfirmationKind::Wait(wait)   => wait.has_subscriber(),
      ConfirmationKind::Map(wait, _) => wait.has_subscriber(),
    }
  }

  pub fn try_wait(&self) -> Option<Result<T, Error>> {
    match &self.kind {
      ConfirmationKind::Wait(wait)   => wait.try_wait(),
      ConfirmationKind::Map(wait, f) => wait.try_wait().map(|res| res.map(f)),
    }
  }

  pub fn wait(self) -> Result<T, Error> {
    match self.kind {
      ConfirmationKind::Wait(wait)   => wait.wait(),
      ConfirmationKind::Map(wait, f) => wait.wait().map(f),
    }
  }
}

impl<T> Confirmation<T> {
  pub(crate) fn map<M>(self, f: Box<dyn Fn(T) -> M + Send + 'static>) -> Confirmation<M, T> {
    Confirmation { kind: ConfirmationKind::Map(Box::new(self), f) }
  }
}

enum ConfirmationKind<T, I> {
  Wait(Wait<T>),
  Map(Box<Confirmation<I>>, Box<dyn Fn(I) -> T + Send + 'static>)
}

impl<T> From<Result<Wait<T>, Error>> for Confirmation<T> {
  fn from(res: Result<Wait<T>, Error>) -> Self {
    match res {
      Ok(wait) => Confirmation::new(wait),
      Err(err) => Confirmation::new_error(err),
    }
  }
}

impl<T> fmt::Debug for Confirmation<T> {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "Confirmation")
  }
}

#[cfg(feature = "futures")]
pub(crate) mod futures {
  use super::*;

  use ::futures::{
    future::TryFuture,
    task::{Context, Poll, Waker},
  };

  use std::pin::Pin;

  impl<T, I> TryFuture for Confirmation<T, I> {
    type Ok = T;
    type Error = Error;

    fn try_poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<Self::Ok, Self::Error>> {
      if !self.has_subscriber() {
        self.subscribe(Box::new(Watcher(cx.waker().clone())));
      }
      self.try_wait().map(Poll::Ready).unwrap_or(Poll::Pending)
    }
  }

  pub(crate) struct Watcher(pub(crate) Waker);

  impl NotifyReady for Watcher {
    fn notify(&self) {
      self.0.wake_by_ref();
    }
  }
}
<|endoftext|>


<commit_before>/// Asserts that constant expressions evaluate to `true`.
///
/// Constant expressions can be ensured to have certain properties via this
/// macro If the expression evaluates to `false`, the file will fail to compile.
/// This is synonymous to [`static_assert` in C++][static_assert].
///
/// # Alternatives
///
/// There also exists [`const_assert_eq`](macro.const_assert_eq.html) for
/// validating whether a sequence of expressions are equal to one another.
///
/// # Examples
///
/// A common use case is to guarantee properties about a constant value that's
/// generated via meta-programming.
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const VALUE: i32 = // ...
/// # 3;
///
/// const_assert!(VALUE >= 2);
/// ```
///
/// Inputs are type-checked as booleans:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(!0);
/// ```
///
/// Despite this being a macro, we see this produces a type error:
///
/// ```txt
///   | const_assert!(!0);
///   |               ^^ expected bool, found integral variable
///   |
///   = note: expected type `bool`
///              found type `{integer}`
/// ```
///
/// The following fails to compile because multiplying by 5 does not have an
/// identity property:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(5 * 5 == 5);
/// ```
///
/// [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
#[macro_export]
macro_rules! const_assert {
    ($x:expr $(,)?) => {
        const _: fn() = ||{
            let _: $crate::True = $crate::to_bool!($x);
        };
    };
}

/// Asserts that constants are equal in value.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a == b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const TWO: usize = 2;
///
/// const_assert_eq!(TWO * TWO, TWO + TWO);
/// ```
///
/// Just because 2 × 2 = 2 + 2 doesn't mean it holds true for other numbers:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_eq!(4 + 4, 4 * 4);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_eq {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x == $y);
    };
}

/// Asserts that constants are **not** equal in value.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a != b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const NUM: usize = 32;
///
/// const_assert_ne!(NUM * NUM, 64);
/// ```
///
/// The following example fails to compile because 2 is magic and 2 × 2 = 2 + 2:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_ne!(2 + 2, 2 * 2);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_ne {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x != $y);
    };
}
<commit_msg>Use `local_inner_macros` for `const_assert!`<commit_after>/// Asserts that constant expressions evaluate to `true`.
///
/// Constant expressions can be ensured to have certain properties via this
/// macro If the expression evaluates to `false`, the file will fail to compile.
/// This is synonymous to [`static_assert` in C++][static_assert].
///
/// # Alternatives
///
/// There also exists [`const_assert_eq`](macro.const_assert_eq.html) for
/// validating whether a sequence of expressions are equal to one another.
///
/// # Examples
///
/// A common use case is to guarantee properties about a constant value that's
/// generated via meta-programming.
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const VALUE: i32 = // ...
/// # 3;
///
/// const_assert!(VALUE >= 2);
/// ```
///
/// Inputs are type-checked as booleans:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(!0);
/// ```
///
/// Despite this being a macro, we see this produces a type error:
///
/// ```txt
///   | const_assert!(!0);
///   |               ^^ expected bool, found integral variable
///   |
///   = note: expected type `bool`
///              found type `{integer}`
/// ```
///
/// The following fails to compile because multiplying by 5 does not have an
/// identity property:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(5 * 5 == 5);
/// ```
///
/// [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
#[macro_export(local_inner_macros)]
macro_rules! const_assert {
    ($x:expr $(,)?) => {
        const _: fn() = ||{
            let _: $crate::True = to_bool!($x);
        };
    };
}

/// Asserts that constants are equal in value.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a == b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const TWO: usize = 2;
///
/// const_assert_eq!(TWO * TWO, TWO + TWO);
/// ```
///
/// Just because 2 × 2 = 2 + 2 doesn't mean it holds true for other numbers:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_eq!(4 + 4, 4 * 4);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_eq {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x == $y);
    };
}

/// Asserts that constants are **not** equal in value.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a != b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const NUM: usize = 32;
///
/// const_assert_ne!(NUM * NUM, 64);
/// ```
///
/// The following example fails to compile because 2 is magic and 2 × 2 = 2 + 2:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_ne!(2 + 2, 2 * 2);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_ne {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x != $y);
    };
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::units::{Direction, Point};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_location: Point,
    info_location: Point,
    message_location: Point,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_location: Point::new(16, 1),
                info_location: Point::new(1, 1),
                message_location: Point::new(16, 41),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        return None;
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_location + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_location + Point::new(-1, -1), 64, 39);
        console.print_plain(self.map_location + Point::new(0, -1), "Map");

        self.draw_box(console, self.info_location + Point::new(-1, -1), 14, 49);
        console.print_plain(self.info_location + Point::new(0, -1), "Info");

        self.draw_box(console, self.message_location + Point::new(-1, -1), 64, 9);
        console.print_plain(self.message_location + Point::new(0, -1), "Messages");
    }

    fn draw_box(&self, console: &mut Console, loc: Point, width: i32, height: i32) {
        console.put_plain(loc + Point::new(0, 0), chars::NW as char);
        console.put_plain(loc + Point::new(width, 0), chars::NE as char);
        console.put_plain(loc + Point::new(0, height), chars::SW as char);
        console.put_plain(loc + Point::new(width, height), chars::SE as char);

        for x in 1..width {
            console.put_plain(loc + Point::new(x, 0), chars::HLINE as char);
            console.put_plain(loc + Point::new(x, height), chars::HLINE as char);
        }

        for y in 1..height {
            console.put_plain(loc + Point::new(0, y), chars::VLINE as char);
            console.put_plain(loc + Point::new(width, y), chars::VLINE as char);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        for (y, line) in map.tiles.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                console.put(self.map_location + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<commit_msg>Only show the map within the borders<commit_after>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::units::{Direction, Point};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_location: Point,
    info_location: Point,
    message_location: Point,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_location: Point::new(16, 1),
                info_location: Point::new(1, 1),
                message_location: Point::new(16, 41),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        return None;
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_location + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_location + Point::new(-1, -1), 64, 39);
        console.print_plain(self.map_location + Point::new(0, -1), "Map");

        self.draw_box(console, self.info_location + Point::new(-1, -1), 14, 49);
        console.print_plain(self.info_location + Point::new(0, -1), "Info");

        self.draw_box(console, self.message_location + Point::new(-1, -1), 64, 9);
        console.print_plain(self.message_location + Point::new(0, -1), "Messages");
    }

    fn draw_box(&self, console: &mut Console, loc: Point, width: i32, height: i32) {
        console.put_plain(loc + Point::new(0, 0), chars::NW as char);
        console.put_plain(loc + Point::new(width, 0), chars::NE as char);
        console.put_plain(loc + Point::new(0, height), chars::SW as char);
        console.put_plain(loc + Point::new(width, height), chars::SE as char);

        for x in 1..width {
            console.put_plain(loc + Point::new(x, 0), chars::HLINE as char);
            console.put_plain(loc + Point::new(x, height), chars::HLINE as char);
        }

        for y in 1..height {
            console.put_plain(loc + Point::new(0, y), chars::VLINE as char);
            console.put_plain(loc + Point::new(width, y), chars::VLINE as char);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[0..height].iter().enumerate() {
            for (x, cell) in line[0..width].iter().enumerate() {
                console.put(self.map_location + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<|endoftext|>


<commit_before>use diesel;
use diesel::prelude::*;
use rocket_contrib::{JSON, SerdeError};
use uuid::Uuid;

use data::types::*;
use data::researches::get_research_list;
use data::helper::{get_research_dependency_strings, dependencies_fulfilled};

use helpers::db::DB;
use responses::{APIResponse, bad_request, created, ok};

use models::pod::Pod;
use models::user::User;
use models::research::Research;
use models::resource::Resource;

use schema::queue_entries;
use schema::pods::dsl as pods_dsl;
use schema::queues::dsl as queues_dsl;
use schema::resources::dsl as resources_dsl;
use schema::researches::dsl as research_dsl;
use schema::queue_entries::dsl as queue_entries_dsl;

use models::queue::{QueueEntry, Queue, NewQueueEntry};
use validation::queue::QueueAddResearchSerializer;

/// The user needs to be logged in to access this route!
///
/// This route returns the list of all researches and their levels/costs,
/// as well as the current level of the research for the pod of the current user.
#[get("/pod")]
pub fn get_research_entries(current_user: User, db: DB) -> APIResponse {

    let mut research_list = get_research_list();
    // Create changed pod model and push it to the DB

    let pod = pods_dsl::pods
        .filter(pods_dsl::user_id.eq(current_user.id))
        .get_result::<Pod>(&*db)
        .expect("Failed to get user pod.");

    let pod_result = research_dsl::researches
        .filter(research_dsl::pod_id.eq(pod.id))
        .get_results::<Research>(&*db);

    if pod_result.is_ok() {
        let researches = pod_result.unwrap();
        for research in researches {
            let type_result = ResearchTypes::from_string(&research.name);
            if type_result.is_err() {
                return bad_request()
                           .message(format!("Found research {}, but no matching ResearchType!",
                                            research.name)
                                            .as_str());
            }
            let research_type = type_result.unwrap();
            let list_result = research_list.get_mut(&research_type);
            if list_result.is_none() {
                return bad_request().message(format!("Found type {}, but no matching entry in our research list!", research_type).as_str());
            }

            let mut list_entry = list_result.unwrap();
            list_entry.current_level = Some(research.level);
        }
    }

    ok().message("Research data.").data(json!(&research_list))
}

/// Add a new research to the queue of the pod
/// This endpoint:
/// - Checks if dependencies for research are fulfilled
/// - Checks if there are enough resources
/// - Removes resources from db
#[post("/pod", data = "<queue_entry>", format = "application/json")]
pub fn add_research_entry(queue_entry: Result<JSON<QueueAddResearchSerializer>, SerdeError>,
                             current_user: User,
                             db: DB)
                             -> APIResponse {

    match queue_entry {
        // Return specific error if invalid JSON has been sent.
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(entry) => {
            // Check if the given research name maps to a research type.
            let result = ResearchTypes::from_string(&entry.research_name);
            match result {
                // Early return if we don't know this research name
                Err(_) => {
                    return bad_request().message(format!("No such research type `{}`",
                                                         entry.research_name)
                                                         .as_str());
                }
                Ok(research_type) => {
                    let dependency_strings = get_research_dependency_strings(&research_type);
                    let mut research_level: i32;
                    let research_list = get_research_list();
                    // Get pod and queue from db
                    let pod = pods_dsl::pods
                        .filter(pods_dsl::user_id.eq(current_user.id))
                        .first::<Pod>(&*db)
                        .unwrap();

                    let research = research_dsl::researches
                        .filter(research_dsl::pod_id.eq(pod.id))
                        .filter(research_dsl::name.eq(research_type.to_string()))
                        .get_result::<Research>(&*db);
                    match research {
                        // Research exists, we don't need to check for dependencies
                        // We just increase the level by 1
                        Ok(research) => {
                            research_level = research.level + 1;
                        }
                        // The research is not yet here. We need to check for dependencies.
                        // We just increase the level by 1
                        Err(_) => {
                            let dependencies = research_dsl::researches
                                .filter(research_dsl::name.eq_any(dependency_strings))
                                .get_results::<Research>(&*db);

                            let fulfilled = dependencies_fulfilled(&research_type,
                                                                   dependencies,
                                                                   &research_list);
                            if !fulfilled {
                                return bad_request().message("Dependencies not fulfilled.");
                            }
                            research_level = 1;
                        }
                    }

                    let queue = queues_dsl::queues
                        .filter(queues_dsl::pod_id.eq(pod.id))
                        .first::<Queue>(&*db)
                        .unwrap();

                    // Check if there already are existing queue entries for this research.
                    // In case there are, we increase the level by the amount of existing entries.
                    let existing_entries: i64 = queue_entries_dsl::queue_entries
                        .count()
                        .filter(queue_entries_dsl::queue_id.eq(queue.id))
                        .filter(queue_entries_dsl::research_name.eq(research_type.to_string()))
                        .get_result(&*db)
                        .unwrap_or(0);

                    let pod_resources = resources_dsl::resources
                        .filter(resources_dsl::pod_id.eq(pod.id))
                        .get_results(&*db)
                        .expect("Failed to get user resources.");

                    research_level += existing_entries as i32;

                    let all_levels = &research_list
                                          .get(&research_type)
                                          .as_ref()
                                          .expect("No research in yml for this type.")
                                          .levels;

                    if !(all_levels.len() <= research_level as usize) {
                        return bad_request().message("Already at max level.");
                    }
                    let costs = &all_levels[research_level as usize].resources;
                    if costs.is_some() && !Resource::check_resources(costs, pod_resources, &db) {
                        return bad_request().message("Insufficient resources.");
                    }

                    // Create a new queue entry with the given research type.
                    let new_entry_model = NewQueueEntry {
                        queue_id: queue.id.clone(),
                        module_name: None,
                        research_name: Some(entry.research_name.clone()),
                        level: research_level,
                    };

                    let new_queue_entry = diesel::insert(&new_entry_model)
                        .into(queue_entries::table)
                        .get_result::<QueueEntry>(&*db)
                        .expect("Failed to update user.");

                    created()
                        .message("Queue entry added.")
                        .data(json!(&new_queue_entry))
                }
            }
        }
    }
}

/// Remove research from queue
#[delete("/pod/<entry_uuid>")]
pub fn delete_research_entry(entry_uuid: &str, current_user: User, db: DB) -> APIResponse {

    // Parse and check if we got a valid id
    let result = Uuid::parse_str(entry_uuid);
    if result.is_err() {
        return bad_request().message("Got an invalid uuid");
    }
    let queue_entry_id = result.unwrap();

    // Get the queue entry
    let queue_entry_result = queue_entries_dsl::queue_entries
        .filter(queue_entries_dsl::id.eq(queue_entry_id))
        .first::<QueueEntry>(&*db);
    if queue_entry_result.is_err() {
        return bad_request().message("No queue entry with this id.");
    }
    let queue_entry = queue_entry_result.unwrap();

    // Check if we got an research queue entry
    if queue_entry.research_name.is_none() {
        return bad_request().message("Queue entry is a model queue entry.");
    }

    // Check if there already are existing queue entries for this research.
    // If there are entries with a higher level, we return a bad request.
    let level = queue_entry.level;
    let name = queue_entry.research_name.unwrap();
    let higher_entry = queue_entries_dsl::queue_entries
        .filter(queue_entries_dsl::queue_id.eq(queue_entry.queue_id))
        .filter(queue_entries_dsl::research_name.eq(&name))
        .filter(queue_entries_dsl::level.gt(queue_entry.level))
        .get_result::<QueueEntry>(&*db);
    if higher_entry.is_ok() {
        return bad_request().message("Can't delete. There is an queue entry with a higher level for this research.");
    }

    // Get all needed info for resource manipulation
    let research_list = get_research_list();

    let pod = pods_dsl::pods
        .filter(pods_dsl::user_id.eq(current_user.id))
        .first::<Pod>(&*db)
        .unwrap();

    let pod_resources = resources_dsl::resources
        .filter(resources_dsl::pod_id.eq(pod.id))
        .get_results::<Resource>(&*db)
        .expect("Failed to get user resources.");

    // Add resources from research to pod resources
    let all_levels = &research_list
        .get(&ResearchTypes::from_string(&name).unwrap()).unwrap().levels;
    let costs_result = &all_levels[level as usize].resources;

    if let Some(ref costs) = *costs_result {
        Resource::update_resources(costs, pod_resources, false, &db);
    }

    // Remove queue_entry from database
    diesel::delete(queue_entries_dsl::queue_entries.filter(
            queue_entries_dsl::id.eq(queue_entry_id)))
        .execute(&*db)
        .expect("Failed to remove queue_entry.");

    ok().message("Resource removed.")
}
<commit_msg>Formatting<commit_after>use diesel;
use diesel::prelude::*;
use rocket_contrib::{JSON, SerdeError};
use uuid::Uuid;

use data::types::*;
use data::researches::get_research_list;
use data::helper::{get_research_dependency_strings, dependencies_fulfilled};

use helpers::db::DB;
use responses::{APIResponse, bad_request, created, ok};

use models::pod::Pod;
use models::user::User;
use models::research::Research;
use models::resource::Resource;

use schema::queue_entries;
use schema::pods::dsl as pods_dsl;
use schema::queues::dsl as queues_dsl;
use schema::resources::dsl as resources_dsl;
use schema::researches::dsl as research_dsl;
use schema::queue_entries::dsl as queue_entries_dsl;

use models::queue::{QueueEntry, Queue, NewQueueEntry};
use validation::queue::QueueAddResearchSerializer;

/// The user needs to be logged in to access this route!
///
/// This route returns the list of all researches and their levels/costs,
/// as well as the current level of the research for the pod of the current user.
#[get("/pod")]
pub fn get_research_entries(current_user: User, db: DB) -> APIResponse {

    let mut research_list = get_research_list();
    // Create changed pod model and push it to the DB

    let pod = pods_dsl::pods
        .filter(pods_dsl::user_id.eq(current_user.id))
        .get_result::<Pod>(&*db)
        .expect("Failed to get user pod.");

    let pod_result = research_dsl::researches
        .filter(research_dsl::pod_id.eq(pod.id))
        .get_results::<Research>(&*db);

    if pod_result.is_ok() {
        let researches = pod_result.unwrap();
        for research in researches {
            let type_result = ResearchTypes::from_string(&research.name);
            if type_result.is_err() {
                return bad_request()
                           .message(format!("Found research {}, but no matching ResearchType!",
                                            research.name)
                                            .as_str());
            }
            let research_type = type_result.unwrap();
            let list_result = research_list.get_mut(&research_type);
            if list_result.is_none() {
                return bad_request().message(format!("Found type {}, but no matching entry in our research list!", research_type).as_str());
            }

            let mut list_entry = list_result.unwrap();
            list_entry.current_level = Some(research.level);
        }
    }

    ok().message("Research data.").data(json!(&research_list))
}

/// Add a new research to the queue of the pod
/// This endpoint:
/// - Checks if dependencies for research are fulfilled
/// - Checks if there are enough resources
/// - Removes resources from db
#[post("/pod", data = "<queue_entry>", format = "application/json")]
pub fn add_research_entry(queue_entry: Result<JSON<QueueAddResearchSerializer>, SerdeError>,
                          current_user: User,
                          db: DB)
                          -> APIResponse {

    match queue_entry {
        // Return specific error if invalid JSON has been sent.
        Err(error) => return bad_request().message(format!("{}", error).as_str()),
        Ok(entry) => {
            // Check if the given research name maps to a research type.
            let result = ResearchTypes::from_string(&entry.research_name);
            match result {
                // Early return if we don't know this research name
                Err(_) => {
                    return bad_request().message(format!("No such research type `{}`",
                                                         entry.research_name)
                                                         .as_str());
                }
                Ok(research_type) => {
                    let dependency_strings = get_research_dependency_strings(&research_type);
                    let mut research_level: i32;
                    let research_list = get_research_list();
                    // Get pod and queue from db
                    let pod = pods_dsl::pods
                        .filter(pods_dsl::user_id.eq(current_user.id))
                        .first::<Pod>(&*db)
                        .unwrap();

                    let research = research_dsl::researches
                        .filter(research_dsl::pod_id.eq(pod.id))
                        .filter(research_dsl::name.eq(research_type.to_string()))
                        .get_result::<Research>(&*db);
                    match research {
                        // Research exists, we don't need to check for dependencies
                        // We just increase the level by 1
                        Ok(research) => {
                            research_level = research.level + 1;
                        }
                        // The research is not yet here. We need to check for dependencies.
                        // We just increase the level by 1
                        Err(_) => {
                            let dependencies = research_dsl::researches
                                .filter(research_dsl::name.eq_any(dependency_strings))
                                .get_results::<Research>(&*db);

                            let fulfilled = dependencies_fulfilled(&research_type,
                                                                   dependencies,
                                                                   &research_list);
                            if !fulfilled {
                                return bad_request().message("Dependencies not fulfilled.");
                            }
                            research_level = 1;
                        }
                    }

                    let queue = queues_dsl::queues
                        .filter(queues_dsl::pod_id.eq(pod.id))
                        .first::<Queue>(&*db)
                        .unwrap();

                    // Check if there already are existing queue entries for this research.
                    // In case there are, we increase the level by the amount of existing entries.
                    let existing_entries: i64 = queue_entries_dsl::queue_entries
                        .count()
                        .filter(queue_entries_dsl::queue_id.eq(queue.id))
                        .filter(queue_entries_dsl::research_name.eq(research_type.to_string()))
                        .get_result(&*db)
                        .unwrap_or(0);

                    let pod_resources = resources_dsl::resources
                        .filter(resources_dsl::pod_id.eq(pod.id))
                        .get_results(&*db)
                        .expect("Failed to get user resources.");

                    research_level += existing_entries as i32;

                    let all_levels = &research_list
                                          .get(&research_type)
                                          .as_ref()
                                          .expect("No research in yml for this type.")
                                          .levels;

                    if !(all_levels.len() <= research_level as usize) {
                        return bad_request().message("Already at max level.");
                    }
                    let costs = &all_levels[research_level as usize].resources;
                    if costs.is_some() && !Resource::check_resources(costs, pod_resources, &db) {
                        return bad_request().message("Insufficient resources.");
                    }

                    // Create a new queue entry with the given research type.
                    let new_entry_model = NewQueueEntry {
                        queue_id: queue.id.clone(),
                        module_name: None,
                        research_name: Some(entry.research_name.clone()),
                        level: research_level,
                    };

                    let new_queue_entry = diesel::insert(&new_entry_model)
                        .into(queue_entries::table)
                        .get_result::<QueueEntry>(&*db)
                        .expect("Failed to update user.");

                    created()
                        .message("Queue entry added.")
                        .data(json!(&new_queue_entry))
                }
            }
        }
    }
}

/// Remove research from queue
#[delete("/pod/<entry_uuid>")]
pub fn delete_research_entry(entry_uuid: &str, current_user: User, db: DB) -> APIResponse {

    // Parse and check if we got a valid id
    let result = Uuid::parse_str(entry_uuid);
    if result.is_err() {
        return bad_request().message("Got an invalid uuid");
    }
    let queue_entry_id = result.unwrap();

    // Get the queue entry
    let queue_entry_result = queue_entries_dsl::queue_entries
        .filter(queue_entries_dsl::id.eq(queue_entry_id))
        .first::<QueueEntry>(&*db);
    if queue_entry_result.is_err() {
        return bad_request().message("No queue entry with this id.");
    }
    let queue_entry = queue_entry_result.unwrap();

    // Check if we got an research queue entry
    if queue_entry.research_name.is_none() {
        return bad_request().message("Queue entry is a model queue entry.");
    }

    // Check if there already are existing queue entries for this research.
    // If there are entries with a higher level, we return a bad request.
    let level = queue_entry.level;
    let name = queue_entry.research_name.unwrap();
    let higher_entry = queue_entries_dsl::queue_entries
        .filter(queue_entries_dsl::queue_id.eq(queue_entry.queue_id))
        .filter(queue_entries_dsl::research_name.eq(&name))
        .filter(queue_entries_dsl::level.gt(queue_entry.level))
        .get_result::<QueueEntry>(&*db);
    if higher_entry.is_ok() {
        return bad_request().message("Can't delete. There is an queue entry with a higher level for this research.");
    }

    // Get all needed info for resource manipulation
    let research_list = get_research_list();

    let pod = pods_dsl::pods
        .filter(pods_dsl::user_id.eq(current_user.id))
        .first::<Pod>(&*db)
        .unwrap();

    let pod_resources = resources_dsl::resources
        .filter(resources_dsl::pod_id.eq(pod.id))
        .get_results::<Resource>(&*db)
        .expect("Failed to get user resources.");

    // Add resources from research to pod resources
    let all_levels = &research_list
                          .get(&ResearchTypes::from_string(&name).unwrap())
                          .unwrap()
                          .levels;
    let costs_result = &all_levels[level as usize].resources;

    if let Some(ref costs) = *costs_result {
        Resource::update_resources(costs, pod_resources, false, &db);
    }

    // Remove queue_entry from database
    diesel::delete(queue_entries_dsl::queue_entries
                       .filter(queue_entries_dsl::id.eq(queue_entry_id)))
            .execute(&*db)
            .expect("Failed to remove queue_entry.");

    ok().message("Resource removed.")
}
<|endoftext|>


<commit_before>extern crate hlua;

#[test]
fn readwrite() {
    #[derive(Clone)]
    struct Foo;
    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = ();
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, ((), L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }
    impl<'lua, L> hlua::LuaRead<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        fn lua_read_at_position(lua: L, index: i32) -> Result<Foo, L> {
            let val: Result<hlua::userdata::UserdataOnStack<Foo, _>, _> =
                hlua::LuaRead::lua_read_at_position(lua, index);
            val.map(|d| d.clone())
        }
    }

    let mut lua = hlua::Lua::new();

    lua.set("a", Foo);
    let _: Foo = lua.get("a").unwrap();
}

#[test]
fn destructor_called() {
    use std::sync::{Arc, Mutex};

    let called = Arc::new(Mutex::new(false));

    struct Foo {
        called: Arc<Mutex<bool>>,
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            let mut called = self.called.lock().unwrap();
            (*called) = true;
        }
    }

    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = ();
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, ((), L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }

    {
        let mut lua = hlua::Lua::new();
        lua.set("a", Foo { called: called.clone() });
    }

    let locked = called.lock().unwrap();
    assert!(*locked);
}

#[test]
fn type_check() {
    #[derive(Clone)]
    struct Foo;
    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = ();
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, ((), L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }
    impl<'lua, L> hlua::LuaRead<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        fn lua_read_at_position(lua: L, index: i32) -> Result<Foo, L> {
            let val: Result<hlua::userdata::UserdataOnStack<Foo, _>, _> =
                hlua::LuaRead::lua_read_at_position(lua, index);
            val.map(|d| d.clone())
        }
    }

    #[derive(Clone)]
    struct Bar;
    impl<'lua, L> hlua::Push<L> for Bar
        where L: hlua::AsMutLua<'lua>
    {
        type Err = ();
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, ((), L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }
    impl<'lua, L> hlua::LuaRead<L> for Bar
        where L: hlua::AsMutLua<'lua>
    {
        fn lua_read_at_position(lua: L, index: i32) -> Result<Bar, L> {
            let val: Result<hlua::userdata::UserdataOnStack<Bar, _>, _> =
                hlua::LuaRead::lua_read_at_position(lua, index);
            val.map(|d| d.clone())
        }
    }

    let mut lua = hlua::Lua::new();

    lua.set("a", Foo);

    let x: Option<Bar> = lua.get("a");
    assert!(x.is_none())
}

#[test]
fn metatables() {
    #[derive(Clone)]
    struct Foo;
    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = ();
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, ((), L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |mut table| {
                table.set("__index".to_string(),
                          vec![("test".to_string(), hlua::function0(|| 5))]);
            }))
        }
    }

    let mut lua = hlua::Lua::new();

    lua.set("a", Foo);

    let x: i32 = lua.execute("return a.test()").unwrap();
    assert_eq!(x, 5);
}
<commit_msg>Fix tests<commit_after>extern crate hlua;

#[test]
fn readwrite() {
    #[derive(Clone)]
    struct Foo;
    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = hlua::Void;
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, (hlua::Void, L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }
    impl<'lua, L> hlua::LuaRead<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        fn lua_read_at_position(lua: L, index: i32) -> Result<Foo, L> {
            let val: Result<hlua::userdata::UserdataOnStack<Foo, _>, _> =
                hlua::LuaRead::lua_read_at_position(lua, index);
            val.map(|d| d.clone())
        }
    }

    let mut lua = hlua::Lua::new();

    lua.set("a", Foo);
    let _: Foo = lua.get("a").unwrap();
}

#[test]
fn destructor_called() {
    use std::sync::{Arc, Mutex};

    let called = Arc::new(Mutex::new(false));

    struct Foo {
        called: Arc<Mutex<bool>>,
    }

    impl Drop for Foo {
        fn drop(&mut self) {
            let mut called = self.called.lock().unwrap();
            (*called) = true;
        }
    }

    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = hlua::Void;
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, (hlua::Void, L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }

    {
        let mut lua = hlua::Lua::new();
        lua.set("a", Foo { called: called.clone() });
    }

    let locked = called.lock().unwrap();
    assert!(*locked);
}

#[test]
fn type_check() {
    #[derive(Clone)]
    struct Foo;
    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = hlua::Void;
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, (hlua::Void, L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }
    impl<'lua, L> hlua::LuaRead<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        fn lua_read_at_position(lua: L, index: i32) -> Result<Foo, L> {
            let val: Result<hlua::userdata::UserdataOnStack<Foo, _>, _> =
                hlua::LuaRead::lua_read_at_position(lua, index);
            val.map(|d| d.clone())
        }
    }

    #[derive(Clone)]
    struct Bar;
    impl<'lua, L> hlua::Push<L> for Bar
        where L: hlua::AsMutLua<'lua>
    {
        type Err = hlua::Void;
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, (hlua::Void, L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |_| {}))
        }
    }
    impl<'lua, L> hlua::LuaRead<L> for Bar
        where L: hlua::AsMutLua<'lua>
    {
        fn lua_read_at_position(lua: L, index: i32) -> Result<Bar, L> {
            let val: Result<hlua::userdata::UserdataOnStack<Bar, _>, _> =
                hlua::LuaRead::lua_read_at_position(lua, index);
            val.map(|d| d.clone())
        }
    }

    let mut lua = hlua::Lua::new();

    lua.set("a", Foo);

    let x: Option<Bar> = lua.get("a");
    assert!(x.is_none())
}

#[test]
fn metatables() {
    #[derive(Clone)]
    struct Foo;
    impl<'lua, L> hlua::Push<L> for Foo
        where L: hlua::AsMutLua<'lua>
    {
        type Err = hlua::Void;
        fn push_to_lua(self, lua: L) -> Result<hlua::PushGuard<L>, (hlua::Void, L)> {
            Ok(hlua::userdata::push_userdata(self, lua, |mut table| {
                table.set("__index".to_string(),
                          vec![("test".to_string(), hlua::function0(|| 5))]);
            }))
        }
    }

    let mut lua = hlua::Lua::new();

    lua.set("a", Foo);

    let x: i32 = lua.execute("return a.test()").unwrap();
    assert_eq!(x, 5);
}
<|endoftext|>


<commit_before>use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::GEN_ALIGNMENT_BITS;
use gc::{align_gen, formatted_size};

pub fn resize_gens_after_minor(
    _min_heap_size: usize,
    max_heap_size: usize,
    young: &YoungGen,
    old: &OldGen,
    verbose: bool,
) -> bool {
    let old_size = align_gen(old.active_size());
    assert!(young.eden_active().size() == 0);

    let (young_size, old_size) = compute_young_size(max_heap_size, old_size);
    assert!(young_size <= young.committed_size());

    if verbose {
        println!(
            "GC: Resize after Minor GC (young committed {}->{}, old committed {}->{})",
            formatted_size(young.committed_size()),
            formatted_size(young_size),
            formatted_size(old.committed_size()),
            formatted_size(old_size),
        );
    }

    young.set_committed_size(young_size);
    old.set_committed_size(old_size);

    young_size < old_size / 16
}

pub fn resize_gens_after_full(
    _min_heap_size: usize,
    max_heap_size: usize,
    young: &YoungGen,
    old: &OldGen,
    verbose: bool,
) {
    let old_size = align_gen(old.active_size());
    assert!(young.active_size() == 0);

    let (young_size, old_size) = compute_young_size(max_heap_size, old_size);

    if verbose {
        println!(
            "GC: Resize after Full GC (young committed {}->{}, old committed {}->{})",
            formatted_size(young.committed_size()),
            formatted_size(young_size),
            formatted_size(old.committed_size()),
            formatted_size(old_size),
        );
    }

    young.set_committed_size(young_size);
    old.set_committed_size(old_size);
}

// calculate young generation size from old generation and heap size.
fn compute_young_size(heap_size: usize, old_size: usize) -> (usize, usize) {
    assert!(old_size <= heap_size);
    let old_size = align_gen(old_size);
    let rest = ((heap_size - old_size) >> (GEN_ALIGNMENT_BITS + 1)) << GEN_ALIGNMENT_BITS;

    let young_size = rest;
    let old_size = heap_size - young_size;

    assert!(young_size > 0 && old_size > 0 && old_size + young_size <= heap_size);
    (young_size, old_size)
}
<commit_msg>swiper: add comment<commit_after>use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::GEN_ALIGNMENT_BITS;
use gc::{align_gen, formatted_size};

pub fn resize_gens_after_minor(
    _min_heap_size: usize,
    max_heap_size: usize,
    young: &YoungGen,
    old: &OldGen,
    verbose: bool,
) -> bool {
    let old_size = align_gen(old.active_size());
    assert!(young.eden_active().size() == 0);

    let (young_size, old_size) = compute_young_size(max_heap_size, old_size);
    assert!(young_size <= young.committed_size());

    if verbose {
        println!(
            "GC: Resize after Minor GC (young committed {}->{}, old committed {}->{})",
            formatted_size(young.committed_size()),
            formatted_size(young_size),
            formatted_size(old.committed_size()),
            formatted_size(old_size),
        );
    }

    young.set_committed_size(young_size);
    old.set_committed_size(old_size);

    // force full GC when young collection becomes too small
    young_size < old_size / 16
}

pub fn resize_gens_after_full(
    _min_heap_size: usize,
    max_heap_size: usize,
    young: &YoungGen,
    old: &OldGen,
    verbose: bool,
) {
    let old_size = align_gen(old.active_size());
    assert!(young.active_size() == 0);

    let (young_size, old_size) = compute_young_size(max_heap_size, old_size);

    if verbose {
        println!(
            "GC: Resize after Full GC (young committed {}->{}, old committed {}->{})",
            formatted_size(young.committed_size()),
            formatted_size(young_size),
            formatted_size(old.committed_size()),
            formatted_size(old_size),
        );
    }

    young.set_committed_size(young_size);
    old.set_committed_size(old_size);
}

// calculate young generation size from old generation and heap size.
fn compute_young_size(heap_size: usize, old_size: usize) -> (usize, usize) {
    assert!(old_size <= heap_size);
    let old_size = align_gen(old_size);
    let rest = ((heap_size - old_size) >> (GEN_ALIGNMENT_BITS + 1)) << GEN_ALIGNMENT_BITS;

    let young_size = rest;
    let old_size = heap_size - young_size;

    assert!(young_size > 0 && old_size > 0 && old_size + young_size <= heap_size);
    (young_size, old_size)
}
<|endoftext|>


<commit_before>use cpu::io;
use super::keydown;

pub static IRQ: u8 = 0x20 + 1;

pub static Layout: &'static str = "\
\x00\x1B1234567890-=\x08\
\tqwertyuiop[]\n\
\x00asdfghjkl;'`\
\x00\\zxcvbnm,./\x00\
*\x00 ";

static LayoutShift: &'static str = "\
\x00\x1B!@#$%^&*()_+\x08\
\tQWERTYUIOP{}\n\
\x00ASDFGHJKL:\"~\
\x00|ZXCVBNM<>?\x00\
*\x00 ";

static mut shift: bool = false;
static mut caps_lock: bool = false;
static mut led_state: u8 = 0;

fn led(state: u8) {
    io::wait(0x64, 2);
    io::out(0x60, 0xEDu8);
    io::wait(0x64, 2);
    unsafe {
        led_state ^= state;
        io::out(0x60, led_state);
    }
}

fn isalpha(c: u8) -> bool {
    ((c | 0x20) - 'a' as u8) < 26
}

#[no_split_stack]
fn keypress(code: u8) {
    match (code & 0x7f, code & 0x80 == 0) {
        (0x2A, down) | (0x36, down) => unsafe { shift = down },
        (0x3A, true) => unsafe { // Caps lock
            caps_lock = !caps_lock;
            led(0b100)
        },
        (0x45, true) => led(0b010), // Number lock
        (0x46, true) => led(0b001), // Scroll lock
        (c, true) if c < 0x3A => unsafe {
            // handle character
            keydown.map(|f| {
                let mut ch = if shift { LayoutShift[c] } else { Layout[c] };
                if ch != 0 {
                    if caps_lock && isalpha(ch) {
                        ch ^= 1 << 5;
                    }
                    f(ch);
                }
            });
        },
        _ => {}
    }
}

#[no_split_stack]
#[inline(never)]
pub unsafe fn isr_addr() -> extern "C" unsafe fn() {
    asm!("jmp skip_isr_addr
      isr_addr_asm:
          .word 0xa80f
          .word 0xa00f
          .byte 0x06
          .byte 0x1e
          pusha"
        :::: "intel");

          keypress(io::inb(0x60));
          io::out(0x20, 0x20u8);

    asm!("popa
          .byte 0x1f
          .byte 0x07
          .word 0xa10f
          .word 0xa90f
          iretd
      skip_isr_addr:"
        :::: "intel");

    // it must be referenced in code
    isr_addr_asm
}

extern "C" { fn isr_addr_asm(); }
<commit_msg>x86: cosmetic changes<commit_after>use cpu::io;
use super::keydown;

pub static IRQ: u8 = 0x20 + 1;

pub static Layout: &'static str = "\
\x00\x1B1234567890-=\x08\
\tqwertyuiop[]\n\
\x00asdfghjkl;'`\
\x00\\zxcvbnm,./\x00\
*\x00 ";

static LayoutShift: &'static str = "\
\x00\x1B!@#$%^&*()_+\x08\
\tQWERTYUIOP{}\n\
\x00ASDFGHJKL:\"~\
\x00|ZXCVBNM<>?\x00\
*\x00 ";

static mut shift: bool = false;
static mut caps_lock: bool = false;
static mut led_state: u8 = 0;

fn led(state: u8) {
    io::wait(0x64, 2);
    io::out(0x60, 0xEDu8);
    io::wait(0x64, 2);
    unsafe {
        led_state ^= state;
        io::out(0x60, led_state);
    }
}

fn isalpha(c: u8) -> bool {
    ((c | 0x20) - 'a' as u8) < 26
}

#[no_split_stack]
fn keypress(code: u8) {
    match (code & 0x7f, code & 0x80 == 0) {
        (0x2A, down) | (0x36, down) => unsafe { shift = down },
        (0x3A, true) => unsafe { // Caps lock
            caps_lock = !caps_lock;
            led(0b100)
        },
        (0x45, true) => led(0b010), // Number lock
        (0x46, true) => led(0b001), // Scroll lock
        (c, true) if c < 0x3A => unsafe {
            // handle character
            let mut ch = if shift { LayoutShift[c] } else { Layout[c] };
            if ch != 0 {
                if caps_lock && isalpha(ch) {
                    ch ^= 1 << 5;
                }
                keydown.map(|f| f(ch) );
            }
        },
        _ => {}
    }
}

#[no_split_stack]
#[inline(never)]
pub unsafe fn isr_addr() -> extern "C" unsafe fn() {
    asm!("jmp skip_isr_addr
      isr_addr_asm:
          push gs
          push fs
          .byte 0x06
          .byte 0x1e
          pusha"
        :::: "intel");

          keypress(io::inb(0x60));
          io::out(0x20, 0x20u8);

    asm!("popa
          .byte 0x1f // pop ds
          .byte 0x07 // pop es
          pop fs
          pop gs
          iretd
      skip_isr_addr:"
        :::: "intel");

    // it must be referenced in code
    isr_addr_asm
}

extern "C" { fn isr_addr_asm(); }
<|endoftext|>


<commit_before>use cmds::{CommandClass, Message};
use error::{Error, ErrorKind};

/// The Multilevel Switch Command Class is used to control devices with variable levels
/// such as dimmer switches
#[derive(Debug, Clone)]
pub struct SwitchMultilevel;

impl SwitchMultilevel {
    /// The Multilevel Switch Set command, version 1 is used to set a u8 value.
    pub fn set<N, V>(node_id: N, value: V) -> Message
    where N: Into<u8>, V: Into<u8> {
        // generate the message
        Message::new(node_id.into(), CommandClass::SWITCH_MULTILEVEL, 0x01, vec!(value.into()))
    }

    /// The Multilevel Switch Get command, version 1 is used to request the status
    /// of a device with variable levels capability.
    pub fn get<N>(node_id: N) -> Message
    where N: Into<u8> {
        Message::new(node_id.into(), CommandClass::SWITCH_MULTILEVEL, 0x02, vec!())
    }

    /// The Multilevel Switch Report command, version 1 is used to advertise the
    /// status of a device with variable levels capability.
    pub fn report<M>(msg: M) -> Result<u8, Error>
    where M: Into<Vec<u8>> {
        // get the message
        let msg = msg.into();

        // the message need to be exact 6 digits long
        // if msg.len() != 6 {
        //     return Err(Error::new(ErrorKind::UnknownZWave, "Message is to short"));
        // }

        // check the CommandClass and command
        if msg[3] != CommandClass::SWITCH_MULTILEVEL as u8 || msg[4] != 0x03 {
            return Err(Error::new(ErrorKind::UnknownZWave, "Answer contained wrong command class"));
        }

        let val = msg[5];

        // return the value
        Ok(val)
    }
}
<commit_msg>adds message length check to switch multilevel get<commit_after>use cmds::{CommandClass, Message};
use error::{Error, ErrorKind};

/// The Multilevel Switch Command Class is used to control devices with variable levels
/// such as dimmer switches
#[derive(Debug, Clone)]
pub struct SwitchMultilevel;

impl SwitchMultilevel {
    /// The Multilevel Switch Set command, version 1 is used to set a u8 value.
    pub fn set<N, V>(node_id: N, value: V) -> Message
    where N: Into<u8>, V: Into<u8> {
        // generate the message
        Message::new(node_id.into(), CommandClass::SWITCH_MULTILEVEL, 0x01, vec!(value.into()))
    }

    /// The Multilevel Switch Get command, version 1 is used to request the status
    /// of a device with variable levels capability.
    pub fn get<N>(node_id: N) -> Message
    where N: Into<u8> {
        Message::new(node_id.into(), CommandClass::SWITCH_MULTILEVEL, 0x02, vec!())
    }

    /// The Multilevel Switch Report command, version 1 is used to advertise the
    /// status of a device with variable levels capability.
    pub fn report<M>(msg: M) -> Result<u8, Error>
    where M: Into<Vec<u8>> {
        // get the message
        let msg = msg.into();

        // the message need to be at least 7 digits long
        if msg.len() < 7 {
             return Err(Error::new(ErrorKind::UnknownZWave, "Message is to short"));
        }

        // check the CommandClass and command
        if msg[3] != CommandClass::SWITCH_MULTILEVEL as u8 || msg[4] != 0x03 {
            return Err(Error::new(ErrorKind::UnknownZWave, "Answer contained wrong command class"));
        }

        let val = msg[5];

        // return the value
        Ok(val)
    }
}
<|endoftext|>