<commit_before>//! This module contains types for all kinds of errors that can occur when
//! converting between http requests / responses and ruma's representation of
//! matrix API requests / responses.

use std::{error::Error as StdError, fmt};

use bytes::BufMut;
use serde_json::{from_slice as from_json_slice, Value as JsonValue};
use thiserror::Error;

use super::{EndpointError, MatrixVersion, OutgoingResponse};

/// A general-purpose Matrix error type consisting of an HTTP status code and a JSON body.
///
/// Note that individual `ruma-*-api` crates may provide more specific error types.
#[allow(clippy::exhaustive_structs)]
#[derive(Clone, Debug)]
pub struct MatrixError {
    /// The http response's status code.
    pub status_code: http::StatusCode,

    /// The http response's body.
    pub body: JsonValue,
}

impl fmt::Display for MatrixError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[{}] ", self.status_code.as_u16())?;
        fmt::Display::fmt(&self.body, f)
    }
}

impl StdError for MatrixError {}

impl OutgoingResponse for MatrixError {
    fn try_into_http_response<T: Default + BufMut>(
        self,
    ) -> Result<http::Response<T>, IntoHttpError> {
        http::Response::builder()
            .header(http::header::CONTENT_TYPE, "application/json")
            .status(self.status_code)
            .body(crate::serde::json_to_buf(&self.body)?)
            .map_err(Into::into)
    }
}

impl EndpointError for MatrixError {
    fn try_from_http_response<T: AsRef<[u8]>>(
        response: http::Response<T>,
    ) -> Result<Self, DeserializationError> {
        Ok(Self {
            status_code: response.status(),
            body: from_json_slice(response.body().as_ref())?,
        })
    }
}

/// An error when converting one of ruma's endpoint-specific request or response
/// types to the corresponding http type.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum IntoHttpError {
    /// Tried to create an authentication request without an access token.
    #[error(
        "This endpoint has to be converted to http::Request using \
         try_into_authenticated_http_request"
    )]
    NeedsAuthentication,

    /// Tried to create a request with an old enough version, for which no unstable endpoint
    /// exists.
    ///
    /// This is also a fallback error for if the version is too new for this endpoint.
    #[error("Endpoint was not supported by server-reported versions, but no unstable path to fall back to was defined.")]
    NoUnstablePath,

    /// Tried to create a request with [`MatrixVersion`]s for all of which this endpoint was
    /// removed.
    #[error("Could not create any path variant for endpoint, as it was removed in version {0}")]
    EndpointRemoved(MatrixVersion),

    /// JSON serialization failed.
    #[error("JSON serialization failed: {0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter serialization failed.
    #[error("Query parameter serialization failed: {0}")]
    Query(#[from] crate::serde::urlencoded::ser::Error),

    /// Header serialization failed.
    #[error("Header serialization failed: {0}")]
    Header(#[from] http::header::InvalidHeaderValue),

    /// HTTP request construction failed.
    #[error("HTTP request construction failed: {0}")]
    Http(#[from] http::Error),
}

/// An error when converting a http request to one of ruma's endpoint-specific request types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum FromHttpRequestError {
    /// Deserialization failed
    #[error("deserialization failed: {0}")]
    Deserialization(DeserializationError),

    /// HTTP method mismatch
    #[error("http method mismatch: expected {expected}, received: {received}")]
    MethodMismatch {
        /// expected http method
        expected: http::method::Method,
        /// received http method
        received: http::method::Method,
    },
}

impl<T> From<T> for FromHttpRequestError
where
    T: Into<DeserializationError>,
{
    fn from(err: T) -> Self {
        Self::Deserialization(err.into())
    }
}

/// An error when converting a http response to one of Ruma's endpoint-specific response types.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromHttpResponseError<E> {
    /// Deserialization failed
    Deserialization(DeserializationError),

    /// The server returned a non-success status
    Server(ServerError<E>),
}

impl<E> FromHttpResponseError<E> {
    /// Map `FromHttpResponseError<E>` to `FromHttpResponseError<F>` by applying a function to a
    /// contained `Server` value, leaving a `Deserialization` value untouched.
    pub fn map<F>(
        self,
        f: impl FnOnce(ServerError<E>) -> ServerError<F>,
    ) -> FromHttpResponseError<F> {
        match self {
            Self::Deserialization(d) => FromHttpResponseError::Deserialization(d),
            Self::Server(s) => FromHttpResponseError::Server(f(s)),
        }
    }
}

impl<E, F> FromHttpResponseError<Result<E, F>> {
    /// Transpose `FromHttpResponseError<Result<E, F>>` to `Result<FromHttpResponseError<E>, F>`.
    pub fn transpose(self) -> Result<FromHttpResponseError<E>, F> {
        match self {
            Self::Deserialization(d) => Ok(FromHttpResponseError::Deserialization(d)),
            Self::Server(s) => s.transpose().map(FromHttpResponseError::Server),
        }
    }
}

impl<E: fmt::Display> fmt::Display for FromHttpResponseError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Deserialization(err) => write!(f, "deserialization failed: {}", err),
            Self::Server(err) => write!(f, "the server returned an error: {}", err),
        }
    }
}

impl<E> From<ServerError<E>> for FromHttpResponseError<E> {
    fn from(err: ServerError<E>) -> Self {
        Self::Server(err)
    }
}

impl<E, T> From<T> for FromHttpResponseError<E>
where
    T: Into<DeserializationError>,
{
    fn from(err: T) -> Self {
        Self::Deserialization(err.into())
    }
}

impl<E: StdError> StdError for FromHttpResponseError<E> {}

/// An error was reported by the server (HTTP status code 4xx or 5xx)
#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum ServerError<E> {
    /// An error that is expected to happen under certain circumstances and
    /// that has a well-defined structure
    Known(E),

    /// An error of unexpected type of structure
    Unknown(DeserializationError),
}

impl<E> ServerError<E> {
    /// Map `ServerError<E>` to `ServerError<F>` by applying a function to a contained `Known`
    /// value, leaving an `Unknown` value untouched.
    pub fn map<F>(self, f: impl FnOnce(E) -> F) -> ServerError<F> {
        match self {
            Self::Known(k) => ServerError::Known(f(k)),
            Self::Unknown(u) => ServerError::Unknown(u),
        }
    }
}

impl<E, F> ServerError<Result<E, F>> {
    /// Transpose `ServerError<Result<E, F>>` to `Result<ServerError<E>, F>`.
    pub fn transpose(self) -> Result<ServerError<E>, F> {
        match self {
            Self::Known(Ok(k)) => Ok(ServerError::Known(k)),
            Self::Known(Err(e)) => Err(e),
            Self::Unknown(u) => Ok(ServerError::Unknown(u)),
        }
    }
}

impl<E: fmt::Display> fmt::Display for ServerError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ServerError::Known(e) => fmt::Display::fmt(e, f),
            ServerError::Unknown(res_err) => fmt::Display::fmt(res_err, f),
        }
    }
}

impl<E: StdError> StdError for ServerError<E> {}

/// An error when converting a http request / response to one of ruma's endpoint-specific request /
/// response types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum DeserializationError {
    /// Encountered invalid UTF-8.
    #[error("{0}")]
    Utf8(#[from] std::str::Utf8Error),

    /// JSON deserialization failed.
    #[error("{0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter deserialization failed.
    #[error("{0}")]
    Query(#[from] crate::serde::urlencoded::de::Error),

    /// Got an invalid identifier.
    #[error("{0}")]
    Ident(#[from] crate::IdParseError),

    /// Header value deserialization failed.
    #[error("{0}")]
    Header(#[from] HeaderDeserializationError),
}

impl From<std::convert::Infallible> for DeserializationError {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}

impl From<http::header::ToStrError> for DeserializationError {
    fn from(err: http::header::ToStrError) -> Self {
        Self::Header(HeaderDeserializationError::ToStrError(err))
    }
}

/// An error with the http headers.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum HeaderDeserializationError {
    /// Failed to convert `http::header::HeaderValue` to `str`.
    #[error("{0}")]
    ToStrError(http::header::ToStrError),

    /// The given required header is missing.
    #[error("Missing header `{0}`")]
    MissingHeader(String),
}

/// An error that happens when Ruma cannot understand a Matrix version.
#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct UnknownVersionError;

impl fmt::Display for UnknownVersionError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Version string was unknown.")
    }
}

impl StdError for UnknownVersionError {}
<commit_msg>api: Update error messages<commit_after>//! This module contains types for all kinds of errors that can occur when
//! converting between http requests / responses and ruma's representation of
//! matrix API requests / responses.

use std::{error::Error as StdError, fmt};

use bytes::BufMut;
use serde_json::{from_slice as from_json_slice, Value as JsonValue};
use thiserror::Error;

use super::{EndpointError, MatrixVersion, OutgoingResponse};

/// A general-purpose Matrix error type consisting of an HTTP status code and a JSON body.
///
/// Note that individual `ruma-*-api` crates may provide more specific error types.
#[allow(clippy::exhaustive_structs)]
#[derive(Clone, Debug)]
pub struct MatrixError {
    /// The http response's status code.
    pub status_code: http::StatusCode,

    /// The http response's body.
    pub body: JsonValue,
}

impl fmt::Display for MatrixError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[{}] ", self.status_code.as_u16())?;
        fmt::Display::fmt(&self.body, f)
    }
}

impl StdError for MatrixError {}

impl OutgoingResponse for MatrixError {
    fn try_into_http_response<T: Default + BufMut>(
        self,
    ) -> Result<http::Response<T>, IntoHttpError> {
        http::Response::builder()
            .header(http::header::CONTENT_TYPE, "application/json")
            .status(self.status_code)
            .body(crate::serde::json_to_buf(&self.body)?)
            .map_err(Into::into)
    }
}

impl EndpointError for MatrixError {
    fn try_from_http_response<T: AsRef<[u8]>>(
        response: http::Response<T>,
    ) -> Result<Self, DeserializationError> {
        Ok(Self {
            status_code: response.status(),
            body: from_json_slice(response.body().as_ref())?,
        })
    }
}

/// An error when converting one of ruma's endpoint-specific request or response
/// types to the corresponding http type.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum IntoHttpError {
    /// Tried to create an authentication request without an access token.
    #[error("no access token given, but this endpoint requires one")]
    NeedsAuthentication,

    /// Tried to create a request with an old enough version, for which no unstable endpoint
    /// exists.
    ///
    /// This is also a fallback error for if the version is too new for this endpoint.
    #[error(
        "endpoint was not supported by server-reported versions, \
         but no unstable path to fall back to was defined"
    )]
    NoUnstablePath,

    /// Tried to create a request with [`MatrixVersion`]s for all of which this endpoint was
    /// removed.
    #[error("could not create any path variant for endpoint, as it was removed in version {0}")]
    EndpointRemoved(MatrixVersion),

    /// JSON serialization failed.
    #[error("JSON serialization failed: {0}")]
    Json(#[from] serde_json::Error),

    /// Query parameter serialization failed.
    #[error("query parameter serialization failed: {0}")]
    Query(#[from] crate::serde::urlencoded::ser::Error),

    /// Header serialization failed.
    #[error("header serialization failed: {0}")]
    Header(#[from] http::header::InvalidHeaderValue),

    /// HTTP request construction failed.
    #[error("HTTP request construction failed: {0}")]
    Http(#[from] http::Error),
}

/// An error when converting a http request to one of ruma's endpoint-specific request types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum FromHttpRequestError {
    /// Deserialization failed
    #[error("deserialization failed: {0}")]
    Deserialization(DeserializationError),

    /// HTTP method mismatch
    #[error("http method mismatch: expected {expected}, received: {received}")]
    MethodMismatch {
        /// expected http method
        expected: http::method::Method,
        /// received http method
        received: http::method::Method,
    },
}

impl<T> From<T> for FromHttpRequestError
where
    T: Into<DeserializationError>,
{
    fn from(err: T) -> Self {
        Self::Deserialization(err.into())
    }
}

/// An error when converting a http response to one of Ruma's endpoint-specific response types.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromHttpResponseError<E> {
    /// Deserialization failed
    Deserialization(DeserializationError),

    /// The server returned a non-success status
    Server(ServerError<E>),
}

impl<E> FromHttpResponseError<E> {
    /// Map `FromHttpResponseError<E>` to `FromHttpResponseError<F>` by applying a function to a
    /// contained `Server` value, leaving a `Deserialization` value untouched.
    pub fn map<F>(
        self,
        f: impl FnOnce(ServerError<E>) -> ServerError<F>,
    ) -> FromHttpResponseError<F> {
        match self {
            Self::Deserialization(d) => FromHttpResponseError::Deserialization(d),
            Self::Server(s) => FromHttpResponseError::Server(f(s)),
        }
    }
}

impl<E, F> FromHttpResponseError<Result<E, F>> {
    /// Transpose `FromHttpResponseError<Result<E, F>>` to `Result<FromHttpResponseError<E>, F>`.
    pub fn transpose(self) -> Result<FromHttpResponseError<E>, F> {
        match self {
            Self::Deserialization(d) => Ok(FromHttpResponseError::Deserialization(d)),
            Self::Server(s) => s.transpose().map(FromHttpResponseError::Server),
        }
    }
}

impl<E: fmt::Display> fmt::Display for FromHttpResponseError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Deserialization(err) => write!(f, "deserialization failed: {}", err),
            Self::Server(err) => write!(f, "the server returned an error: {}", err),
        }
    }
}

impl<E> From<ServerError<E>> for FromHttpResponseError<E> {
    fn from(err: ServerError<E>) -> Self {
        Self::Server(err)
    }
}

impl<E, T> From<T> for FromHttpResponseError<E>
where
    T: Into<DeserializationError>,
{
    fn from(err: T) -> Self {
        Self::Deserialization(err.into())
    }
}

impl<E: StdError> StdError for FromHttpResponseError<E> {}

/// An error was reported by the server (HTTP status code 4xx or 5xx)
#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum ServerError<E> {
    /// An error that is expected to happen under certain circumstances and
    /// that has a well-defined structure
    Known(E),

    /// An error of unexpected type of structure
    Unknown(DeserializationError),
}

impl<E> ServerError<E> {
    /// Map `ServerError<E>` to `ServerError<F>` by applying a function to a contained `Known`
    /// value, leaving an `Unknown` value untouched.
    pub fn map<F>(self, f: impl FnOnce(E) -> F) -> ServerError<F> {
        match self {
            Self::Known(k) => ServerError::Known(f(k)),
            Self::Unknown(u) => ServerError::Unknown(u),
        }
    }
}

impl<E, F> ServerError<Result<E, F>> {
    /// Transpose `ServerError<Result<E, F>>` to `Result<ServerError<E>, F>`.
    pub fn transpose(self) -> Result<ServerError<E>, F> {
        match self {
            Self::Known(Ok(k)) => Ok(ServerError::Known(k)),
            Self::Known(Err(e)) => Err(e),
            Self::Unknown(u) => Ok(ServerError::Unknown(u)),
        }
    }
}

impl<E: fmt::Display> fmt::Display for ServerError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ServerError::Known(e) => fmt::Display::fmt(e, f),
            ServerError::Unknown(res_err) => fmt::Display::fmt(res_err, f),
        }
    }
}

impl<E: StdError> StdError for ServerError<E> {}

/// An error when converting a http request / response to one of ruma's endpoint-specific request /
/// response types.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum DeserializationError {
    /// Encountered invalid UTF-8.
    #[error(transparent)]
    Utf8(#[from] std::str::Utf8Error),

    /// JSON deserialization failed.
    #[error(transparent)]
    Json(#[from] serde_json::Error),

    /// Query parameter deserialization failed.
    #[error(transparent)]
    Query(#[from] crate::serde::urlencoded::de::Error),

    /// Got an invalid identifier.
    #[error(transparent)]
    Ident(#[from] crate::IdParseError),

    /// Header value deserialization failed.
    #[error(transparent)]
    Header(#[from] HeaderDeserializationError),
}

impl From<std::convert::Infallible> for DeserializationError {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}

impl From<http::header::ToStrError> for DeserializationError {
    fn from(err: http::header::ToStrError) -> Self {
        Self::Header(HeaderDeserializationError::ToStrError(err))
    }
}

/// An error with the http headers.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum HeaderDeserializationError {
    /// Failed to convert `http::header::HeaderValue` to `str`.
    #[error("{0}")]
    ToStrError(http::header::ToStrError),

    /// The given required header is missing.
    #[error("missing header `{0}`")]
    MissingHeader(String),
}

/// An error that happens when Ruma cannot understand a Matrix version.
#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct UnknownVersionError;

impl fmt::Display for UnknownVersionError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "version string was unknown")
    }
}

impl StdError for UnknownVersionError {}
<|endoftext|>


<commit_before>use core::fmt;
use core::ops::{Deref, DerefMut};

/// Pads and aligns a value to the length of a cache line.
///
/// In concurrent programming, sometimes it is desirable to make sure commonly accessed pieces of
/// data are not placed into the same cache line. Updating an atomic value invalides the whole
/// cache line it belongs to, which makes the next access to the same cache line slower for other
/// CPU cores. Use `CachePadded` to ensure updating one piece of data doesn't invalidate other
/// cached data.
///
/// # Size and alignment
///
/// Cache lines are assumed to be N bytes long, depending on the architecture:
///
/// * On x86-64 and aarch64, N = 128.
/// * On all others, N = 64.
///
/// Note that N is just a reasonable guess and is not guaranteed to match the actual cache line
/// length of the machine the program is running on. On modern Intel architectures, spatial
/// prefetcher is pulling pairs of 64-byte cache lines at a time, so we pessimistically assume that
/// cache lines are 128 bytes long.
///
/// The size of `CachePadded<T>` is the smallest multiple of N bytes large enough to accommodate
/// a value of type `T`.
///
/// The alignment of `CachePadded<T>` is the maximum of N bytes and the alignment of `T`.
///
/// # Examples
///
/// Alignment and padding:
///
/// ```
/// use crossbeam_utils::CachePadded;
///
/// let array = [CachePadded::new(1i8), CachePadded::new(2i8)];
/// let addr1 = &*array[0] as *const i8 as usize;
/// let addr2 = &*array[1] as *const i8 as usize;
///
/// assert!(addr2 - addr1 >= 64);
/// assert_eq!(addr1 % 64, 0);
/// assert_eq!(addr2 % 64, 0);
/// ```
///
/// When building a concurrent queue with a head and a tail index, it is wise to place them in
/// different cache lines so that concurrent threads pushing and popping elements don't invalidate
/// each other's cache lines:
///
/// ```
/// use crossbeam_utils::CachePadded;
/// use std::sync::atomic::AtomicUsize;
///
/// struct Queue<T> {
///     head: CachePadded<AtomicUsize>,
///     tail: CachePadded<AtomicUsize>,
///     buffer: *mut T,
/// }
/// ```
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
// Starting from Intel's Sandy Bridge, spatial prefetcher is now pulling pairs of 64-byte cache
// lines at a time, so we have to align to 128 bytes rather than 64.
//
// Sources:
// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107
//
// ARM's big.LITTLE architecture has asymmetric cores and "big" cores have 128 byte cache line size
// Sources:
// - https://www.mono-project.com/news/2016/09/12/arm64-icache/
//
#[cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), repr(align(128)))]
#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "aarch64")), repr(align(64)))]
pub struct CachePadded<T> {
    value: T,
}

unsafe impl<T: Send> Send for CachePadded<T> {}
unsafe impl<T: Sync> Sync for CachePadded<T> {}

impl<T> CachePadded<T> {
    /// Pads and aligns a value to the length of a cache line.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_utils::CachePadded;
    ///
    /// let padded_value = CachePadded::new(1);
    /// ```
    pub fn new(t: T) -> CachePadded<T> {
        CachePadded::<T> { value: t }
    }

    /// Returns the inner value.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_utils::CachePadded;
    ///
    /// let padded_value = CachePadded::new(7);
    /// let value = padded_value.into_inner();
    /// assert_eq!(value, 7);
    /// ```
    pub fn into_inner(self) -> T {
        self.value
    }
}

impl<T> Deref for CachePadded<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T> DerefMut for CachePadded<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("CachePadded")
            .field("value", &self.value)
            .finish()
    }
}

impl<T> From<T> for CachePadded<T> {
    fn from(t: T) -> Self {
        CachePadded::new(t)
    }
}
<commit_msg>Rustfmt<commit_after>use core::fmt;
use core::ops::{Deref, DerefMut};

/// Pads and aligns a value to the length of a cache line.
///
/// In concurrent programming, sometimes it is desirable to make sure commonly accessed pieces of
/// data are not placed into the same cache line. Updating an atomic value invalides the whole
/// cache line it belongs to, which makes the next access to the same cache line slower for other
/// CPU cores. Use `CachePadded` to ensure updating one piece of data doesn't invalidate other
/// cached data.
///
/// # Size and alignment
///
/// Cache lines are assumed to be N bytes long, depending on the architecture:
///
/// * On x86-64 and aarch64, N = 128.
/// * On all others, N = 64.
///
/// Note that N is just a reasonable guess and is not guaranteed to match the actual cache line
/// length of the machine the program is running on. On modern Intel architectures, spatial
/// prefetcher is pulling pairs of 64-byte cache lines at a time, so we pessimistically assume that
/// cache lines are 128 bytes long.
///
/// The size of `CachePadded<T>` is the smallest multiple of N bytes large enough to accommodate
/// a value of type `T`.
///
/// The alignment of `CachePadded<T>` is the maximum of N bytes and the alignment of `T`.
///
/// # Examples
///
/// Alignment and padding:
///
/// ```
/// use crossbeam_utils::CachePadded;
///
/// let array = [CachePadded::new(1i8), CachePadded::new(2i8)];
/// let addr1 = &*array[0] as *const i8 as usize;
/// let addr2 = &*array[1] as *const i8 as usize;
///
/// assert!(addr2 - addr1 >= 64);
/// assert_eq!(addr1 % 64, 0);
/// assert_eq!(addr2 % 64, 0);
/// ```
///
/// When building a concurrent queue with a head and a tail index, it is wise to place them in
/// different cache lines so that concurrent threads pushing and popping elements don't invalidate
/// each other's cache lines:
///
/// ```
/// use crossbeam_utils::CachePadded;
/// use std::sync::atomic::AtomicUsize;
///
/// struct Queue<T> {
///     head: CachePadded<AtomicUsize>,
///     tail: CachePadded<AtomicUsize>,
///     buffer: *mut T,
/// }
/// ```
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
// Starting from Intel's Sandy Bridge, spatial prefetcher is now pulling pairs of 64-byte cache
// lines at a time, so we have to align to 128 bytes rather than 64.
//
// Sources:
// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107
//
// ARM's big.LITTLE architecture has asymmetric cores and "big" cores have 128 byte cache line size
// Sources:
// - https://www.mono-project.com/news/2016/09/12/arm64-icache/
//
#[cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), repr(align(128)))]
#[cfg_attr(
    not(any(target_arch = "x86_64", target_arch = "aarch64")),
    repr(align(64))
)]
pub struct CachePadded<T> {
    value: T,
}

unsafe impl<T: Send> Send for CachePadded<T> {}
unsafe impl<T: Sync> Sync for CachePadded<T> {}

impl<T> CachePadded<T> {
    /// Pads and aligns a value to the length of a cache line.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_utils::CachePadded;
    ///
    /// let padded_value = CachePadded::new(1);
    /// ```
    pub fn new(t: T) -> CachePadded<T> {
        CachePadded::<T> { value: t }
    }

    /// Returns the inner value.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_utils::CachePadded;
    ///
    /// let padded_value = CachePadded::new(7);
    /// let value = padded_value.into_inner();
    /// assert_eq!(value, 7);
    /// ```
    pub fn into_inner(self) -> T {
        self.value
    }
}

impl<T> Deref for CachePadded<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T> DerefMut for CachePadded<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T: fmt::Debug> fmt::Debug for CachePadded<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("CachePadded")
            .field("value", &self.value)
            .finish()
    }
}

impl<T> From<T> for CachePadded<T> {
    fn from(t: T) -> Self {
        CachePadded::new(t)
    }
}
<|endoftext|>


<commit_before>use std::{thread,
          time::{Duration,
                 Instant}};

/// How long to wait for an Ack after we ping
const PING_TIMING_DEFAULT_MS: u64 = 1000;
/// How long to wait for an Ack after we PingReq - should be at least 2x the PING_TIMING_DEFAULT_MS
const PINGREQ_TIMING_DEFAULT_MS: u64 = 2100;
/// How many protocol periods before a suspect member is marked as confirmed.
const SUSPICION_TIMEOUT_DEFAULT_PROTOCOL_PERIODS: u64 = 3;
/// How long to wait between each time we send rumors out.
const GOSSIP_INTERVAL_DEFAULT_MS: u64 = 1000;
/// How long before we set a confirmed member to a departed member, removing them from quorums
///   just for your own sanity - this is 3 days.
const DEPARTURE_TIMEOUT_DEFAULT_MS: u64 = 259_200_000;

/// The timing of the outbound threads.
#[derive(Debug, Clone)]
pub struct Timing {
    ping: Duration,
    pingreq_ms: u64,
    gossip_interval_ms: u64,
    suspicion_timeout_protocol_periods: u64,
    departure_timeout_ms: u64,
}

impl Default for Timing {
    fn default() -> Timing {
        Timing { ping: Duration::from_millis(PING_TIMING_DEFAULT_MS),
                 pingreq_ms: PINGREQ_TIMING_DEFAULT_MS,
                 gossip_interval_ms: GOSSIP_INTERVAL_DEFAULT_MS,
                 suspicion_timeout_protocol_periods: SUSPICION_TIMEOUT_DEFAULT_PROTOCOL_PERIODS,
                 departure_timeout_ms: DEPARTURE_TIMEOUT_DEFAULT_MS, }
    }
}

impl Timing {
    /// How long a gossip period should last.
    fn gossip_interval(&self) -> Duration { Duration::from_millis(self.gossip_interval_ms) }

    /// How long is a protocol period, in millis.
    pub fn protocol_period_ms(&self) -> u64 { PING_TIMING_DEFAULT_MS + self.pingreq_ms }

    /// How long a ping has to timeout.
    pub fn ping(&self) -> Duration { self.ping }

    /// How long a pingreq has to timeout.
    pub fn pingreq(&self) -> Duration { Duration::from_millis(self.pingreq_ms) }

    /// How long to space out individual SWIM probe rounds
    fn swim_probe_interval(&self) -> Duration {
        Duration::from_millis(PING_TIMING_DEFAULT_MS + self.pingreq_ms)
    }

    /// If the amount of time since `starting_point` is less than a
    /// gossip interval, sleep for the remainder of that gossip interval.
    pub fn sleep_for_remaining_gossip_interval(&self, starting_point: Instant) {
        maybe_sleep(starting_point, self.gossip_interval())
    }

    /// How long before this suspect entry times out
    pub fn suspicion_timeout_duration(&self) -> Duration {
        Duration::from_millis(self.protocol_period_ms() * self.suspicion_timeout_protocol_periods)
    }

    /// If the amount of time since `starting_point` is less than a
    /// SWIM protocol probe interval, sleep for the remainder of that
    /// interval.
    pub fn sleep_for_remaining_swim_protocol_interval(&self, starting_point: Instant) {
        maybe_sleep(starting_point, self.swim_probe_interval())
    }

    pub fn departure_timeout_duration(&self) -> Duration {
        Duration::from_millis(self.departure_timeout_ms)
    }
}

/// If the amount of time elapsed from `start` is less than `timeout`,
/// sleep for the difference.
fn maybe_sleep(start: Instant, timeout: Duration) {
    if let Some(amount) = timeout.checked_sub(start.elapsed()) {
        thread::sleep(amount)
    }
}
<commit_msg>Timing: Add `pingreq` field as a Duration<commit_after>use std::{thread,
          time::{Duration,
                 Instant}};

/// How long to wait for an Ack after we ping
const PING_TIMING_DEFAULT_MS: u64 = 1000;
/// How long to wait for an Ack after we PingReq - should be at least 2x the PING_TIMING_DEFAULT_MS
const PINGREQ_TIMING_DEFAULT_MS: u64 = 2100;
/// How many protocol periods before a suspect member is marked as confirmed.
const SUSPICION_TIMEOUT_DEFAULT_PROTOCOL_PERIODS: u64 = 3;
/// How long to wait between each time we send rumors out.
const GOSSIP_INTERVAL_DEFAULT_MS: u64 = 1000;
/// How long before we set a confirmed member to a departed member, removing them from quorums
///   just for your own sanity - this is 3 days.
const DEPARTURE_TIMEOUT_DEFAULT_MS: u64 = 259_200_000;

/// The timing of the outbound threads.
#[derive(Debug, Clone)]
pub struct Timing {
    ping: Duration,
    pingreq: Duration,
    gossip_interval_ms: u64,
    suspicion_timeout_protocol_periods: u64,
    departure_timeout_ms: u64,
}

impl Default for Timing {
    fn default() -> Timing {
        Timing { ping: Duration::from_millis(PING_TIMING_DEFAULT_MS),
                 pingreq: Duration::from_millis(PINGREQ_TIMING_DEFAULT_MS),
                 gossip_interval_ms: GOSSIP_INTERVAL_DEFAULT_MS,
                 suspicion_timeout_protocol_periods: SUSPICION_TIMEOUT_DEFAULT_PROTOCOL_PERIODS,
                 departure_timeout_ms: DEPARTURE_TIMEOUT_DEFAULT_MS, }
    }
}

impl Timing {
    /// How long a gossip period should last.
    fn gossip_interval(&self) -> Duration { Duration::from_millis(self.gossip_interval_ms) }

    /// How long is a protocol period, in millis.
    pub fn protocol_period_ms(&self) -> u64 { PING_TIMING_DEFAULT_MS + PINGREQ_TIMING_DEFAULT_MS }

    /// How long a ping has to timeout.
    pub fn ping(&self) -> Duration { self.ping }

    /// How long a pingreq has to timeout.
    pub fn pingreq(&self) -> Duration { self.pingreq }

    /// How long to space out individual SWIM probe rounds
    fn swim_probe_interval(&self) -> Duration {
        Duration::from_millis(PING_TIMING_DEFAULT_MS + PINGREQ_TIMING_DEFAULT_MS)
    }

    /// If the amount of time since `starting_point` is less than a
    /// gossip interval, sleep for the remainder of that gossip interval.
    pub fn sleep_for_remaining_gossip_interval(&self, starting_point: Instant) {
        maybe_sleep(starting_point, self.gossip_interval())
    }

    /// How long before this suspect entry times out
    pub fn suspicion_timeout_duration(&self) -> Duration {
        Duration::from_millis(self.protocol_period_ms() * self.suspicion_timeout_protocol_periods)
    }

    /// If the amount of time since `starting_point` is less than a
    /// SWIM protocol probe interval, sleep for the remainder of that
    /// interval.
    pub fn sleep_for_remaining_swim_protocol_interval(&self, starting_point: Instant) {
        maybe_sleep(starting_point, self.swim_probe_interval())
    }

    pub fn departure_timeout_duration(&self) -> Duration {
        Duration::from_millis(self.departure_timeout_ms)
    }
}

/// If the amount of time elapsed from `start` is less than `timeout`,
/// sleep for the difference.
fn maybe_sleep(start: Instant, timeout: Duration) {
    if let Some(amount) = timeout.checked_sub(start.elapsed()) {
        thread::sleep(amount)
    }
}
<|endoftext|>


<commit_before>/// Implement +, -, *, / operators for Tensor
/// +=, -=, *=, /= are provided as methods of ops::inplace_*.
/// *=, /= don't propagate gradients.
extern crate ndarray;

use ndarray_ext::NdArray;
use ops;
use std::mem;
use std::ops::{Add, Div, Mul, Sub};
use std::result::Result;
use tensor::Tensor;

pub struct AddOp;
pub struct SubOp;
pub struct MulOp;
pub struct DivOp;
pub struct InplaceAddOp;
pub struct InplaceSubOp;
pub struct InplaceMulOp;
pub struct InplaceDivOp;

impl ops::Op for AddOp {
    fn name(&self) -> &str
    {
        "Add"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        add_forward(xs[0], xs[1])
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(gy2)]
    }
}

impl ops::Op for SubOp {
    fn name(&self) -> &str
    {
        "Sub"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        let x0 = xs[0];
        let x1 = xs[1];
        let shape0: &[usize] = x0.shape();
        if shape0 == &[] {
            // a is scalar
            let x0_elem = x0[ndarray::IxDyn(&[])];
            Ok(x1.map(move |a| x0_elem - a))
        } else {
            Ok(x0 - x1)
        }
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(ops::neg(&gy2))]
    }
}

impl ops::Op for MulOp {
    fn name(&self) -> &str
    {
        "Mul"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        mul_forward(xs[0], xs[1])
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let x0 = inputs[0];
        let x1 = inputs[1];
        let (gy1, gy2) = maybe_reduce_gy(x0, x1, gy);
        vec![Some(gy1 * x1), Some(gy2 * x0)]
    }
}

impl ops::Op for DivOp {
    fn name(&self) -> &str
    {
        "Div"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        let x0 = xs[0];
        let x1 = xs[1];
        let shape0: &[usize] = x0.shape();
        if shape0 == &[] {
            // a is scalar
            let x0_elem = x0[ndarray::IxDyn(&[])];
            Ok(x1.map(move |a| x0_elem / a))
        } else {
            Ok(x0 / x1)
        }
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let x0 = inputs[0];
        let x1 = inputs[1];
        let (gy1, gy2) = maybe_reduce_gy(x0, x1, gy);
        vec![Some(gy1 / x1), Some(ops::neg(x0) * ops::pow(x1, -2.) * gy2)]
    }
}

impl ops::Op for InplaceAddOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceAdd"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a += b);
        Ok(())
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(gy2)]
    }
}

impl ops::Op for InplaceSubOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceSub"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a -= b);
        Ok(())
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(ops::neg(&gy2))]
    }
}

impl ops::Op for InplaceMulOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceMul"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a *= b);
        Ok(())
    }

    fn grad(&self, _: &Tensor, _: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        vec![None, None]
    }
}

impl ops::Op for InplaceDivOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceDiv"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a /= b);
        Ok(())
    }

    fn grad(&self, _: &Tensor, _: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        vec![None, None]
    }
}

#[inline]
// Reduce gy if broadcast occurred in the forward path
fn maybe_reduce_gy(x0: &Tensor, x1: &Tensor, gy: &Tensor) -> (Tensor, Tensor)
{
    let shape0 = x0.shape();
    let shape1 = x1.shape();
    let gy_shape = gy.shape();
    let sum0 = ops::reduction_ops::ReduceSum { keep_dims: true, sparse_axes: true };
    let sum1 = ops::reduction_ops::ReduceSum { keep_dims: true, sparse_axes: true };
    return (
        ops::apply_op(
            sum0,
            &[gy, &ops::not_equal(&gy_shape, &shape0)],
            Some(shape0),
        ), // gy1
        ops::apply_op(
            sum1,
            &[gy, &ops::not_equal(&gy_shape, &shape1)],
            Some(shape1),
        ), /* gy2 */
    );
}

// -- std::ops::{Add, Sub, Mul, Div} implementations --

macro_rules! impl_bin_op_between_tensor_and_scalar {
    (
        $trt:ident,
        $func:ident,
        $op:ident,
        $scalar_type:ty
    ) => {

        // scalar op Tensor
        impl $trt<Tensor> for $scalar_type {
            type Output = Tensor;
            fn $func(self, rhs: Tensor) -> Self::Output
            {
                ops::apply_op($op, &[&ops::scalar(self as f32), &rhs], Some(rhs.shape()))
            }
        }

        // scalar op &Tensor
        impl<'a> $trt<&'a Tensor> for $scalar_type {
            type Output = Tensor;
            fn $func(self, rhs: &'a Tensor) -> Self::Output
            {
                ops::apply_op($op, &[&ops::scalar(self as f32), rhs], Some(rhs.shape()))
            }
        }

        // Tensor op scalar
        impl $trt<$scalar_type> for Tensor {
            type Output = Tensor;
            fn $func(self, rhs: $scalar_type) -> Self::Output
            {
                ops::apply_op($op, &[&self, &ops::scalar(rhs as f32)], Some(self.shape()))
            }
        }

        // &Tensor op scalar
        impl<'a> $trt<$scalar_type> for &'a Tensor {
            type Output = Tensor;
            fn $func(self, rhs: $scalar_type) -> Self::Output
            {
                ops::apply_op($op, &[self, &ops::scalar(rhs as f32)], Some(self.shape()))
            }
        }
    }
}

macro_rules! impl_bin_op_between_tensors {
    (
        $trt:ident,
        $func:ident,
        $op:ident
    ) => {
        // Tensor op Tensor
        impl $trt for Tensor {
            type Output = Tensor;
            fn $func(self, rhs: Tensor) -> Self::Output
            {
                ops::$func(&self, &rhs)
            }
        }

        // Tensor op &Tensor
        impl<'a> $trt<&'a Tensor> for Tensor {
            type Output = Tensor;
            fn $func(self, rhs: &Tensor) -> Self::Output
            {
                ops::$func(&self, rhs)
            }
        }

        // &Tensor op Tensor
        impl<'a> $trt<Tensor> for &'a Tensor {
            type Output = Tensor;
            fn $func(self, rhs: Tensor) -> Self::Output
            {
                ops::$func(&self, &rhs)
            }
        }

        // &Tensor op &Tensor
        // lifetime of the two tensors are unrelated
        impl<'a, 'b> $trt<&'a Tensor> for &'b Tensor {
            type Output = Tensor;
            fn $func(self, rhs: &Tensor) -> Self::Output
            {
                ops::$func(self, rhs)
            }
        }
    };
}

macro_rules! impl_bin_op_forward {
    ($forward_name:ident, $bin_op:tt) => {
        fn $forward_name(x0: &NdArray, x1: &NdArray) -> Result<NdArray, ::OpComputeErrorStatus>
        {
            let shape0: &[usize]  = x0.shape();
            let shape1: &[usize]  = x1.shape();
            let scalar_shape = &[];

            let x0_is_scalar = shape0 == scalar_shape;
            let x1_is_scalar = shape1 == scalar_shape;

            if x0_is_scalar && !x1_is_scalar {
                let elem = x0[ndarray::IxDyn(&[])];
                Ok(x1.map(move |a| a $bin_op elem ))
            } else if x1_is_scalar && !x0_is_scalar {
                let elem = x1[ndarray::IxDyn(&[])];
                Ok(x0.map(move |a| a $bin_op elem ))
            } else if !x0_is_scalar && !x1_is_scalar {
                let len0: usize = shape0.iter().product();
                let len1: usize = shape1.iter().product();
                if len0 > len1 {
                    Ok(x0 $bin_op x1)
                } else {
                    Ok(x1 $bin_op x0)
                }
            } else {
                Ok(x0 $bin_op x1)
            }
        }
    };
}

impl_bin_op_forward!(add_forward, +);
impl_bin_op_forward!(mul_forward, *);

impl_bin_op_between_tensors!(Add, add, AddOp);
impl_bin_op_between_tensors!(Sub, sub, SubOp);
impl_bin_op_between_tensors!(Mul, mul, MulOp);
impl_bin_op_between_tensors!(Div, div, DivOp);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, i32);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, i32);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, i32);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, i32);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, i64);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, i64);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, i64);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, i64);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, f32);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, f32);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, f32);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, f32);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, f64);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, f64);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, f64);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, f64);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, u32);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, u32);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, u32);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, u32);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, u64);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, u64);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, u64);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, u64);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, usize);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, usize);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, usize);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, usize);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, isize);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, isize);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, isize);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, isize);
<commit_msg>Fix scalar shape<commit_after>/// Implement +, -, *, / operators for Tensor
/// +=, -=, *=, /= are provided as methods of ops::inplace_*.
/// *=, /= don't propagate gradients.
extern crate ndarray;

use ndarray_ext::NdArray;
use ops;
use std::mem;
use std::ops::{Add, Div, Mul, Sub};
use std::result::Result;
use tensor::Tensor;

pub struct AddOp;
pub struct SubOp;
pub struct MulOp;
pub struct DivOp;
pub struct InplaceAddOp;
pub struct InplaceSubOp;
pub struct InplaceMulOp;
pub struct InplaceDivOp;

impl ops::Op for AddOp {
    fn name(&self) -> &str
    {
        "Add"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        add_forward(xs[0], xs[1])
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(gy2)]
    }
}

impl ops::Op for SubOp {
    fn name(&self) -> &str
    {
        "Sub"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        let x0 = xs[0];
        let x1 = xs[1];
        let shape0: &[usize] = x0.shape();
        if shape0 == &[] {
            // a is scalar
            let x0_elem = x0[ndarray::IxDyn(&[])];
            Ok(x1.map(move |a| x0_elem - a))
        } else {
            Ok(x0 - x1)
        }
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(ops::neg(&gy2))]
    }
}

impl ops::Op for MulOp {
    fn name(&self) -> &str
    {
        "Mul"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        mul_forward(xs[0], xs[1])
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let x0 = inputs[0];
        let x1 = inputs[1];
        let (gy1, gy2) = maybe_reduce_gy(x0, x1, gy);
        vec![Some(gy1 * x1), Some(gy2 * x0)]
    }
}

impl ops::Op for DivOp {
    fn name(&self) -> &str
    {
        "Div"
    }

    fn compute(&self, xs: &[&NdArray]) -> Result<NdArray, ::OpComputeErrorStatus>
    {
        let x0 = xs[0];
        let x1 = xs[1];
        let shape0: &[usize] = x0.shape();
        if shape0 == &[] {
            // a is scalar
            let x0_elem = x0[ndarray::IxDyn(&[])];
            Ok(x1.map(move |a| x0_elem / a))
        } else {
            Ok(x0 / x1)
        }
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let x0 = inputs[0];
        let x1 = inputs[1];
        let (gy1, gy2) = maybe_reduce_gy(x0, x1, gy);
        vec![Some(gy1 / x1), Some(ops::neg(x0) * ops::pow(x1, -2.) * gy2)]
    }
}

impl ops::Op for InplaceAddOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceAdd"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a += b);
        Ok(())
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(gy2)]
    }
}

impl ops::Op for InplaceSubOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceSub"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a -= b);
        Ok(())
    }

    fn grad(&self, gy: &Tensor, inputs: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        let (gy1, gy2) = maybe_reduce_gy(inputs[0], inputs[1], gy);
        vec![Some(gy1), Some(ops::neg(&gy2))]
    }
}

impl ops::Op for InplaceMulOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceMul"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a *= b);
        Ok(())
    }

    fn grad(&self, _: &Tensor, _: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        vec![None, None]
    }
}

impl ops::Op for InplaceDivOp {
    fn inplace(&self) -> bool
    {
        true
    }

    fn name(&self) -> &str
    {
        "InplaceDiv"
    }

    fn compute_inplace(&self, xs: &mut [&mut NdArray]) -> Result<(), ::OpComputeErrorStatus>
    {
        // safe transmute probably
        let x1: &&NdArray = unsafe { mem::transmute(&mut xs[1]) };
        let x0 = &mut xs[0];
        x0.zip_mut_with(x1, |a, &b| *a /= b);
        Ok(())
    }

    fn grad(&self, _: &Tensor, _: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        vec![None, None]
    }
}

#[inline]
// Reduce gy if broadcast occurred in the forward path
fn maybe_reduce_gy(x0: &Tensor, x1: &Tensor, gy: &Tensor) -> (Tensor, Tensor)
{
    let shape0 = x0.shape();
    let shape1 = x1.shape();
    let gy_shape = gy.shape();
    let sum0 = ops::reduction_ops::ReduceSum { keep_dims: true, sparse_axes: true };
    let sum1 = ops::reduction_ops::ReduceSum { keep_dims: true, sparse_axes: true };
    return (
        ops::apply_op(
            sum0,
            &[gy, &ops::not_equal(&gy_shape, &shape0)],
            Some(shape0),
        ), // gy1
        ops::apply_op(
            sum1,
            &[gy, &ops::not_equal(&gy_shape, &shape1)],
            Some(shape1),
        ), /* gy2 */
    );
}

// -- std::ops::{Add, Sub, Mul, Div} implementations --

macro_rules! impl_bin_op_between_tensor_and_scalar {
    (
        $trt:ident,
        $func:ident,
        $op:ident,
        $scalar_type:ty
    ) => {

        // scalar op Tensor
        impl $trt<Tensor> for $scalar_type {
            type Output = Tensor;
            fn $func(self, rhs: Tensor) -> Self::Output
            {
                ops::apply_op($op, &[&ops::scalar(self as f32), &rhs], Some(rhs.shape()))
            }
        }

        // scalar op &Tensor
        impl<'a> $trt<&'a Tensor> for $scalar_type {
            type Output = Tensor;
            fn $func(self, rhs: &'a Tensor) -> Self::Output
            {
                ops::apply_op($op, &[&ops::scalar(self as f32), rhs], Some(rhs.shape()))
            }
        }

        // Tensor op scalar
        impl $trt<$scalar_type> for Tensor {
            type Output = Tensor;
            fn $func(self, rhs: $scalar_type) -> Self::Output
            {
                ops::apply_op($op, &[&self, &ops::scalar(rhs as f32)], Some(self.shape()))
            }
        }

        // &Tensor op scalar
        impl<'a> $trt<$scalar_type> for &'a Tensor {
            type Output = Tensor;
            fn $func(self, rhs: $scalar_type) -> Self::Output
            {
                ops::apply_op($op, &[self, &ops::scalar(rhs as f32)], Some(self.shape()))
            }
        }
    }
}

macro_rules! impl_bin_op_between_tensors {
    (
        $trt:ident,
        $func:ident,
        $op:ident
    ) => {
        // Tensor op Tensor
        impl $trt for Tensor {
            type Output = Tensor;
            fn $func(self, rhs: Tensor) -> Self::Output
            {
                ops::$func(&self, &rhs)
            }
        }

        // Tensor op &Tensor
        impl<'a> $trt<&'a Tensor> for Tensor {
            type Output = Tensor;
            fn $func(self, rhs: &Tensor) -> Self::Output
            {
                ops::$func(&self, rhs)
            }
        }

        // &Tensor op Tensor
        impl<'a> $trt<Tensor> for &'a Tensor {
            type Output = Tensor;
            fn $func(self, rhs: Tensor) -> Self::Output
            {
                ops::$func(&self, &rhs)
            }
        }

        // &Tensor op &Tensor
        // lifetime of the two tensors are unrelated
        impl<'a, 'b> $trt<&'a Tensor> for &'b Tensor {
            type Output = Tensor;
            fn $func(self, rhs: &Tensor) -> Self::Output
            {
                ops::$func(self, rhs)
            }
        }
    };
}

macro_rules! impl_bin_op_forward {
    ($forward_name:ident, $bin_op:tt) => {
        fn $forward_name(x0: &NdArray, x1: &NdArray) -> Result<NdArray, ::OpComputeErrorStatus>
        {
            let shape0: &[usize]  = x0.shape();
            let shape1: &[usize]  = x1.shape();
            let scalar_shape = &[];
            let scalar_shape1 = &[0];

            let x0_is_scalar = shape0 == scalar_shape || shape0 == scalar_shape1;
            let x1_is_scalar = shape1 == scalar_shape || shape1 == scalar_shape1;

            if x0_is_scalar && !x1_is_scalar {
                let elem = x0[ndarray::IxDyn(&[])];
                Ok(x1.map(move |a| a $bin_op elem ))
            } else if x1_is_scalar && !x0_is_scalar {
                let elem = x1[ndarray::IxDyn(&[])];
                Ok(x0.map(move |a| a $bin_op elem ))
            } else if !x0_is_scalar && !x1_is_scalar {
                let len0: usize = shape0.iter().product();
                let len1: usize = shape1.iter().product();
                if len0 > len1 {
                    Ok(x0 $bin_op x1)
                } else {
                    Ok(x1 $bin_op x0)
                }
            } else {
                Ok(x0 $bin_op x1)
            }
        }
    };
}

impl_bin_op_forward!(add_forward, +);
impl_bin_op_forward!(mul_forward, *);

impl_bin_op_between_tensors!(Add, add, AddOp);
impl_bin_op_between_tensors!(Sub, sub, SubOp);
impl_bin_op_between_tensors!(Mul, mul, MulOp);
impl_bin_op_between_tensors!(Div, div, DivOp);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, i32);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, i32);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, i32);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, i32);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, i64);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, i64);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, i64);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, i64);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, f32);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, f32);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, f32);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, f32);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, f64);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, f64);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, f64);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, f64);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, u32);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, u32);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, u32);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, u32);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, u64);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, u64);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, u64);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, u64);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, usize);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, usize);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, usize);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, usize);

impl_bin_op_between_tensor_and_scalar!(Add, add, AddOp, isize);
impl_bin_op_between_tensor_and_scalar!(Sub, sub, SubOp, isize);
impl_bin_op_between_tensor_and_scalar!(Mul, mul, MulOp, isize);
impl_bin_op_between_tensor_and_scalar!(Div, div, DivOp, isize);
<|endoftext|>


<commit_before>use glib::translate::{ToGlibPtr, from_glib_none};

use super::DOMDOMWindow;
use dom_dom_selection::DOMDOMSelection;

pub trait DOMDOMWindowExtManual {
    fn get_selection(&self) -> Option<DOMDOMSelection>;
}

impl DOMDOMWindowExtManual for DOMDOMWindow {
    fn get_selection(&self) -> Option<DOMDOMSelection> {
        unsafe { from_glib_none(sys::webkit_dom_dom_window_get_selection(self.to_glib_none().0)) }
    }
}

mod sys {
    use ffi;

    use dom_dom_selection::sys::WebKitDOMDOMSelection;

    extern "C" {
        pub fn webkit_dom_dom_window_get_selection(window: *mut ffi::WebKitDOMDOMWindow) -> *mut WebKitDOMDOMSelection;
    }
}
<commit_msg>Added get_computed_style() method.<commit_after>use glib::IsA;
use glib::translate::{ToGlibPtr, from_glib_full, from_glib_none};

use super::{DOMCSSStyleDeclaration, DOMDOMWindow, DOMElement};
use dom_dom_selection::DOMDOMSelection;

pub trait DOMDOMWindowExtManual {
    fn get_computed_style<T: IsA<DOMElement>>(&self, element: &T, pseudo_element: Option<&str>) -> Option<DOMCSSStyleDeclaration>;
    fn get_selection(&self) -> Option<DOMDOMSelection>;
}

impl DOMDOMWindowExtManual for DOMDOMWindow {
    fn get_computed_style<T: IsA<DOMElement>>(&self, element: &T, pseudo_element: Option<&str>) -> Option<DOMCSSStyleDeclaration> {
        unsafe {
            from_glib_full(sys::webkit_dom_dom_window_get_computed_style(self.to_glib_none().0, element.to_glib_none().0, pseudo_element.to_glib_none().0))
        }
    }

    fn get_selection(&self) -> Option<DOMDOMSelection> {
        unsafe { from_glib_none(sys::webkit_dom_dom_window_get_selection(self.to_glib_none().0)) }
    }
}

mod sys {
    use ffi;

    use libc::c_char;
    use dom_dom_selection::sys::WebKitDOMDOMSelection;

    extern "C" {
        pub fn webkit_dom_dom_window_get_computed_style(window: *mut ffi::WebKitDOMDOMWindow, element: *mut ffi::WebKitDOMElement, pseudo_element: *const c_char) -> *mut ffi::WebKitDOMCSSStyleDeclaration;
        pub fn webkit_dom_dom_window_get_selection(window: *mut ffi::WebKitDOMDOMWindow) -> *mut WebKitDOMDOMSelection;
    }
}
<|endoftext|>


<commit_before>
use std::slice;

use libnum;
use imp_prelude::*;

/// ***Deprecated: Use `ArrayBase::zeros` instead.***
///
/// Return an array filled with zeros
#[cfg_attr(has_deprecated, deprecated(note="Use `ArrayBase::zeros` instead."))]
pub fn zeros<A, D>(dim: D) -> OwnedArray<A, D>
    where A: Clone + libnum::Zero, D: Dimension,
{
    ArrayBase::zeros(dim)
}

/// Return a zero-dimensional array with the element `x`.
pub fn arr0<A>(x: A) -> OwnedArray<A, ()>
{
    unsafe { ArrayBase::from_vec_dim_unchecked((), vec![x]) }
}

/// Return a one-dimensional array with elements from `xs`.
pub fn arr1<A: Clone>(xs: &[A]) -> OwnedArray<A, Ix> {
    ArrayBase::from_vec(xs.to_vec())
}

/// Return a one-dimensional array with elements from `xs`.
pub fn rcarr1<A: Clone>(xs: &[A]) -> RcArray<A, Ix> {
    arr1(xs).into_shared()
}

/// Return a zero-dimensional array view borrowing `x`.
pub fn aview0<A>(x: &A) -> ArrayView<A, ()> {
    unsafe { ArrayView::new_(x, (), ()) }
}

/// Return a one-dimensional array view with elements borrowing `xs`.
///
/// ```
/// use ndarray::aview1;
///
/// let data = [1.0; 1024];
///
/// // Create a 2D array view from borrowed data
/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
///
/// assert!(
///     a2d.scalar_sum() == 1024.0
/// );
/// ```
pub fn aview1<A>(xs: &[A]) -> ArrayView<A, Ix> {
    ArrayView::from_slice(xs)
}

/// Return a two-dimensional array view with elements borrowing `xs`.
pub fn aview2<A, V: FixedInitializer<Elem=A>>(xs: &[V]) -> ArrayView<A, (Ix, Ix)> {
    let cols = V::len();
    let rows = xs.len();
    let data = unsafe {
        slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows)
    };
    let dim = (rows as Ix, cols as Ix);
    unsafe {
        let strides = dim.default_strides();
        ArrayView::new_(data.as_ptr(), dim, strides)
    }
}

/// Return a one-dimensional read-write array view with elements borrowing `xs`.
///
/// ```
/// #[macro_use(s)]
/// extern crate ndarray;
///
/// use ndarray::aview_mut1;
///
/// // Create an array view over some data, then slice it and modify it.
/// fn main() {
///     let mut data = [0; 1024];
///     {
///         let mut a = aview_mut1(&mut data).into_shape((32, 32)).unwrap();
///         a.slice_mut(s![.., ..;3]).assign_scalar(&5);
///     }
///     assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
/// }
/// ```
pub fn aview_mut1<A>(xs: &mut [A]) -> ArrayViewMut<A, Ix> {
    ArrayViewMut::from_slice(xs)
}

/// Fixed-size array used for array initialization
pub unsafe trait FixedInitializer {
    type Elem;
    fn as_init_slice(&self) -> &[Self::Elem];
    fn len() -> usize;
}

macro_rules! impl_arr_init {
    (__impl $n: expr) => (
        unsafe impl<T> FixedInitializer for [T;  $n] {
            type Elem = T;
            fn as_init_slice(&self) -> &[T] { self }
            fn len() -> usize { $n }
        }
    );
    () => ();
    ($n: expr, $($m:expr,)*) => (
        impl_arr_init!(__impl $n);
        impl_arr_init!($($m,)*);
    )

}

impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);

/// Return a two-dimensional array with elements from `xs`.
///
/// ```
/// use ndarray::arr2;
///
/// let a = arr2(&[[1, 2, 3],
///                [4, 5, 6]]);
/// assert!(
///     a.shape() == [2, 3]
/// );
/// ```
pub fn arr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> OwnedArray<A, (Ix, Ix)> {
    // FIXME: Simplify this when V is fix size array
    let (m, n) = (xs.len() as Ix,
                  xs.get(0).map_or(0, |snd| snd.as_init_slice().len() as Ix));
    let dim = (m, n);
    let mut result = Vec::<A>::with_capacity(dim.size());
    for snd in xs {
        let snd = snd.as_init_slice();
        result.extend(snd.iter().cloned());
    }
    unsafe {
        ArrayBase::from_vec_dim_unchecked(dim, result)
    }
}

/// Return a two-dimensional array with elements from `xs`.
///
pub fn rcarr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> RcArray<A, (Ix, Ix)> {
    arr2(xs).into_shared()
}

/// Return a three-dimensional array with elements from `xs`.
///
/// **Panics** if the slices are not all of the same length.
///
/// ```
/// use ndarray::arr3;
///
/// let a = arr3(&[[[1, 2],
///                 [3, 4]],
///                [[5, 6],
///                 [7, 8]],
///                [[9, 0],
///                 [1, 2]]]);
/// assert!(
///     a.shape() == [3, 2, 2]
/// );
/// ```
pub fn arr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> OwnedArray<A, (Ix, Ix, Ix)>
{
    // FIXME: Simplify this when U/V are fix size arrays
    let m = xs.len() as Ix;
    let fst = xs.get(0).map(|snd| snd.as_init_slice());
    let thr = fst.and_then(|elt| elt.get(0).map(|elt2| elt2.as_init_slice()));
    let n = fst.map_or(0, |v| v.len() as Ix);
    let o = thr.map_or(0, |v| v.len() as Ix);
    let dim = (m, n, o);
    let mut result = Vec::<A>::with_capacity(dim.size());
    for snd in xs {
        let snd = snd.as_init_slice();
        for thr in snd.iter() {
            let thr = thr.as_init_slice();
            result.extend(thr.iter().cloned());
        }
    }
    unsafe {
        ArrayBase::from_vec_dim_unchecked(dim, result)
    }
}

/// Return a three-dimensional array with elements from `xs`.
pub fn rcarr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> RcArray<A, (Ix, Ix, Ix)>
{
    arr3(xs).into_shared()
}
<commit_msg>Simplify arr2, arr3<commit_after>
use std::slice;

use libnum;
use imp_prelude::*;

/// ***Deprecated: Use `ArrayBase::zeros` instead.***
///
/// Return an array filled with zeros
#[cfg_attr(has_deprecated, deprecated(note="Use `ArrayBase::zeros` instead."))]
pub fn zeros<A, D>(dim: D) -> OwnedArray<A, D>
    where A: Clone + libnum::Zero, D: Dimension,
{
    ArrayBase::zeros(dim)
}

/// Return a zero-dimensional array with the element `x`.
pub fn arr0<A>(x: A) -> OwnedArray<A, ()>
{
    unsafe { ArrayBase::from_vec_dim_unchecked((), vec![x]) }
}

/// Return a one-dimensional array with elements from `xs`.
pub fn arr1<A: Clone>(xs: &[A]) -> OwnedArray<A, Ix> {
    ArrayBase::from_vec(xs.to_vec())
}

/// Return a one-dimensional array with elements from `xs`.
pub fn rcarr1<A: Clone>(xs: &[A]) -> RcArray<A, Ix> {
    arr1(xs).into_shared()
}

/// Return a zero-dimensional array view borrowing `x`.
pub fn aview0<A>(x: &A) -> ArrayView<A, ()> {
    unsafe { ArrayView::new_(x, (), ()) }
}

/// Return a one-dimensional array view with elements borrowing `xs`.
///
/// ```
/// use ndarray::aview1;
///
/// let data = [1.0; 1024];
///
/// // Create a 2D array view from borrowed data
/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
///
/// assert!(
///     a2d.scalar_sum() == 1024.0
/// );
/// ```
pub fn aview1<A>(xs: &[A]) -> ArrayView<A, Ix> {
    ArrayView::from_slice(xs)
}

/// Return a two-dimensional array view with elements borrowing `xs`.
pub fn aview2<A, V: FixedInitializer<Elem=A>>(xs: &[V]) -> ArrayView<A, (Ix, Ix)> {
    let cols = V::len();
    let rows = xs.len();
    let data = unsafe {
        slice::from_raw_parts(xs.as_ptr() as *const A, cols * rows)
    };
    let dim = (rows as Ix, cols as Ix);
    unsafe {
        let strides = dim.default_strides();
        ArrayView::new_(data.as_ptr(), dim, strides)
    }
}

/// Return a one-dimensional read-write array view with elements borrowing `xs`.
///
/// ```
/// #[macro_use(s)]
/// extern crate ndarray;
///
/// use ndarray::aview_mut1;
///
/// // Create an array view over some data, then slice it and modify it.
/// fn main() {
///     let mut data = [0; 1024];
///     {
///         let mut a = aview_mut1(&mut data).into_shape((32, 32)).unwrap();
///         a.slice_mut(s![.., ..;3]).assign_scalar(&5);
///     }
///     assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
/// }
/// ```
pub fn aview_mut1<A>(xs: &mut [A]) -> ArrayViewMut<A, Ix> {
    ArrayViewMut::from_slice(xs)
}

/// Fixed-size array used for array initialization
pub unsafe trait FixedInitializer {
    type Elem;
    fn as_init_slice(&self) -> &[Self::Elem];
    fn len() -> usize;
}

macro_rules! impl_arr_init {
    (__impl $n: expr) => (
        unsafe impl<T> FixedInitializer for [T;  $n] {
            type Elem = T;
            fn as_init_slice(&self) -> &[T] { self }
            fn len() -> usize { $n }
        }
    );
    () => ();
    ($n: expr, $($m:expr,)*) => (
        impl_arr_init!(__impl $n);
        impl_arr_init!($($m,)*);
    )

}

impl_arr_init!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);

/// Return a two-dimensional array with elements from `xs`.
///
/// ```
/// use ndarray::arr2;
///
/// let a = arr2(&[[1, 2, 3],
///                [4, 5, 6]]);
/// assert!(
///     a.shape() == [2, 3]
/// );
/// ```
pub fn arr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> OwnedArray<A, (Ix, Ix)> {
    let (m, n) = (xs.len() as Ix, V::len() as Ix);
    let dim = (m, n);
    let mut result = Vec::<A>::with_capacity(dim.size());
    for snd in xs {
        result.extend_from_slice(snd.as_init_slice());
    }
    unsafe {
        ArrayBase::from_vec_dim_unchecked(dim, result)
    }
}

/// Return a two-dimensional array with elements from `xs`.
///
pub fn rcarr2<A: Clone, V: FixedInitializer<Elem = A>>(xs: &[V]) -> RcArray<A, (Ix, Ix)> {
    arr2(xs).into_shared()
}

/// Return a three-dimensional array with elements from `xs`.
///
/// **Panics** if the slices are not all of the same length.
///
/// ```
/// use ndarray::arr3;
///
/// let a = arr3(&[[[1, 2],
///                 [3, 4]],
///                [[5, 6],
///                 [7, 8]],
///                [[9, 0],
///                 [1, 2]]]);
/// assert!(
///     a.shape() == [3, 2, 2]
/// );
/// ```
pub fn arr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> OwnedArray<A, (Ix, Ix, Ix)>
{
    let dim = (xs.len() as Ix, V::len() as Ix, U::len() as Ix);
    let mut result = Vec::<A>::with_capacity(dim.size());
    for snd in xs {
        for thr in snd.as_init_slice() {
            result.extend_from_slice(thr.as_init_slice());
        }
    }
    unsafe {
        ArrayBase::from_vec_dim_unchecked(dim, result)
    }
}

/// Return a three-dimensional array with elements from `xs`.
pub fn rcarr3<A: Clone, V: FixedInitializer<Elem=U>, U: FixedInitializer<Elem=A>>(xs: &[V])
    -> RcArray<A, (Ix, Ix, Ix)>
{
    arr3(xs).into_shared()
}
<|endoftext|>


<commit_before>use time::{now, Tm, strptime, Duration};
use crypto::mac::{Mac, MacResult};
use crypto::hmac::Hmac;
use crypto::sha2::Sha512Trunc224;
use rustc_serialize::base64::{ToBase64, FromBase64, URL_SAFE, FromBase64Error};
use hyper::header::{Headers, Cookie, SetCookie};
use cookie::Cookie as CookiePair;
use std::str::{FromStr, from_utf8, Utf8Error};
use std::string::ToString;
use std::fmt::{self, Debug};

/// An auth token.  This gets serialized and put in a cookie
pub struct AuthToken {
    /// The time that the token was created.  Used to calculate timeout
    pub time: Tm,
    /// The data you wish to store in the token
    pub data: String,
    hmac: MacResult,
}

/// Error returned when deserializing a token
#[derive(Debug)]
pub enum TokenError {
    Base64(FromBase64Error),
    FirstDotNotFound,
    Utf8(Utf8Error),
    SecondDotNotFound,
}

impl Debug for AuthToken {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "AuthToken {{ time: {:?}, data: {}, hmac: {:?} }}",
               self.time, self.data, self.hmac.code().to_base64(URL_SAFE))
    }
}

impl ToString for AuthToken {
    fn to_string(&self) -> String {
        let text = format!("{}.{}", self.data, self.time.to_timespec().sec)
            .as_bytes()
            .to_base64(URL_SAFE);

        format!("{}.{}", text, self.hmac.code().to_base64(URL_SAFE))
    }
}

impl FromStr for AuthToken {
    type Err = TokenError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split('.').collect();
        if parts.len() != 2 {
            return Err(TokenError::FirstDotNotFound);
        }

        let hmacpart = try!(parts.get(1).unwrap().from_base64());
        let hmac = MacResult::new_from_owned(hmacpart);

        let user = try!(parts.get(0).unwrap().from_base64());
        let userparts: Vec<&str> = try!(from_utf8(&user)).split('.').collect();
        if userparts.len() != 2 {
            return Err(TokenError::SecondDotNotFound);
        }

        let data = userparts.get(0).unwrap();
        let t = strptime(userparts.get(1).unwrap(), "%s").unwrap().to_utc();

        Ok(AuthToken {
            time: t,
            data: data.to_string(),
            hmac: hmac,
        })
    }
}

impl AuthToken {
    /// Create a new AuthToken.  hmac_secret is the secret key, data is the
    /// data you wish to store
    pub fn new(hmac_secret: &str, data: &str) -> AuthToken {
        AuthToken::new_with_time(hmac_secret, data, now().to_utc())
    }

    /// Create a new AuthToken, but specify the creation time
    pub fn new_with_time(hmac_secret: &str, data: &str, t: Tm) -> AuthToken {
        let mut hmac = Hmac::new(Sha512Trunc224::new(), hmac_secret.as_bytes());
        let text = format!("{}.{}", data, t.rfc3339());
        hmac.input(text.as_bytes());

        AuthToken {
            time: t,
            data: data.to_string(),
            hmac: hmac.result(),
        }

    }

    /// Verify whether `unknown` matches `good` within `timeout`
    pub fn verify_token_set_timeout(good: &AuthToken, unknown: &AuthToken,
                                    timeout: Duration) -> bool {
        let mut is_good = true;

        is_good = is_good && (good.hmac == unknown.hmac);

        is_good = is_good && (unknown.time >= (now().to_utc() - timeout));

        is_good
    }

    /// Verify whether `unknown` matches `good` and is within the timeout
    /// (default timout is 5 mintues)
    pub fn verify_token(good: &AuthToken, unknown: &AuthToken) -> bool {
        let timeout = Duration::minutes(5);
        AuthToken::verify_token_set_timeout(good, unknown, timeout)
    }

}

impl From<FromBase64Error> for TokenError {
    fn from(e: FromBase64Error) -> TokenError {
        TokenError::Base64(e)
    }
}

impl From<Utf8Error> for TokenError {
    fn from(e: Utf8Error) -> TokenError {
        TokenError::Utf8(e)
    }
}

/// Takes a a key (hmac_secret), the data, and hyper Headers and adds the
/// serialized AuthToken to the SetCookie header
pub fn set_auth_cookie(hmac_secret: &str, data: &str, headers: &mut Headers) {
    let token = AuthToken::new(hmac_secret, data);
    let c_pair = CookiePair::new("auth_token".to_string(), token.to_string());

    match headers.get_mut::<SetCookie>() {
        Some(c) => {
            c.push(c_pair);
            return;
        },
        None => {}
    };
    headers.set::<SetCookie>(SetCookie(vec![c_pair]));
}

/// Verifies an AuthToken given an hmac_secret from the Cookie in a hyper
/// Headers
pub fn verify_auth_cookie(hmac_secret: &str, headers: &Headers) -> bool {
    let to_verify = match get_auth_token_from_headers(headers) {
        Some(v) => v,
        None => return false
    };
    let good = AuthToken::new_with_time(hmac_secret, &to_verify.data,
                                        to_verify.time);

    AuthToken::verify_token(&good, &to_verify)
}

/// Extract the AuthToken from hyper Headers
pub fn get_auth_token_from_headers(headers: &Headers) -> Option<AuthToken> {
    let cookies = match headers.get::<Cookie>() {
        Some(c) => c,
        None => return None
    };

    let mut auth_string = "".to_string();

    for c in cookies.iter() {
        if c.name == "auth_token" {
            auth_string = c.value.clone();
            break;
        }
    }

    match AuthToken::from_str(&auth_string) {
        Ok(v) => Some(v),
        Err(_) => None
    }
}
<commit_msg>Change data to generic type :smile:<commit_after>use time::{now, Tm, strptime, Duration};
use crypto::mac::{Mac, MacResult};
use crypto::hmac::Hmac;
use crypto::sha2::Sha512Trunc224;
use rustc_serialize::base64::{ToBase64, FromBase64, URL_SAFE, FromBase64Error};
use hyper::header::{Headers, Cookie, SetCookie};
use cookie::Cookie as CookiePair;
use std::str::{FromStr, from_utf8, Utf8Error};
use std::string::ToString;
use std::fmt::{self, Debug, Display};

/// An auth token.  This gets serialized and put in a cookie
pub struct AuthToken<D> {
    /// The time that the token was created.  Used to calculate timeout
    pub time: Tm,
    /// The data you wish to store in the token
    pub data: D,
    hmac: MacResult,
}

/// Error returned when deserializing a token
#[derive(Debug)]
pub enum TokenError {
    Base64(FromBase64Error),
    FirstDotNotFound,
    Utf8(Utf8Error),
    SecondDotNotFound,
}

impl<D> Debug for AuthToken<D> where D: Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "AuthToken {{ time: {:?}, data: {:?}, hmac: {:?} }}",
               self.time, self.data, self.hmac.code().to_base64(URL_SAFE))
    }
}

impl<D> ToString for AuthToken<D> where D: Display {
    fn to_string(&self) -> String {
        let text = format!("{}.{}", self.data, self.time.to_timespec().sec)
            .as_bytes()
            .to_base64(URL_SAFE);

        format!("{}.{}", text, self.hmac.code().to_base64(URL_SAFE))
    }
}

impl<D> FromStr for AuthToken<D> where D: FromStr, <D as FromStr>::Err: Debug {
    type Err = TokenError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split('.').collect();
        if parts.len() != 2 {
            return Err(TokenError::FirstDotNotFound);
        }

        let hmacpart = try!(parts.get(1).unwrap().from_base64());
        let hmac = MacResult::new_from_owned(hmacpart);

        let user = try!(parts.get(0).unwrap().from_base64());
        let userparts: Vec<&str> = try!(from_utf8(&user)).split('.').collect();
        if userparts.len() != 2 {
            return Err(TokenError::SecondDotNotFound);
        }

        let data: D = D::from_str(userparts.get(0).unwrap()).unwrap();
        let t = strptime(userparts.get(1).unwrap(), "%s").unwrap().to_utc();

        Ok(AuthToken {
            time: t,
            data: data,
            hmac: hmac,
        })
    }
}

impl <D: Display> AuthToken<D> {
    /// Create a new AuthToken.  hmac_secret is the secret key, data is the
    /// data you wish to store
    pub fn new(hmac_secret: &str, data: D) -> AuthToken<D> {
        AuthToken::new_with_time(hmac_secret, data, now().to_utc())
    }

    /// Create a new AuthToken, but specify the creation time
    pub fn new_with_time(hmac_secret: &str, data: D, t: Tm) -> AuthToken<D> {
        let mut hmac = Hmac::new(Sha512Trunc224::new(), hmac_secret.as_bytes());
        let text = format!("{}.{}", data, t.rfc3339());
        hmac.input(text.as_bytes());

        AuthToken {
            time: t,
            data: data,
            hmac: hmac.result(),
        }

    }

    /// Verify whether `unknown` matches `good` within `timeout`
    pub fn verify_token_set_timeout<B>(&self, unknown: &AuthToken<B>,
                                       timeout: Duration) -> bool {
        let mut is_good = true;

        is_good = is_good && (self.hmac == unknown.hmac);

        is_good = is_good && (unknown.time >= (now().to_utc() - timeout));

        is_good
    }

    /// Verify whether `unknown` matches `good` and is within the timeout
    /// (default timout is 5 mintues)
    pub fn verify_token<B>(&self, unknown: &AuthToken<B>) -> bool {
        let timeout = Duration::minutes(5);

        self.verify_token_set_timeout(unknown, timeout)
    }

}

impl From<FromBase64Error> for TokenError {
    fn from(e: FromBase64Error) -> TokenError {
        TokenError::Base64(e)
    }
}

impl From<Utf8Error> for TokenError {
    fn from(e: Utf8Error) -> TokenError {
        TokenError::Utf8(e)
    }
}

/// Takes a a key (hmac_secret), the data, and hyper Headers and adds the
/// serialized AuthToken to the SetCookie header
pub fn set_auth_cookie(hmac_secret: &str, data: &str, headers: &mut Headers) {
    let token = AuthToken::new(hmac_secret, data);
    let c_pair = CookiePair::new("auth_token".to_string(), token.to_string());

    match headers.get_mut::<SetCookie>() {
        Some(c) => {
            c.push(c_pair);
            return;
        },
        None => {}
    };
    headers.set::<SetCookie>(SetCookie(vec![c_pair]));
}

/// Verifies an AuthToken given an hmac_secret from the Cookie in a hyper
/// Headers
pub fn verify_auth_cookie<D>(hmac_secret: &str, headers: &Headers) -> bool
        where D: FromStr + Display, <D as FromStr>::Err: Debug {
    let to_verify: AuthToken<D> = match get_auth_token_from_headers(headers) {
        Some(v) => v,
        None => return false
    };
    let good = AuthToken::new_with_time(hmac_secret, &to_verify.data,
                                        to_verify.time);

    good.verify_token(&to_verify)
}

/// Extract the AuthToken from hyper Headers
pub fn get_auth_token_from_headers<D>(headers: &Headers)
    -> Option<AuthToken<D>> where D: FromStr + Display,
                                  <D as FromStr>::Err: Debug {
    let cookies = match headers.get::<Cookie>() {
        Some(c) => c,
        None => return None
    };

    let mut auth_string = "".to_string();

    for c in cookies.iter() {
        if c.name == "auth_token" {
            auth_string = c.value.clone();
            break;
        }
    }

    match AuthToken::from_str(&auth_string) {
        Ok(v) => Some(v),
        Err(_) => None
    }
}
<|endoftext|>


<commit_before>
use std::str;
use parser::{Node, Children, Data};

#[macro_escape]
mod macros;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~" )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      // TODO: use StrBuf here somehow when it's merged in
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    wrapChildrenOutput( ~"or!( ", node , ~" )" )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNodeContents( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  // TODO: unescape chars
  let content = codeForNodeContents( node ).trim().to_owned();

  [ rule_name.to_owned(),
    ~"!( r\"",
    content.slice_chars( 1, content.len() - 1 ).replace( r#"""#, r#"\""# ),
    ~"\" )" ].concat()
}
<commit_msg>Suffix rule code generation<commit_after>
use std::str;
use parser::{Node, Children, Data};

#[macro_escape]
mod macros;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~" )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Suffix" => suffixOutput( node ),
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      // TODO: use StrBuf here somehow when it's merged in
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    wrapChildrenOutput( ~"or!( ", node , ~" )" )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNodeContents( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  }
}

fn suffixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let macro_name = match children.get( 1 ).name {
      "QUESTION" => ~"opt",
      "STAR" => ~"star",
      "PLUS" => ~"plus",
      _ => fail!( "Bad second child." )
    };

    [ macro_name, ~"!( ", codeForNode( children.get( 0 ) ), ~" )" ].concat()
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  // TODO: unescape chars
  let content = codeForNodeContents( node ).trim().to_owned();

  [ rule_name.to_owned(),
    ~"!( r\"",
    content.slice_chars( 1, content.len() - 1 ).replace( r#"""#, r#"\""# ),
    ~"\" )" ].concat()
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

extern crate brain;

use std::process;
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use clap::{Arg, App};

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brain file to process")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("output-file")
            .short("o")
            .help("Write output to <target>")
            .value_name("target")
            .takes_value(true)
        )
        .get_matches();

    let source_file = Path::new(args.value_of("input-file").unwrap());
    if !source_file.exists() || !source_file.is_file() {
        println_stderr!("Not a valid file: '{}'", source_file.display());
        process::exit(1);
    }

    let output = args.value_of("output-file").map_or_else(|| {
        let mut path = PathBuf::from(source_file.file_name().and_then(|s| s.to_str()).unwrap_or(""));
        path.set_extension("bf");
        path
    }, |s| PathBuf::from(s));

    println!("{} -> {}", source_file.display(), output.display());

//    println!("Source Code:\n\n{}\n", source);
//
//    let mut f = try!(File::open("foo.txt"));
//    let mut s = String::new();
//    try!(f.read_to_string(&mut s));
//    println!("AST:\n\n{:#?}", brain::parse(source));
}
<commit_msg>Added ability to actually read input file and better error messages<commit_after>#[macro_use]
extern crate clap;

extern crate brain;

use std::process;
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brain file to process")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("output-file")
            .short("o")
            .help("Write output to <target>")
            .value_name("target")
            .takes_value(true)
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let output_path = args.value_of("output-file").map_or_else(|| {
        let mut path = PathBuf::from(source_path.file_name().and_then(|s| s.to_str()).unwrap_or(""));
        path.set_extension("bf");
        path
    }, |s| PathBuf::from(s));

    let mut f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });
    let mut source = String::new();
    f.read_to_string(&mut source).unwrap_or_else(|e| {
        exit_with_error!("Could not read source file: {}", e);
    });
    println!("Source Code:\n\n{}\n", source);

    println!("AST:\n\n{:#?}", brain::parse(&source));
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

extern crate libc;

use std::cell::Cell;
use self::libc::size_t;
use self::libc::c_int;
use self::libc::c_char;
use std::ptr;
use std::ffi::CString;

//////////////////////////////////////////////////////////////////
pub struct Prober<'a> {
    file:       &'a str,
    raw_prober: Cell<*const i32>
}

impl<'a> Prober<'a> {
    pub fn new(filename: &str) -> Prober {
        Prober{file: filename,
               raw_prober: Cell::new(ptr::null())}
    }

    pub fn probe(&self) -> Result<(), String> {
        let name = CString::new(self.file).unwrap();
        let name_raw = name.into_raw();
        unsafe {
            self.raw_prober.set(blkid_new_probe_from_filename(name_raw));
        }

        if self.raw_prober.get().is_null() {
            return Err("Error in blkid_new_probe_from_filename!".to_string());
        }

        let rr: c_int;
        unsafe {
            rr = blkid_do_probe(self.raw_prober.get());
        }

        if rr < 0 {
            let message = "Error in blkid_do_probe!".to_string();
            return Err(message);
        }
        Ok(())
    }

    pub fn getType(&self) -> Result<String, String> {
        return self.get("TYPE");
    }

    pub fn getLabel(&self) -> Result<String, String> {
        return self.get("LABEL");
    }

    pub fn get(&self, key: &str) -> Result<String, String> {
        let c_key = CString::new(key).unwrap();
        let c_key_raw = c_key.into_raw();
        let mut buff: c_char = 0;
        let mut p_buff: *mut c_char = &mut buff;
        let p_p_buff: *mut *mut c_char = &mut p_buff;
        let i: size_t = 0;
        let p_i: *const size_t  = &i;

        let res: c_int;
        unsafe {
            res = blkid_probe_lookup_value(self.raw_prober.get(),
                                           c_key_raw,
                                           p_p_buff,
                                           p_i);
        }

        if res < 0 {
            let message = "Error in blkid_probe_lookup_value!".to_string();
            return Err(message);
        }

        unsafe {
            let ss = CString::from_raw(p_buff);
            let sss = ss.into_string();
            match sss {
                Ok(r)  => Ok(r),
                _      => Err("Error in CString::into_string!".to_string())
            }
        }
    }
}

impl<'a> Drop for Prober<'a> {
    fn drop(&mut self) {
        let ptr = self.raw_prober.get();
        if ptr.is_null() {
            return;
        }

        unsafe {
            blkid_free_probe(ptr);
        }
    }
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[link(name = "blkid")]
extern {
    fn blkid_new_probe_from_filename(file: *const c_char) -> *const i32;
    fn blkid_do_probe(prober: *const i32) -> c_int;
    fn blkid_probe_lookup_value(prober: *const i32,
                                key: *const c_char,
                                data: *mut *mut c_char,
                                size: *const size_t) -> c_int;
    fn blkid_free_probe(prober: *const i32);
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[test]
fn test_blkid_01() {
    let p = Prober::new("/dev/sda1");
    let p_r = p.probe();
    match p_r {
        Err(r) => {
            println!("{}", r);
            return;
        },
        _       => println!("********* OK ***********")
    }

    let t = p.getType();
    match t {
        Ok(r)  => println!("{}", r),
        Err(r) => println!("{}", r)
    }

    let l = p.getLabel();
    match l {
        Ok(r)  => println!("{}", r),
        Err(r) => println!("{}", r)
    }

    let k = p.get("ARC");
    match k {
        Ok(r)  => println!("{}", r),
        Err(r) => println!("{}", r)
    }
}
//////////////////////////////////////////////////////////////////
<commit_msg>fix type of *struct<commit_after>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

extern crate libc;

use std::cell::Cell;
use self::libc::size_t;
use self::libc::c_int;
use self::libc::c_char;
use std::ptr;
use std::ffi::CString;

//////////////////////////////////////////////////////////////////
pub struct Prober<'a> {
    file:       &'a str,
    raw_prober: Cell<*const usize>
}

impl<'a> Prober<'a> {
    pub fn new(filename: &str) -> Prober {
        Prober{file: filename,
               raw_prober: Cell::new(ptr::null())}
    }

    pub fn probe(&self) -> Result<(), String> {
        let name = CString::new(self.file).unwrap();
        let name_raw = name.into_raw();
        unsafe {
            self.raw_prober.set(blkid_new_probe_from_filename(name_raw));
        }

        if self.raw_prober.get().is_null() {
            return Err("Error in blkid_new_probe_from_filename!".to_string());
        }

        let rr: c_int;
        unsafe {
            rr = blkid_do_probe(self.raw_prober.get());
        }

        if rr < 0 {
            let message = "Error in blkid_do_probe!".to_string();
            return Err(message);
        }
        Ok(())
    }

    pub fn getType(&self) -> Result<String, String> {
        return self.get("TYPE");
    }

    pub fn getLabel(&self) -> Result<String, String> {
        return self.get("LABEL");
    }

    pub fn get(&self, key: &str) -> Result<String, String> {
        let c_key = CString::new(key).unwrap();
        let c_key_raw = c_key.into_raw();
        let mut buff: c_char = 0;
        let mut p_buff: *mut c_char = &mut buff;
        let p_p_buff: *mut *mut c_char = &mut p_buff;
        let i: size_t = 0;
        let p_i: *const size_t  = &i;

        let res: c_int;
        unsafe {
            res = blkid_probe_lookup_value(self.raw_prober.get(),
                                           c_key_raw,
                                           p_p_buff,
                                           p_i);
        }

        if res < 0 {
            let message = "Error in blkid_probe_lookup_value!".to_string();
            return Err(message);
        }

        unsafe {
            let ss = CString::from_raw(p_buff);
            let sss = ss.into_string();
            match sss {
                Ok(r)  => Ok(r),
                _      => Err("Error in CString::into_string!".to_string())
            }
        }
    }
}

impl<'a> Drop for Prober<'a> {
    fn drop(&mut self) {
        let ptr = self.raw_prober.get();
        if ptr.is_null() {
            return;
        }

        unsafe {
            blkid_free_probe(ptr);
        }
    }
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[link(name = "blkid")]
extern {
    fn blkid_new_probe_from_filename(file: *const c_char) -> *const usize;
    fn blkid_do_probe(prober: *const usize) -> c_int;
    fn blkid_probe_lookup_value(prober: *const usize,
                                key: *const c_char,
                                data: *mut *mut c_char,
                                size: *const size_t) -> c_int;
    fn blkid_free_probe(prober: *const usize);
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[test]
fn test_blkid_01() {
    let p = Prober::new("/dev/sda1");
    let p_r = p.probe();
    match p_r {
        Err(r) => {
            println!("{}", r);
            return;
        },
        _       => println!("********* OK ***********")
    }

    let t = p.getType();
    match t {
        Ok(r)  => println!("{}", r),
        Err(r) => println!("{}", r)
    }

    let l = p.getLabel();
    match l {
        Ok(r)  => println!("{}", r),
        Err(r) => println!("{}", r)
    }

    let k = p.get("ARC");
    match k {
        Ok(r)  => println!("{}", r),
        Err(r) => println!("{}", r)
    }
}
//////////////////////////////////////////////////////////////////
<|endoftext|>