<commit_before>#![doc(html_root_url = "https://docs.rs/twitter-stream/0.10.0-alpha.3")]
#![recursion_limit = "128"]

/*!
# Twitter Stream

A library for listening on Twitter Streaming API.

## Usage

Add `twitter-stream` to your dependencies in your project's `Cargo.toml`:

```toml
[dependencies]
futures = "0.3"
tokio = { version = "0.2", features = ["macros"] }
twitter-stream = "=0.10.0-alpha.3"
```

## Overview

Here is a basic example that prints public mentions to @Twitter in JSON format:

```rust,no_run
use futures::prelude::*;
use twitter_stream::Token;

# #[tokio::main]
# async fn main() {
let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");

twitter_stream::Builder::filter(token)
    .track(Some("@Twitter"))
    .listen()
    .try_flatten_stream()
    .try_for_each(|json| {
        println!("{}", json);
        future::ok(())
    })
    .await
    .unwrap();
# }
```
*/

#[cfg(feature = "hyper")]
extern crate hyper_pkg as hyper;

#[macro_use]
mod util;

pub mod error;
pub mod types;

mod gzip;
mod token;

pub use oauth::Credentials;

pub use crate::error::Error;
pub use crate::token::Token;

use std::borrow::Borrow;
use std::future::Future;
use std::pin::Pin;
use std::str;
use std::task::{Context, Poll};

use bytes::Bytes;
use futures_core::Stream;
use futures_util::ready;
use http::header::{
    HeaderValue, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE,
};
use http::response::Parts;
use http::{Request, Response};
use http_body::Body;
use pin_project::pin_project;
use tower_service::Service;

use crate::gzip::MaybeGzip;
use crate::types::{FilterLevel, RequestMethod, StatusCode, Uri};
use crate::util::*;

/// A builder for `TwitterStream`.
///
/// ## Example
///
/// ```rust,no_run
/// use futures::prelude::*;
/// use twitter_stream::Token;
///
/// # #[tokio::main]
/// # async fn main() {
/// let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");
///
/// twitter_stream::Builder::sample(token)
///     .listen()
///     .try_flatten_stream()
///     .try_for_each(|json| {
///         println!("{}", json);
///         future::ok(())
///     })
///     .await
///     .unwrap();
/// # }
/// ```
#[derive(Clone, Debug)]
pub struct Builder<'a, T = Token> {
    method: RequestMethod,
    endpoint: Uri,
    token: T,
    inner: BuilderInner<'a>,
}

/// A future returned by constructor methods
/// which resolves to a `TwitterStream`.
#[pin_project]
pub struct FutureTwitterStream<F> {
    #[pin]
    response: F,
}

/// A listener for Twitter Streaming API.
/// It yields JSON strings returned from the API.
#[pin_project]
pub struct TwitterStream<B: Body<Data = Bytes>> {
    #[pin]
    inner: Lines<MaybeGzip<HttpBodyAsStream<B>>>,
}

#[derive(Clone, Debug, oauth::Authorize)]
struct BuilderInner<'a> {
    #[oauth1(skip_if = "not")]
    stall_warnings: bool,
    filter_level: Option<FilterLevel>,
    language: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_follow")]
    follow: Option<&'a [u64]>,
    track: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_locations")]
    #[allow(clippy::type_complexity)]
    locations: Option<&'a [((f64, f64), (f64, f64))]>,
    #[oauth1(encoded)]
    count: Option<i32>,
}

impl<'a, C, A> Builder<'a, Token<C, A>>
where
    C: Borrow<str>,
    A: Borrow<str>,
{
    /// Create a builder for `POST statuses/filter` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/post/statuses/filter
    pub fn filter(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/filter.json";
        Self::custom(RequestMethod::POST, Uri::from_static(URI), token)
    }

    /// Create a builder for `GET statuses/sample` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/get/statuses/sample
    pub fn sample(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/sample.json";
        Self::custom(RequestMethod::GET, Uri::from_static(URI), token)
    }

    /// Constructs a builder for a Stream at a custom endpoint.
    pub fn custom(method: RequestMethod, endpoint: Uri, token: Token<C, A>) -> Self {
        Self {
            method,
            endpoint,
            token,
            inner: BuilderInner {
                stall_warnings: false,
                filter_level: None,
                language: None,
                follow: None,
                track: None,
                locations: None,
                count: None,
            },
        }
    }

    /// Start listening on the Streaming API endpoint, returning a `Future` which resolves
    /// to a `Stream` yielding JSON messages from the API.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    #[cfg(feature = "hyper")]
    pub fn listen(&self) -> FutureTwitterStream<hyper::client::ResponseFuture> {
        let conn = hyper_tls::HttpsConnector::new();
        self.listen_with_client(hyper::Client::builder().build::<_, hyper::Body>(conn))
    }

    /// Same as `listen` except that it uses `client` to make HTTP request to the endpoint.
    ///
    /// # Panics
    ///
    /// This will call `<S as Service>::call` without checking for `<S as Service>::poll_ready`
    /// and may cause a panic if `client` is not ready to send an HTTP request yet.
    pub fn listen_with_client<S, ReqB, ResB>(&self, mut client: S) -> FutureTwitterStream<S::Future>
    where
        S: Service<Request<ReqB>, Response = Response<ResB>>,
        ReqB: Default + From<Vec<u8>>,
        ResB: Body<Data = Bytes>,
    {
        let req = Request::builder()
            .method(self.method.clone())
            .header(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));

        let mut oauth = oauth::Builder::new(self.token.client.as_ref(), oauth::HmacSha1);
        oauth.token(self.token.token.as_ref());
        let req = if RequestMethod::POST == self.method {
            let oauth::Request {
                authorization,
                data,
            } = oauth.post_form(&self.endpoint, &self.inner);

            req.uri(self.endpoint.clone())
                .header(AUTHORIZATION, authorization)
                .header(
                    CONTENT_TYPE,
                    HeaderValue::from_static("application/x-www-form-urlencoded"),
                )
                .header(CONTENT_LENGTH, data.len())
                .body(data.into_bytes().into())
                .unwrap()
        } else {
            let oauth::Request {
                authorization,
                data: uri,
            } = oauth.build(self.method.as_ref(), &self.endpoint, &self.inner);

            req.uri(uri)
                .header(AUTHORIZATION, authorization)
                .body(ReqB::default())
                .unwrap()
        };

        let response = client.call(req);
        FutureTwitterStream { response }
    }
}

impl<'a, C, A> Builder<'a, Token<C, A>> {
    /// Reset the HTTP request method to be used when connecting
    /// to the server.
    pub fn method(&mut self, method: RequestMethod) -> &mut Self {
        self.method = method;
        self
    }

    /// Reset the API endpoint URI to be connected.
    pub fn endpoint(&mut self, endpoint: Uri) -> &mut Self {
        self.endpoint = endpoint;
        self
    }

    /// Reset the token to be used to log into Twitter.
    pub fn token(&mut self, token: Token<C, A>) -> &mut Self {
        self.token = token;
        self
    }

    /// Set whether to receive messages when in danger of
    /// being disconnected.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#stall-warnings
    pub fn stall_warnings(&mut self, stall_warnings: bool) -> &mut Self {
        self.inner.stall_warnings = stall_warnings;
        self
    }

    /// Set the minimum `filter_level` Tweet attribute to receive.
    /// The default is `FilterLevel::None`.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#filter-level
    pub fn filter_level(&mut self, filter_level: impl Into<Option<FilterLevel>>) -> &mut Self {
        self.inner.filter_level = filter_level.into();
        self
    }

    /// Set a comma-separated language identifiers to receive Tweets
    /// written in the specified languages only.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#language
    pub fn language(&mut self, language: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.language = language.into();
        self
    }

    /// Set a list of user IDs to receive Tweets from the specified users.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#follow
    pub fn follow(&mut self, follow: impl Into<Option<&'a [u64]>>) -> &mut Self {
        self.inner.follow = follow.into();
        self
    }

    /// A comma separated list of phrases to filter Tweets by.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#track
    pub fn track(&mut self, track: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.track = track.into();
        self
    }

    /// Set a list of bounding boxes to filter Tweets by,
    /// specified by a pair of coordinates in the form of
    /// `((longitude, latitude), (longitude, latitude))` tuple.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#locations
    pub fn locations(
        &mut self,
        locations: impl Into<Option<&'a [((f64, f64), (f64, f64))]>>,
    ) -> &mut Self {
        self.inner.locations = locations.into();
        self
    }

    /// The `count` parameter.
    /// This parameter requires elevated access to use.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#count
    pub fn count(&mut self, count: impl Into<Option<i32>>) -> &mut Self {
        self.inner.count = count.into();
        self
    }
}

#[cfg(feature = "hyper")]
impl<B: Body<Data = Bytes>> TwitterStream<B> {
    /// A shorthand for `Builder::filter().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn filter<C, A>(token: Token<C, A>) -> FutureTwitterStream<hyper::client::ResponseFuture>
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::filter(token).listen()
    }

    /// A shorthand for `Builder::sample().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn sample<C, A>(token: Token<C, A>) -> FutureTwitterStream<hyper::client::ResponseFuture>
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::sample(token).listen()
    }
}

impl<F, B, E> Future for FutureTwitterStream<F>
where
    F: Future<Output = Result<Response<B>, E>>,
    B: Body<Data = Bytes>,
{
    type Output = Result<TwitterStream<B>, Error<E>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let res = match ready!(self.project().response.poll(cx)) {
            Ok(res) => res,
            Err(e) => return Poll::Ready(Err(Error::Service(e))),
        };
        let (parts, body) = res.into_parts();
        let Parts {
            status, headers, ..
        } = parts;

        if StatusCode::OK != status {
            return Poll::Ready(Err(Error::Http(status)));
        }

        let use_gzip = headers
            .get_all(CONTENT_ENCODING)
            .iter()
            .any(|e| e == "gzip");
        let inner = if use_gzip {
            Lines::new(gzip::gzip(HttpBodyAsStream(body)))
        } else {
            Lines::new(gzip::identity(HttpBodyAsStream(body)))
        };

        Poll::Ready(Ok(TwitterStream { inner }))
    }
}

impl<B> Stream for TwitterStream<B>
where
    B: Body<Data = Bytes>,
{
    type Item = Result<string::String<Bytes>, Error<B::Error>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut this = self.project();

        loop {
            let line = ready_some!(this.inner.as_mut().poll_next(cx))?;
            if line.iter().all(|&c| is_json_whitespace(c)) {
                continue;
            }

            str::from_utf8(&line).map_err(Error::Utf8)?;
            let line = unsafe {
                // Safety:
                // - We have checked above that `line` is valid as UTF-8.
                // - `Bytes` satisfies the requirements of `string::StableAsRef` trait
                // (https://github.com/carllerche/string/pull/17)
                string::String::<Bytes>::from_utf8_unchecked(line)
            };
            return Poll::Ready(Some(Ok(line)));
        }
    }
}

fn is_json_whitespace(c: u8) -> bool {
    // RFC7159 §2
    b" \t\n\r".contains(&c)
}
<commit_msg>Remove unnecessary `#![recursion_limit = ...]`<commit_after>#![doc(html_root_url = "https://docs.rs/twitter-stream/0.10.0-alpha.3")]

/*!
# Twitter Stream

A library for listening on Twitter Streaming API.

## Usage

Add `twitter-stream` to your dependencies in your project's `Cargo.toml`:

```toml
[dependencies]
futures = "0.3"
tokio = { version = "0.2", features = ["macros"] }
twitter-stream = "=0.10.0-alpha.3"
```

## Overview

Here is a basic example that prints public mentions to @Twitter in JSON format:

```rust,no_run
use futures::prelude::*;
use twitter_stream::Token;

# #[tokio::main]
# async fn main() {
let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");

twitter_stream::Builder::filter(token)
    .track(Some("@Twitter"))
    .listen()
    .try_flatten_stream()
    .try_for_each(|json| {
        println!("{}", json);
        future::ok(())
    })
    .await
    .unwrap();
# }
```
*/

#[cfg(feature = "hyper")]
extern crate hyper_pkg as hyper;

#[macro_use]
mod util;

pub mod error;
pub mod types;

mod gzip;
mod token;

pub use oauth::Credentials;

pub use crate::error::Error;
pub use crate::token::Token;

use std::borrow::Borrow;
use std::future::Future;
use std::pin::Pin;
use std::str;
use std::task::{Context, Poll};

use bytes::Bytes;
use futures_core::Stream;
use futures_util::ready;
use http::header::{
    HeaderValue, ACCEPT_ENCODING, AUTHORIZATION, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE,
};
use http::response::Parts;
use http::{Request, Response};
use http_body::Body;
use pin_project::pin_project;
use tower_service::Service;

use crate::gzip::MaybeGzip;
use crate::types::{FilterLevel, RequestMethod, StatusCode, Uri};
use crate::util::*;

/// A builder for `TwitterStream`.
///
/// ## Example
///
/// ```rust,no_run
/// use futures::prelude::*;
/// use twitter_stream::Token;
///
/// # #[tokio::main]
/// # async fn main() {
/// let token = Token::new("consumer_key", "consumer_secret", "access_key", "access_secret");
///
/// twitter_stream::Builder::sample(token)
///     .listen()
///     .try_flatten_stream()
///     .try_for_each(|json| {
///         println!("{}", json);
///         future::ok(())
///     })
///     .await
///     .unwrap();
/// # }
/// ```
#[derive(Clone, Debug)]
pub struct Builder<'a, T = Token> {
    method: RequestMethod,
    endpoint: Uri,
    token: T,
    inner: BuilderInner<'a>,
}

/// A future returned by constructor methods
/// which resolves to a `TwitterStream`.
#[pin_project]
pub struct FutureTwitterStream<F> {
    #[pin]
    response: F,
}

/// A listener for Twitter Streaming API.
/// It yields JSON strings returned from the API.
#[pin_project]
pub struct TwitterStream<B: Body<Data = Bytes>> {
    #[pin]
    inner: Lines<MaybeGzip<HttpBodyAsStream<B>>>,
}

#[derive(Clone, Debug, oauth::Authorize)]
struct BuilderInner<'a> {
    #[oauth1(skip_if = "not")]
    stall_warnings: bool,
    filter_level: Option<FilterLevel>,
    language: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_follow")]
    follow: Option<&'a [u64]>,
    track: Option<&'a str>,
    #[oauth1(encoded, fmt = "fmt_locations")]
    #[allow(clippy::type_complexity)]
    locations: Option<&'a [((f64, f64), (f64, f64))]>,
    #[oauth1(encoded)]
    count: Option<i32>,
}

impl<'a, C, A> Builder<'a, Token<C, A>>
where
    C: Borrow<str>,
    A: Borrow<str>,
{
    /// Create a builder for `POST statuses/filter` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/post/statuses/filter
    pub fn filter(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/filter.json";
        Self::custom(RequestMethod::POST, Uri::from_static(URI), token)
    }

    /// Create a builder for `GET statuses/sample` endpoint.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://dev.twitter.com/streaming/reference/get/statuses/sample
    pub fn sample(token: Token<C, A>) -> Self {
        const URI: &str = "https://stream.twitter.com/1.1/statuses/sample.json";
        Self::custom(RequestMethod::GET, Uri::from_static(URI), token)
    }

    /// Constructs a builder for a Stream at a custom endpoint.
    pub fn custom(method: RequestMethod, endpoint: Uri, token: Token<C, A>) -> Self {
        Self {
            method,
            endpoint,
            token,
            inner: BuilderInner {
                stall_warnings: false,
                filter_level: None,
                language: None,
                follow: None,
                track: None,
                locations: None,
                count: None,
            },
        }
    }

    /// Start listening on the Streaming API endpoint, returning a `Future` which resolves
    /// to a `Stream` yielding JSON messages from the API.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    #[cfg(feature = "hyper")]
    pub fn listen(&self) -> FutureTwitterStream<hyper::client::ResponseFuture> {
        let conn = hyper_tls::HttpsConnector::new();
        self.listen_with_client(hyper::Client::builder().build::<_, hyper::Body>(conn))
    }

    /// Same as `listen` except that it uses `client` to make HTTP request to the endpoint.
    ///
    /// # Panics
    ///
    /// This will call `<S as Service>::call` without checking for `<S as Service>::poll_ready`
    /// and may cause a panic if `client` is not ready to send an HTTP request yet.
    pub fn listen_with_client<S, ReqB, ResB>(&self, mut client: S) -> FutureTwitterStream<S::Future>
    where
        S: Service<Request<ReqB>, Response = Response<ResB>>,
        ReqB: Default + From<Vec<u8>>,
        ResB: Body<Data = Bytes>,
    {
        let req = Request::builder()
            .method(self.method.clone())
            .header(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));

        let mut oauth = oauth::Builder::new(self.token.client.as_ref(), oauth::HmacSha1);
        oauth.token(self.token.token.as_ref());
        let req = if RequestMethod::POST == self.method {
            let oauth::Request {
                authorization,
                data,
            } = oauth.post_form(&self.endpoint, &self.inner);

            req.uri(self.endpoint.clone())
                .header(AUTHORIZATION, authorization)
                .header(
                    CONTENT_TYPE,
                    HeaderValue::from_static("application/x-www-form-urlencoded"),
                )
                .header(CONTENT_LENGTH, data.len())
                .body(data.into_bytes().into())
                .unwrap()
        } else {
            let oauth::Request {
                authorization,
                data: uri,
            } = oauth.build(self.method.as_ref(), &self.endpoint, &self.inner);

            req.uri(uri)
                .header(AUTHORIZATION, authorization)
                .body(ReqB::default())
                .unwrap()
        };

        let response = client.call(req);
        FutureTwitterStream { response }
    }
}

impl<'a, C, A> Builder<'a, Token<C, A>> {
    /// Reset the HTTP request method to be used when connecting
    /// to the server.
    pub fn method(&mut self, method: RequestMethod) -> &mut Self {
        self.method = method;
        self
    }

    /// Reset the API endpoint URI to be connected.
    pub fn endpoint(&mut self, endpoint: Uri) -> &mut Self {
        self.endpoint = endpoint;
        self
    }

    /// Reset the token to be used to log into Twitter.
    pub fn token(&mut self, token: Token<C, A>) -> &mut Self {
        self.token = token;
        self
    }

    /// Set whether to receive messages when in danger of
    /// being disconnected.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#stall-warnings
    pub fn stall_warnings(&mut self, stall_warnings: bool) -> &mut Self {
        self.inner.stall_warnings = stall_warnings;
        self
    }

    /// Set the minimum `filter_level` Tweet attribute to receive.
    /// The default is `FilterLevel::None`.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#filter-level
    pub fn filter_level(&mut self, filter_level: impl Into<Option<FilterLevel>>) -> &mut Self {
        self.inner.filter_level = filter_level.into();
        self
    }

    /// Set a comma-separated language identifiers to receive Tweets
    /// written in the specified languages only.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#language
    pub fn language(&mut self, language: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.language = language.into();
        self
    }

    /// Set a list of user IDs to receive Tweets from the specified users.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#follow
    pub fn follow(&mut self, follow: impl Into<Option<&'a [u64]>>) -> &mut Self {
        self.inner.follow = follow.into();
        self
    }

    /// A comma separated list of phrases to filter Tweets by.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#track
    pub fn track(&mut self, track: impl Into<Option<&'a str>>) -> &mut Self {
        self.inner.track = track.into();
        self
    }

    /// Set a list of bounding boxes to filter Tweets by,
    /// specified by a pair of coordinates in the form of
    /// `((longitude, latitude), (longitude, latitude))` tuple.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#locations
    pub fn locations(
        &mut self,
        locations: impl Into<Option<&'a [((f64, f64), (f64, f64))]>>,
    ) -> &mut Self {
        self.inner.locations = locations.into();
        self
    }

    /// The `count` parameter.
    /// This parameter requires elevated access to use.
    ///
    /// See the [Twitter Developer Documentation][1] for more information.
    ///
    /// [1]: https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/basic-stream-parameters#count
    pub fn count(&mut self, count: impl Into<Option<i32>>) -> &mut Self {
        self.inner.count = count.into();
        self
    }
}

#[cfg(feature = "hyper")]
impl<B: Body<Data = Bytes>> TwitterStream<B> {
    /// A shorthand for `Builder::filter().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn filter<C, A>(token: Token<C, A>) -> FutureTwitterStream<hyper::client::ResponseFuture>
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::filter(token).listen()
    }

    /// A shorthand for `Builder::sample().listen()`.
    ///
    /// # Panics
    ///
    /// This will panic if the underlying HTTPS connector failed to initialize.
    pub fn sample<C, A>(token: Token<C, A>) -> FutureTwitterStream<hyper::client::ResponseFuture>
    where
        C: Borrow<str>,
        A: Borrow<str>,
    {
        Builder::sample(token).listen()
    }
}

impl<F, B, E> Future for FutureTwitterStream<F>
where
    F: Future<Output = Result<Response<B>, E>>,
    B: Body<Data = Bytes>,
{
    type Output = Result<TwitterStream<B>, Error<E>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let res = match ready!(self.project().response.poll(cx)) {
            Ok(res) => res,
            Err(e) => return Poll::Ready(Err(Error::Service(e))),
        };
        let (parts, body) = res.into_parts();
        let Parts {
            status, headers, ..
        } = parts;

        if StatusCode::OK != status {
            return Poll::Ready(Err(Error::Http(status)));
        }

        let use_gzip = headers
            .get_all(CONTENT_ENCODING)
            .iter()
            .any(|e| e == "gzip");
        let inner = if use_gzip {
            Lines::new(gzip::gzip(HttpBodyAsStream(body)))
        } else {
            Lines::new(gzip::identity(HttpBodyAsStream(body)))
        };

        Poll::Ready(Ok(TwitterStream { inner }))
    }
}

impl<B> Stream for TwitterStream<B>
where
    B: Body<Data = Bytes>,
{
    type Item = Result<string::String<Bytes>, Error<B::Error>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let mut this = self.project();

        loop {
            let line = ready_some!(this.inner.as_mut().poll_next(cx))?;
            if line.iter().all(|&c| is_json_whitespace(c)) {
                continue;
            }

            str::from_utf8(&line).map_err(Error::Utf8)?;
            let line = unsafe {
                // Safety:
                // - We have checked above that `line` is valid as UTF-8.
                // - `Bytes` satisfies the requirements of `string::StableAsRef` trait
                // (https://github.com/carllerche/string/pull/17)
                string::String::<Bytes>::from_utf8_unchecked(line)
            };
            return Poll::Ready(Some(Ok(line)));
        }
    }
}

fn is_json_whitespace(c: u8) -> bool {
    // RFC7159 §2
    b" \t\n\r".contains(&c)
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A generic library for textures.
//!
//! This library is used in Piston for generic code when working with textures.
//!
//! The `ImageSize` trait is used for passing textures around for rendering.
//! For more information, see
//! [Piston-Graphics](https://github.com/pistondevelopers/graphics).

pub mod ops;

/// Implemented by all images to be used with generic algorithms.
pub trait ImageSize {
    /// Get the image size.
    fn get_size(&self) -> (u32, u32);

    /// Gets the image width.
    #[inline(always)]
    fn get_width(&self) -> u32 {
        let (w, _) = self.get_size();
        w
    }

    /// Gets the image height.
    #[inline(always)]
    fn get_height(&self) -> u32 {
        let (_, h) = self.get_size();
        h
    }
}

/// Texture creation parameters.
pub struct TextureSettings {
    // Whether to convert gamma, treated as sRGB color space
    convert_gamma: bool,
    // Compress on GPU.
    compress: bool,
    // Generate mipmap chain.
    generate_mipmap: bool,
    // Filtering Mode for Minifying
    min: Filter,
    // Filtering Mode for Magnifying
    mag: Filter,
    // Filtering Mode for Minify Mipmapping
    mipmap: Filter
}

impl TextureSettings {
    /// Create default settings.
    pub fn new() -> TextureSettings {
        TextureSettings {
            convert_gamma: false,
            compress: false,
            generate_mipmap: false,
            min: Filter::Linear,
            mag: Filter::Linear,
            mipmap: Filter::Linear,
        }
    }

    /// Gets whether to convert gamma, treated as sRGB color space.
    pub fn get_convert_gamma(&self) -> bool { self.convert_gamma }
    /// Sets convert gamma.
    pub fn set_convert_gamma(&mut self, val: bool) { self.convert_gamma = val; }
    /// Sets convert gamma.
    pub fn convert_gamma(mut self, val: bool) -> Self {
        self.set_convert_gamma(val);
        self
    }

    /// Gets wheter compress on the GPU.
    pub fn get_compress(&self) -> bool { self.compress }
    /// Sets compress.
    pub fn set_compress(&mut self, val: bool) { self.compress = val; }
    /// Sets compress.
    pub fn compress(mut self, val: bool) -> Self {
        self.set_compress(val);
        self
    }

    /// Gets generate mipmap.
    pub fn get_generate_mipmap(&self) -> bool { self.generate_mipmap }
    /// Sets generate mipmap.
    pub fn set_generate_mipmap(&mut self, val: bool) {
        self.generate_mipmap = val;
    }
    /// Sets generate mipmap.
    pub fn generate_mipmap(mut self, val: bool) -> Self {
        self.set_generate_mipmap(val);
        self
    }

    /// Gets minify filter.
    pub fn get_min(&self) -> Filter { self.min }
    /// Sets minify filter.
    pub fn set_min(&mut self, val: Filter) {
        self.min = val
    }
    /// Sets minify filter.
    pub fn min(mut self, val: Filter) -> Self {
        self.set_min(val);
        self
    }

    /// Gets magnify filter
    pub fn get_mag(&self) -> Filter { self.mag }
    /// Sets magnify filter
    pub fn set_mag(&mut self, val: Filter) {
        self.mag = val;
    }
    /// Sets magnify filter
    pub fn mag(mut self, val: Filter) -> Self {
        self.set_mag(val);
        self
    }

    /// Gets minify mipmap filter
    pub fn get_mipmap(&self) -> Filter { self.mipmap }
    /// Sets magnify mipmap filter, and sets generate_mipmap to true.
    pub fn set_mipmap(&mut self, val: Filter) {
        self.set_generate_mipmap(true);
        self.mag = val;
    }
    /// Sets magnify mipmap filter, and sets generate_mipmap to true
    pub fn mipmap(mut self, val: Filter) -> Self {
        self.set_mag(val);
        self
    }

    /// Returns the min and mag filter
    pub fn get_filter(&self) -> (Filter, Filter) { (self.min, self.mag) }
    /// Sets the min and mag filter
    pub fn set_filter(&mut self, val: Filter) {
        self.set_min(val);
        self.set_mag(val);
    }

    /// Sets the min and mag filter
    pub fn filter(mut self, val: Filter) -> Self {
        self.set_filter(val);
        self
    }

}

/// Texture format.
#[derive(Copy, Clone, Debug)]
pub enum Format {
    /// `(red, green, blue, alpha)` with values 0-255.
    Rgba8,
}

/// Implemented by textures for creation.
pub trait CreateTexture<F>: ImageSize + Sized {
    /// The error when creating texture.
    type Error;

    /// Create texture from memory.
    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error>;
}

/// Implemented by textures for updating.
pub trait UpdateTexture<F>: ImageSize + Sized {
    /// The error when updating texture.
    type Error;

    /// Update texture.
    fn update<S: Into<[u32; 2]>>(
        &mut self,
        factory: &mut F,
        format: Format,
        memory: &[u8],
        size: S,
    ) -> Result<(), Self::Error>;
}

/// Sampling filter
#[derive(Copy, Clone, Debug)]
pub enum Filter {
    /// A Weighted Linear Blend
    Linear,
    /// Nearest Texel
    Nearest
}
<commit_msg>Add an offset argument to the UpdateTexture::update method<commit_after>#![deny(missing_docs)]

//! A generic library for textures.
//!
//! This library is used in Piston for generic code when working with textures.
//!
//! The `ImageSize` trait is used for passing textures around for rendering.
//! For more information, see
//! [Piston-Graphics](https://github.com/pistondevelopers/graphics).

pub mod ops;

/// Implemented by all images to be used with generic algorithms.
pub trait ImageSize {
    /// Get the image size.
    fn get_size(&self) -> (u32, u32);

    /// Gets the image width.
    #[inline(always)]
    fn get_width(&self) -> u32 {
        let (w, _) = self.get_size();
        w
    }

    /// Gets the image height.
    #[inline(always)]
    fn get_height(&self) -> u32 {
        let (_, h) = self.get_size();
        h
    }
}

/// Texture creation parameters.
pub struct TextureSettings {
    // Whether to convert gamma, treated as sRGB color space
    convert_gamma: bool,
    // Compress on GPU.
    compress: bool,
    // Generate mipmap chain.
    generate_mipmap: bool,
    // Filtering Mode for Minifying
    min: Filter,
    // Filtering Mode for Magnifying
    mag: Filter,
    // Filtering Mode for Minify Mipmapping
    mipmap: Filter
}

impl TextureSettings {
    /// Create default settings.
    pub fn new() -> TextureSettings {
        TextureSettings {
            convert_gamma: false,
            compress: false,
            generate_mipmap: false,
            min: Filter::Linear,
            mag: Filter::Linear,
            mipmap: Filter::Linear,
        }
    }

    /// Gets whether to convert gamma, treated as sRGB color space.
    pub fn get_convert_gamma(&self) -> bool { self.convert_gamma }
    /// Sets convert gamma.
    pub fn set_convert_gamma(&mut self, val: bool) { self.convert_gamma = val; }
    /// Sets convert gamma.
    pub fn convert_gamma(mut self, val: bool) -> Self {
        self.set_convert_gamma(val);
        self
    }

    /// Gets wheter compress on the GPU.
    pub fn get_compress(&self) -> bool { self.compress }
    /// Sets compress.
    pub fn set_compress(&mut self, val: bool) { self.compress = val; }
    /// Sets compress.
    pub fn compress(mut self, val: bool) -> Self {
        self.set_compress(val);
        self
    }

    /// Gets generate mipmap.
    pub fn get_generate_mipmap(&self) -> bool { self.generate_mipmap }
    /// Sets generate mipmap.
    pub fn set_generate_mipmap(&mut self, val: bool) {
        self.generate_mipmap = val;
    }
    /// Sets generate mipmap.
    pub fn generate_mipmap(mut self, val: bool) -> Self {
        self.set_generate_mipmap(val);
        self
    }

    /// Gets minify filter.
    pub fn get_min(&self) -> Filter { self.min }
    /// Sets minify filter.
    pub fn set_min(&mut self, val: Filter) {
        self.min = val
    }
    /// Sets minify filter.
    pub fn min(mut self, val: Filter) -> Self {
        self.set_min(val);
        self
    }

    /// Gets magnify filter
    pub fn get_mag(&self) -> Filter { self.mag }
    /// Sets magnify filter
    pub fn set_mag(&mut self, val: Filter) {
        self.mag = val;
    }
    /// Sets magnify filter
    pub fn mag(mut self, val: Filter) -> Self {
        self.set_mag(val);
        self
    }

    /// Gets minify mipmap filter
    pub fn get_mipmap(&self) -> Filter { self.mipmap }
    /// Sets magnify mipmap filter, and sets generate_mipmap to true.
    pub fn set_mipmap(&mut self, val: Filter) {
        self.set_generate_mipmap(true);
        self.mag = val;
    }
    /// Sets magnify mipmap filter, and sets generate_mipmap to true
    pub fn mipmap(mut self, val: Filter) -> Self {
        self.set_mag(val);
        self
    }

    /// Returns the min and mag filter
    pub fn get_filter(&self) -> (Filter, Filter) { (self.min, self.mag) }
    /// Sets the min and mag filter
    pub fn set_filter(&mut self, val: Filter) {
        self.set_min(val);
        self.set_mag(val);
    }

    /// Sets the min and mag filter
    pub fn filter(mut self, val: Filter) -> Self {
        self.set_filter(val);
        self
    }

}

/// Texture format.
#[derive(Copy, Clone, Debug)]
pub enum Format {
    /// `(red, green, blue, alpha)` with values 0-255.
    Rgba8,
}

/// Implemented by textures for creation.
pub trait CreateTexture<F>: ImageSize + Sized {
    /// The error when creating texture.
    type Error;

    /// Create texture from memory.
    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error>;
}

/// Implemented by textures for updating.
pub trait UpdateTexture<F>: ImageSize + Sized {
    /// The error when updating texture.
    type Error;

    /// Update the texture.
    ///
    /// The `offset` and `size` arguments represent the position and dimensions of the sub-section
    /// of the texture that is to be updated with the given `memory`.
    fn update<O, S>(
        &mut self,
        factory: &mut F,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>;
}

/// Sampling filter
#[derive(Copy, Clone, Debug)]
pub enum Filter {
    /// A Weighted Linear Blend
    Linear,
    /// Nearest Texel
    Nearest
}
<|endoftext|>


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

//! Operations on ASCII strings and characters

#![feature(macro_rules, globs, default_type_params, old_orphan_check)]
// added old_orphan_check to work around https://github.com/rust-lang/rust/issues/20477

#![unstable = "unsure about placement and naming"]
#![allow(deprecated)]

//use std::kinds::Sized;

use std::fmt;
use std::mem;
use std::borrow::BorrowFrom;
use std::ascii::AsciiExt;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Converts an ascii character into a `u8`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline]
    #[stable]
    pub fn to_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    /// Convert to uppercase.
    #[inline]
    #[stable]
    pub fn to_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    #[stable]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    #[unstable = "may be renamed"]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    #[stable]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    #[experimental = "likely to be removed"]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    #[stable]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    #[experimental = "unsure about naming, or whether this is needed"]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    #[unstable = "unsure about naming"]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    #[stable]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    #[stable]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    #[stable]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    #[stable]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl<'a> fmt::Show for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.chr as char).fmt(f)
    }
}

/// Trait for converting into an ascii type.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiCast<T, U = Self> : AsciiExt<U> {
    /// Convert to an ascii type, return Err(()) on non-ASCII input.
    #[inline]
    fn to_ascii(&self) -> Result<T, ()> {
        if self.is_ascii() {
            Ok(unsafe { self.to_ascii_nocheck() })
        } else {
            Err(())
        }
    }

    /// Convert to an ascii type, not doing any range asserts
    unsafe fn to_ascii_nocheck(&self) -> T;
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a[Ascii], Vec<u8>> for [u8] {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a [Ascii], String> for str {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for u8 {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for char {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

/// Trait for copyless casting to an ascii vector.
#[experimental = "may be replaced by generic conversion traits"]
pub trait OwnedAsciiCast<T: ?Sized, U = Self> : Sized
where T: BorrowFrom<Self> + AsciiExt<U> {
    /// Take ownership and cast to an ascii vector. Return Err(()) on non-ASCII input.
    #[inline]
    fn into_ascii(self) -> Result<Vec<Ascii>, Self> {
        if {
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        } {
            Ok(unsafe { self.into_ascii_nocheck() })
        } else {
            Err(self)
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        self.into_bytes().into_ascii_nocheck()
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
                                    self.len(),
                                    self.capacity());

        // We forget `self` to avoid freeing it at the end of the scope
        // Otherwise, the returned `Vec` would point to freed memory
        mem::forget(self);
        v
    }
}

/// Trait for converting a type to a string, consuming it in the process.
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoString {
    /// Consume and convert to a string.
    fn into_string(self) -> String;
}

/// Trait for converting an ascii type to a string. Needed to convert
/// `&[Ascii]` to `&str`.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiStr {
    /// Convert to a string.
    fn as_str<'a>(&'a self) -> &'a str;

    /// Convert to bytes.
    fn as_bytes<'a>(&'a self) -> &'a [u8];
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiStr for [Ascii] {
    #[inline]
    fn as_str<'a>(&'a self) -> &'a str {
        unsafe { mem::transmute(self) }
    }

    #[inline]
    fn as_bytes<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(self) }
    }
}

impl IntoString for Vec<Ascii> {
    #[inline]
    fn into_string(self) -> String {
        unsafe { String::from_utf8_unchecked(self.into_bytes()) }
    }
}

/// Trait to convert to an owned byte vector by consuming self
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoBytes {
    /// Converts to an owned byte vector by consuming self
    fn into_bytes(self) -> Vec<u8>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl IntoBytes for Vec<Ascii> {
    fn into_bytes(self) -> Vec<u8> {
        unsafe {
            let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
                                        self.len(),
                                        self.capacity());

            // We forget `self` to avoid freeing it at the end of the scope
            // Otherwise, the returned `Vec` would point to freed memory
            mem::forget(self);
            v
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
        (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
    );

    macro_rules! vec2ascii (
        ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
    );

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
        assert_eq!(65u8.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_byte(), 65u8);

        assert!('0'.to_ascii().unwrap().is_digit());
        assert!('9'.to_ascii().unwrap().is_digit());
        assert!(!'/'.to_ascii().unwrap().is_digit());
        assert!(!':'.to_ascii().unwrap().is_digit());

        assert!(0x1f_u8.to_ascii().unwrap().is_control());
        assert!(!' '.to_ascii().unwrap().is_control());
        assert!(0x7f_u8.to_ascii().unwrap().is_control());
    }

    #[test]
    fn test_ascii_vec() {
        let test = &[40u8, 32u8, 59u8];
        let b: &[_] = v2ascii!([40, 32, 59]);
        assert_eq!(test.to_ascii().unwrap(), b);
        assert_eq!("( ;".to_ascii().unwrap(), b);
        let v = vec![40u8, 32u8, 59u8];
        assert_eq!(v.as_slice().to_ascii().unwrap(), b);
        assert_eq!("( ;".to_string().as_slice().to_ascii().unwrap(), b);
    }

    #[test]
    fn test_ascii_as_str() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_str(), "( ;");
    }

    #[test]
    fn test_ascii_as_bytes() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_bytes(), b"( ;");
    }

    #[test]
    fn test_ascii_into_string() {
        assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
        assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
    }

    #[test]
    fn test_ascii_to_bytes() {
        assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
    }

    #[test]
    fn test_opt() {
        assert_eq!(65u8.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!(255u8.to_ascii(), Err(()));

        assert_eq!('A'.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!('λ'.to_ascii(), Err(()));

        assert_eq!("zoä华".to_ascii(), Err(()));

        let test1 = &[127u8, 128u8, 255u8];
        assert_eq!(test1.to_ascii(), Err(()));

        let v = [40u8, 32u8, 59u8];
        let v2: &[_] = v2ascii!(&[40, 32, 59]);
        assert_eq!(v.to_ascii(), Ok(v2));
        let v = [127u8, 128u8, 255u8];
        assert_eq!(v.to_ascii(), Err(()));

        let v = "( ;";
        assert_eq!(v.to_ascii(), Ok(v2));
        assert_eq!("zoä华".to_ascii(), Err(()));

        assert_eq!(vec![40u8, 32u8, 59u8].into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!(vec![127u8, 128u8, 255u8].into_ascii(), Err(vec![127u8, 128u8, 255u8]));

        assert_eq!("( ;".to_string().into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!("zoä华".to_string().into_ascii(), Err("zoä华".to_string()));
    }

    #[test]
    fn test_to_string() {
        let s = Ascii{ chr: b't' }.to_string();
        assert_eq!(s, "t".to_string());
    }

    #[test]
    fn test_show() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{}", c), "t".to_string());
    }
}
<commit_msg>Update documentation to reflect the current code<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

#![feature(macro_rules, globs, default_type_params, old_orphan_check)]
// added old_orphan_check to work around https://github.com/rust-lang/rust/issues/20477

#![unstable = "unsure about placement and naming"]
#![allow(deprecated)]

//use std::kinds::Sized;

use std::fmt;
use std::mem;
use std::borrow::BorrowFrom;
use std::ascii::AsciiExt;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Converts an ascii character into a `u8`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline]
    #[stable]
    pub fn to_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    /// Convert to uppercase.
    #[inline]
    #[stable]
    pub fn to_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    #[stable]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    #[unstable = "may be renamed"]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    #[stable]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    #[experimental = "likely to be removed"]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    #[stable]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    #[experimental = "unsure about naming, or whether this is needed"]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    #[unstable = "unsure about naming"]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    #[stable]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    #[stable]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    #[stable]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    #[stable]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl<'a> fmt::Show for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.chr as char).fmt(f)
    }
}

/// Trait for converting into an ascii type.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiCast<T, U = Self> : AsciiExt<U> {
    /// Convert to an ascii type, return Err(()) on non-ASCII input.
    #[inline]
    fn to_ascii(&self) -> Result<T, ()> {
        if self.is_ascii() {
            Ok(unsafe { self.to_ascii_nocheck() })
        } else {
            Err(())
        }
    }

    /// Convert to an ascii type, not doing any range asserts
    unsafe fn to_ascii_nocheck(&self) -> T;
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a[Ascii], Vec<u8>> for [u8] {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a [Ascii], String> for str {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for u8 {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for char {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

/// Trait for copyless casting to an ascii vector.
#[experimental = "may be replaced by generic conversion traits"]
pub trait OwnedAsciiCast<T: ?Sized, U = Self> : Sized
where T: BorrowFrom<Self> + AsciiExt<U> {
    /// Take ownership and cast to an ascii vector. On non-ASCII input return ownership of data
    /// that was attempted to cast to ascii in `Err(Self)`.
    #[inline]
    fn into_ascii(self) -> Result<Vec<Ascii>, Self> {
        if {
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        } {
            Ok(unsafe { self.into_ascii_nocheck() })
        } else {
            Err(self)
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        self.into_bytes().into_ascii_nocheck()
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
                                    self.len(),
                                    self.capacity());

        // We forget `self` to avoid freeing it at the end of the scope
        // Otherwise, the returned `Vec` would point to freed memory
        mem::forget(self);
        v
    }
}

/// Trait for converting a type to a string, consuming it in the process.
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoString {
    /// Consume and convert to a string.
    fn into_string(self) -> String;
}

/// Trait for converting an ascii type to a string. Needed to convert
/// `&[Ascii]` to `&str`.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiStr {
    /// Convert to a string.
    fn as_str<'a>(&'a self) -> &'a str;

    /// Convert to bytes.
    fn as_bytes<'a>(&'a self) -> &'a [u8];
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiStr for [Ascii] {
    #[inline]
    fn as_str<'a>(&'a self) -> &'a str {
        unsafe { mem::transmute(self) }
    }

    #[inline]
    fn as_bytes<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(self) }
    }
}

impl IntoString for Vec<Ascii> {
    #[inline]
    fn into_string(self) -> String {
        unsafe { String::from_utf8_unchecked(self.into_bytes()) }
    }
}

/// Trait to convert to an owned byte vector by consuming self
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoBytes {
    /// Converts to an owned byte vector by consuming self
    fn into_bytes(self) -> Vec<u8>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl IntoBytes for Vec<Ascii> {
    fn into_bytes(self) -> Vec<u8> {
        unsafe {
            let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
                                        self.len(),
                                        self.capacity());

            // We forget `self` to avoid freeing it at the end of the scope
            // Otherwise, the returned `Vec` would point to freed memory
            mem::forget(self);
            v
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
        (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
    );

    macro_rules! vec2ascii (
        ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
    );

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
        assert_eq!(65u8.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_byte(), 65u8);

        assert!('0'.to_ascii().unwrap().is_digit());
        assert!('9'.to_ascii().unwrap().is_digit());
        assert!(!'/'.to_ascii().unwrap().is_digit());
        assert!(!':'.to_ascii().unwrap().is_digit());

        assert!(0x1f_u8.to_ascii().unwrap().is_control());
        assert!(!' '.to_ascii().unwrap().is_control());
        assert!(0x7f_u8.to_ascii().unwrap().is_control());
    }

    #[test]
    fn test_ascii_vec() {
        let test = &[40u8, 32u8, 59u8];
        let b: &[_] = v2ascii!([40, 32, 59]);
        assert_eq!(test.to_ascii().unwrap(), b);
        assert_eq!("( ;".to_ascii().unwrap(), b);
        let v = vec![40u8, 32u8, 59u8];
        assert_eq!(v.as_slice().to_ascii().unwrap(), b);
        assert_eq!("( ;".to_string().as_slice().to_ascii().unwrap(), b);
    }

    #[test]
    fn test_ascii_as_str() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_str(), "( ;");
    }

    #[test]
    fn test_ascii_as_bytes() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_bytes(), b"( ;");
    }

    #[test]
    fn test_ascii_into_string() {
        assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
        assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
    }

    #[test]
    fn test_ascii_to_bytes() {
        assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
    }

    #[test]
    fn test_opt() {
        assert_eq!(65u8.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!(255u8.to_ascii(), Err(()));

        assert_eq!('A'.to_ascii(), Ok(Ascii { chr: 65u8 }));
        assert_eq!('λ'.to_ascii(), Err(()));

        assert_eq!("zoä华".to_ascii(), Err(()));

        let test1 = &[127u8, 128u8, 255u8];
        assert_eq!(test1.to_ascii(), Err(()));

        let v = [40u8, 32u8, 59u8];
        let v2: &[_] = v2ascii!(&[40, 32, 59]);
        assert_eq!(v.to_ascii(), Ok(v2));
        let v = [127u8, 128u8, 255u8];
        assert_eq!(v.to_ascii(), Err(()));

        let v = "( ;";
        assert_eq!(v.to_ascii(), Ok(v2));
        assert_eq!("zoä华".to_ascii(), Err(()));

        assert_eq!(vec![40u8, 32u8, 59u8].into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!(vec![127u8, 128u8, 255u8].into_ascii(), Err(vec![127u8, 128u8, 255u8]));

        assert_eq!("( ;".to_string().into_ascii(), Ok(vec2ascii![40, 32, 59]));
        assert_eq!("zoä华".to_string().into_ascii(), Err("zoä华".to_string()));
    }

    #[test]
    fn test_to_string() {
        let s = Ascii{ chr: b't' }.to_string();
        assert_eq!(s, "t".to_string());
    }

    #[test]
    fn test_show() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{}", c), "t".to_string());
    }
}
<|endoftext|>


<commit_before>extern crate libc;

#[allow(dead_code,
        non_snake_case,
        non_camel_case_types,
        non_upper_case_globals)]
pub mod libpq;

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn _PG_init() { }

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut libpq::OutputPluginCallbacks) { init(cb); }

// Implementation of initialization and callbacks.

pub unsafe extern fn init(cb: *mut libpq::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}
/*
pub type LogicalOutputPluginInit =
    ::std::option::Option<extern "C" fn(cb: *mut Struct_OutputPluginCallbacks)
                              -> ()>;
*/

extern fn startup(ctx: *mut libpq::Struct_LogicalDecodingContext,
                  options: *mut libpq::OutputPluginOptions,
                  is_init: libpq::_bool) {

}
/*
pub type LogicalDecodeStartupCB =
    ::std::option::Option<extern "C" fn(ctx:
                                            *mut Struct_LogicalDecodingContext,
                                        options: *mut OutputPluginOptions,
                                        is_init: _bool) -> ()>;
 */

extern fn begin(ctx: *mut libpq::Struct_LogicalDecodingContext,
                txn: *mut libpq::ReorderBufferTXN) {

}
/*
pub type LogicalDecodeBeginCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN) -> ()>;
 */

extern fn change(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 relation: libpq::Relation,
                 change: *mut libpq::ReorderBufferChange) {

}
/*
pub type LogicalDecodeChangeCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        relation: Relation,
                                        change: *mut ReorderBufferChange)
                              -> ()>;
 */

extern fn commit(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 lsn: libpq::XLogRecPtr) {

}
/*
pub type LogicalDecodeCommitCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        commit_lsn: XLogRecPtr) -> ()>;
 */

extern fn shutdown(ctx: *mut libpq::Struct_LogicalDecodingContext) {

}
/*
pub type LogicalDecodeShutdownCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext)
                              -> ()>;

 */
<commit_msg>Taking a stab at implementing BEGIN/COMMIT<commit_after>extern crate libc;
use std::ffi::CString;

#[allow(dead_code,
        non_snake_case,
        non_camel_case_types,
        non_upper_case_globals)]
pub mod libpq;

// Symbols Postgres needs to find.

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn _PG_init() { }

#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern fn
    _PG_output_plugin_init(cb: *mut libpq::OutputPluginCallbacks) { init(cb); }

// Implementation of initialization and callbacks.

pub unsafe extern fn init(cb: *mut libpq::OutputPluginCallbacks) {
    (*cb).startup_cb = Some(startup);
    (*cb).begin_cb = Some(begin);
    (*cb).change_cb = Some(change);
    (*cb).commit_cb = Some(commit);
    (*cb).shutdown_cb = Some(shutdown);
}
/*
pub type LogicalOutputPluginInit =
    ::std::option::Option<extern "C" fn(cb: *mut Struct_OutputPluginCallbacks)
                              -> ()>;
*/

extern fn startup(ctx: *mut libpq::Struct_LogicalDecodingContext,
                  options: *mut libpq::OutputPluginOptions,
                  is_init: libpq::_bool) {

}
/*
pub type LogicalDecodeStartupCB =
    ::std::option::Option<extern "C" fn(ctx:
                                            *mut Struct_LogicalDecodingContext,
                                        options: *mut OutputPluginOptions,
                                        is_init: _bool) -> ()>;
 */

extern fn begin(ctx: *mut libpq::Struct_LogicalDecodingContext,
                txn: *mut libpq::ReorderBufferTXN) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("BEGIN %u").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, last);
    }
}
/*
pub type LogicalDecodeBeginCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN) -> ()>;
 */

extern fn change(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 relation: libpq::Relation,
                 change: *mut libpq::ReorderBufferChange) {

}
/*
pub type LogicalDecodeChangeCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        relation: Relation,
                                        change: *mut ReorderBufferChange)
                              -> ()>;
 */

extern fn commit(ctx: *mut libpq::Struct_LogicalDecodingContext,
                 txn: *mut libpq::ReorderBufferTXN,
                 lsn: libpq::XLogRecPtr) {
    unsafe {
        let last = 1;                                     // True in C language
        let s = CString::new("COMMIT %u").unwrap();
        libpq::OutputPluginPrepareWrite(ctx, last);
        libpq::appendStringInfo((*ctx).out, s.as_ptr(), (*txn).xid);
        libpq::OutputPluginWrite(ctx, last);
    }
}
/*
pub type LogicalDecodeCommitCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext,
                                        txn: *mut ReorderBufferTXN,
                                        commit_lsn: XLogRecPtr) -> ()>;
 */

extern fn shutdown(ctx: *mut libpq::Struct_LogicalDecodingContext) {

}
/*
pub type LogicalDecodeShutdownCB =
    ::std::option::Option<extern "C" fn(arg1:
                                            *mut Struct_LogicalDecodingContext)
                              -> ()>;

 */
<|endoftext|>


<commit_before>extern crate serial;

use std::ffi::OsStr;
use std::io;
use std::io::Write;

/// A type representing a position on the cube, of the form [`x`, `y`, `z`].
pub type CubePosition = [usize; 3];

/// A connection to an LED cube.
///
/// The methods on this struct operate on an internal buffer, and won't have an effect on the cube
/// until the `flush` method is called.
///
/// # Examples
///
/// Turn each light on in sequence:
///
/// ```no_run
/// use std::thread;
/// use std::time::Duration;
/// use led_cube::*;
///
/// let mut cube = Cube::new("COM5").unwrap();
///
/// for z in 0..4 {
///     for y in 0..4 {
///         for x in 0..4 {
///             cube.clear();
///             cube.set([x, y, z], true);
///             cube.flush();
///             thread::sleep(Duration::from_millis(500));
///         }
///     }
/// }
/// ```
pub struct Cube {
    state: [u8; 16],
    port: serial::SystemPort,
}

impl Cube {
    /// Connect to an LED cube through a serial port.
    pub fn new<T: AsRef<OsStr> + ?Sized>(port: &T) -> io::Result<Self> {
        let mut cube = Cube {
            state: [0, 0, 0, 0,
                    0, 0, 0, 0,
                    0, 0, 0, 0,
                    0, 0, 0, 0],
            port: serial::open(port).unwrap(),
        };
        try!(cube.flush());
        Ok(cube)
    }

    /// Update the LED cube to match the internal buffer.
    pub fn flush(&mut self) -> io::Result<()>{
        self.port.write(&self.state).map(|_| {})
    }

    /// Turn the LED at position `pos` on or off based on `state`.
    ///
    /// # Panics
    /// Panics if `pos` is out of range.
    pub fn set(&mut self, pos: CubePosition, state: bool) {
        check_bounds(pos);
        let pattern_idx = 4 * invert4(pos[1]) + invert4(pos[2]);
        let mask = 1 << invert4(pos[0]);
        if state {
            self.state[pattern_idx] |= mask;
        } else {
            self.state[pattern_idx] &= !mask;
        }
    }

    /// Returns `true` if the LED at position `pos` is on.
    ///
    /// # Panics
    /// Panics if `pos` is out of range.
    pub fn get(&self, pos: CubePosition) -> bool {
        check_bounds(pos);
        self.state[4 * invert4(pos[1]) + invert4(pos[2])] & (1 << invert4(pos[0])) != 0
    }

    /// Turns off all LEDs.
    pub fn clear(&mut self) {
        self.state = [0, 0, 0, 0,
                      0, 0, 0, 0,
                      0, 0, 0, 0,
                      0, 0, 0, 0];
    }
}

fn check_bounds(pos: CubePosition) {
    assert!(pos[0] < 4 && pos[1] < 4 && pos[2] < 4);
}

fn invert4(n: usize) -> usize {
    [3, 2, 1, 0][n]
}
<commit_msg>Use third person singular present indicative form in comment summary line<commit_after>extern crate serial;

use std::ffi::OsStr;
use std::io;
use std::io::Write;

/// A type representing a position on the cube, of the form [`x`, `y`, `z`].
pub type CubePosition = [usize; 3];

/// A connection to an LED cube.
///
/// The methods on this struct operate on an internal buffer, and won't have an effect on the cube
/// until the `flush` method is called.
///
/// # Examples
///
/// Turn each light on in sequence:
///
/// ```no_run
/// use std::thread;
/// use std::time::Duration;
/// use led_cube::*;
///
/// let mut cube = Cube::new("COM5").unwrap();
///
/// for z in 0..4 {
///     for y in 0..4 {
///         for x in 0..4 {
///             cube.clear();
///             cube.set([x, y, z], true);
///             cube.flush();
///             thread::sleep(Duration::from_millis(500));
///         }
///     }
/// }
/// ```
pub struct Cube {
    state: [u8; 16],
    port: serial::SystemPort,
}

impl Cube {
    /// Connects to an LED cube through a serial port.
    pub fn new<T: AsRef<OsStr> + ?Sized>(port: &T) -> io::Result<Self> {
        let mut cube = Cube {
            state: [0, 0, 0, 0,
                    0, 0, 0, 0,
                    0, 0, 0, 0,
                    0, 0, 0, 0],
            port: serial::open(port).unwrap(),
        };
        try!(cube.flush());
        Ok(cube)
    }

    /// Updates the LED cube to match the internal buffer.
    pub fn flush(&mut self) -> io::Result<()>{
        self.port.write(&self.state).map(|_| {})
    }

    /// Turns the LED at position `pos` on or off based on `state`.
    ///
    /// # Panics
    /// Panics if `pos` is out of range.
    pub fn set(&mut self, pos: CubePosition, state: bool) {
        check_bounds(pos);
        let pattern_idx = 4 * invert4(pos[1]) + invert4(pos[2]);
        let mask = 1 << invert4(pos[0]);
        if state {
            self.state[pattern_idx] |= mask;
        } else {
            self.state[pattern_idx] &= !mask;
        }
    }

    /// Returns `true` if the LED at position `pos` is on.
    ///
    /// # Panics
    /// Panics if `pos` is out of range.
    pub fn get(&self, pos: CubePosition) -> bool {
        check_bounds(pos);
        self.state[4 * invert4(pos[1]) + invert4(pos[2])] & (1 << invert4(pos[0])) != 0
    }

    /// Turns off all LEDs.
    pub fn clear(&mut self) {
        self.state = [0, 0, 0, 0,
                      0, 0, 0, 0,
                      0, 0, 0, 0,
                      0, 0, 0, 0];
    }
}

fn check_bounds(pos: CubePosition) {
    assert!(pos[0] < 4 && pos[1] < 4 && pos[2] < 4);
}

fn invert4(n: usize) -> usize {
    [3, 2, 1, 0][n]
}
<|endoftext|>


<commit_before>use std::cmp;

// 2 billion junctions is good enough for now
pub type JunctionIndex = usize;
pub type Time = i64;
pub type Level = bool;

#[derive (Clone, Copy)]
pub enum GateBehavior {
	And,
	Not,
	Or,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Signal {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

pub struct Circuit {
	wires: Vec <Wire>,
	gates: Vec <Gate>,
}

pub struct World {
	// These don't change at runtime
	circuit: Circuit,

	junctions: Vec <Level>,
	time: Time,
	signals: Vec <Signal>,
}

pub enum WorldCreationErr {
	// Two elements point to the same junction, this is illegal
	FanIn,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Wire {
		Wire {
			input: self.input + offset,
			output: self.output + offset,
			delay: self.delay,
		}
	}
}

impl Gate {
	fn offset_junctions (&self, offset: JunctionIndex) -> Gate {
		Gate {
			inputs: self.inputs.iter ().map (|junction| junction + offset).collect (),
			output: self.output + offset,
			behavior: self.behavior,
		}
	}
}

impl Circuit {
	fn new_half_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 1, 4),
				(0, 5, 8),
				(2, 3, 4),
				(6, 7, 3),
				(8, 4, 8),
				(8, 9, 4),
			]),
			gates: vec![
				Gate {
					inputs: vec![1, 4],
					output: 2,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 9],
					output: 6,
					behavior: GateBehavior::Xor,
				},
			]
		}
	}

	fn new_full_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 3, 1),
				(0, 5, 1),
				(1, 4, 1),
				(1, 6, 1),
				(2, 11, 1),
				(2, 9, 1),
				(7, 10, 1),
				(7, 8, 1),
				(12, 14, 1),
				(13, 15, 1),
			]),
			gates: vec![
				Gate {
					inputs: vec![3, 4],
					output: 7,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![10, 11],
					output: 16,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![8, 9],
					output: 12,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 6],
					output: 13,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![14, 15],
					output: 17,
					behavior: GateBehavior::Or,
				},
			]
		}
	}

	fn wires_from_tuples (wire_tuples: Vec <(JunctionIndex, JunctionIndex, Time)>) -> Vec <Wire> {
		wire_tuples.iter ().map (|tuple| Wire::new (tuple.0, tuple.1, tuple.2)).collect ()
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Circuit {
		Circuit {
			wires: self.wires.iter ().map (|wire| wire.offset_junctions (offset)).collect (),
			gates: self.gates.iter ().map (|gate| gate.offset_junctions (offset)).collect (),
		}
	}

	fn max_junction (&self) -> JunctionIndex {
		let max_junction_wires = self.wires.iter ().fold (0, |max, wire| cmp::max (max, cmp::max (wire.input, wire.output)));
		let max_junction_gates = self.gates.iter ().fold (0, |max, gate| {
			let max_input = gate.inputs.iter ().max ();

			let max_junction_gate = match max_input {
				Option::Some (junction) => cmp::max (*junction, gate.output),
				Option::None => gate.output,
			};

			cmp::max (max, max_junction_gate)
		});

		cmp::max (max_junction_gates, max_junction_wires)
	}

	fn junction_count (&self) -> JunctionIndex {
		self.max_junction () + 1
	}

	fn has_fan_in (&self) -> bool {
		let mut junction_has_input = vec! [false; self.junction_count ()];

		for wire in self.wires.iter () {
			if junction_has_input [wire.output] {
				return true;
			}

			junction_has_input [wire.output] = true;
		}

		for gate in self.gates.iter () {
			if junction_has_input [gate.output] {
				return true;
			}

			junction_has_input [gate.output] = true;
		}

		false
	}
}

impl World {
	pub fn new_from_circuit (circuit: Circuit) -> Result <World, WorldCreationErr> {
		if circuit.has_fan_in () {
			return Err (WorldCreationErr::FanIn);
		}

		Ok (World {
			time: 0,
			signals: vec![],
			junctions: vec![false; circuit.junction_count ()],
			circuit: circuit,
		})
	}

	pub fn new (wires: Vec <Wire>, gates: Vec <Gate>) -> Result <World, WorldCreationErr> {
		World::new_from_circuit (Circuit {
			wires: wires,
			gates: gates,
		})
	}

	pub fn new_half_adder () -> World {
		World::new_from_circuit (Circuit::new_half_adder ()).ok ().expect ("Half adder circuit is invalid")
	}

	pub fn new_full_adder () -> World {
		World::new_from_circuit (Circuit::new_full_adder ()).ok ().expect ("Full adder circuit is invalid")
	}

	pub fn is_settled (& self) -> bool {
		self.signals.len () == 0
	}

	fn sort_signals (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.signals.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_signals = Vec::<Signal>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.circuit.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Not => ! inputs [0],
				GateBehavior::Or => inputs.iter ().fold (false, |sum, a| sum || *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
			};

			let destiny_level = self.get_junction_destiny (gate.output);

			if destiny_level != output {
				new_signals.push (Signal {
					junction: gate.output,
					time: self.time,
					level: output,
				});
			}
		};

		// TODO: Proper insertion sorting
		// If the number of new signals is small compared to the number of
		// in-flight signals, I could do a few binary insertions sorts.
		// If the number is large, it might be better to do a mergesort.
		for signal in new_signals {
			self.signals.push (signal);
		}

		self.sort_signals ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> Level {
		if self.signals.len () > 0 {
			// Find the last signal that was heading for that junction
			// Remember that junctions are not allowed to fan in
			for i in 0 .. self.signals.len () {
				let signals = self.signals [self.signals.len () - i - 1];

				if signals.junction == junction {
					return signals.level;
				}
			}
		}

		self.junctions [junction]
	}

	fn step_wires (&mut self) {
		for wire in self.circuit.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny_level = self.get_junction_destiny (wire.output);

			if input != destiny_level {
				self.signals.push (Signal {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});
			}
		};

		// TODO: Proper insertion sorting
		self.sort_signals ();
	}

	fn propagate_signals (&mut self) {
		let next_time = self.signals [0].time;

		for signal in self.signals.iter () {
			if signal.time == next_time {
				self.junctions [signal.junction] = signal.level;
			}
			else if signal.time > next_time {
				break;
			}
		}

		self.signals.retain (|signal| signal.time > next_time);

		self.time = next_time;
	}

	pub fn set_junction (&mut self, junction: JunctionIndex, level: Level) {
		self.signals.push (Signal {
			junction: junction,
			level: level,
			time: self.time,
		});
	}

	pub fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_signals ();

		self.propagate_signals ();

		self.step_gates ();
		self.step_wires ();
	}

	pub fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}

#[test]
pub fn test_fan_in () {
	let world_or_err = World::new (
		Circuit::wires_from_tuples (vec! [
		(0, 2, 1),
		(1, 2, 1),
		]),
		vec! []
	);

	if let Err (WorldCreationErr::FanIn) = world_or_err {
		// Good
	}
	else {
		panic! ("World creation should have thrown a FanIn error");
	}
}

#[test]
pub fn test_half_adder () {
	let mut world = World::new_half_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &World, msb: Level, lsb: Level| {
		assert_eq! (world.junctions [3], msb);
		assert_eq! (world.junctions [7], lsb);
	};

	assert_outputs (&world, false, false);

	// Junctions 0 and 8 are the input bits

	world.set_junction (0, true);
	world.step_to_settled ();
	assert_outputs (&world, false, true);

	world.set_junction (8, true);
	world.step_to_settled ();
	assert_outputs (&world, true, false);

	world.set_junction (0, false);
	world.step_to_settled ();
	assert_outputs (&world, false, true);
}

#[test]
pub fn test_full_adder () {
	let mut world = World::new_full_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &mut World, a: Level, b: Level, c: Level, carry: Level, sum: Level| {
		world.set_junction (0, a);
		world.set_junction (1, b);
		world.set_junction (2, c);

		world.step_to_settled ();

		assert_eq! (world.junctions [17], carry);
		assert_eq! (world.junctions [16], sum);
	};

	// Truth table for a full adder
	assert_outputs (&mut world, false, false, false, false, false);
	assert_outputs (&mut world, false, false, true, false, true);
	assert_outputs (&mut world, false, true, true, true, false);
	assert_outputs (&mut world, false, true, false, false, true);

	assert_outputs (&mut world, true, true, false, true, false);
	assert_outputs (&mut world, true, true, true, true, true);
	assert_outputs (&mut world, true, false, true, true, false);
	assert_outputs (&mut world, true, false, false, false, true);
}

#[test]
pub fn test_ripple_adder () {
	//let
}<commit_msg>Circuits are now Clone<commit_after>use std::cmp;

// 2 billion junctions is good enough for now
pub type JunctionIndex = usize;
pub type Time = i64;
pub type Level = bool;

#[derive (Clone, Copy)]
pub enum GateBehavior {
	And,
	Not,
	Or,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Signal {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

#[derive (Clone)]
pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

#[derive (Clone)]
pub struct Circuit {
	wires: Vec <Wire>,
	gates: Vec <Gate>,
}

pub struct World {
	// These don't change at runtime
	circuit: Circuit,

	junctions: Vec <Level>,
	time: Time,
	signals: Vec <Signal>,
}

pub enum WorldCreationErr {
	// Two elements point to the same junction, this is illegal
	FanIn,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Wire {
		Wire {
			input: self.input + offset,
			output: self.output + offset,
			delay: self.delay,
		}
	}
}

impl Gate {
	fn offset_junctions (&self, offset: JunctionIndex) -> Gate {
		Gate {
			inputs: self.inputs.iter ().map (|junction| junction + offset).collect (),
			output: self.output + offset,
			behavior: self.behavior,
		}
	}
}

impl Circuit {
	fn new_half_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 1, 4),
				(0, 5, 8),
				(2, 3, 4),
				(6, 7, 3),
				(8, 4, 8),
				(8, 9, 4),
			]),
			gates: vec![
				Gate {
					inputs: vec![1, 4],
					output: 2,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 9],
					output: 6,
					behavior: GateBehavior::Xor,
				},
			]
		}
	}

	fn new_full_adder () -> Circuit {
		Circuit {
			wires: Circuit::wires_from_tuples (vec![
				(0, 3, 1),
				(0, 5, 1),
				(1, 4, 1),
				(1, 6, 1),
				(2, 11, 1),
				(2, 9, 1),
				(7, 10, 1),
				(7, 8, 1),
				(12, 14, 1),
				(13, 15, 1),
			]),
			gates: vec![
				Gate {
					inputs: vec![3, 4],
					output: 7,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![10, 11],
					output: 16,
					behavior: GateBehavior::Xor,
				},
				Gate {
					inputs: vec![8, 9],
					output: 12,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 6],
					output: 13,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![14, 15],
					output: 17,
					behavior: GateBehavior::Or,
				},
			]
		}
	}

	fn wires_from_tuples (wire_tuples: Vec <(JunctionIndex, JunctionIndex, Time)>) -> Vec <Wire> {
		wire_tuples.iter ().map (|tuple| Wire::new (tuple.0, tuple.1, tuple.2)).collect ()
	}

	fn offset_junctions (&self, offset: JunctionIndex) -> Circuit {
		Circuit {
			wires: self.wires.iter ().map (|wire| wire.offset_junctions (offset)).collect (),
			gates: self.gates.iter ().map (|gate| gate.offset_junctions (offset)).collect (),
		}
	}

	fn max_junction (&self) -> JunctionIndex {
		let max_junction_wires = self.wires.iter ().fold (0, |max, wire| cmp::max (max, cmp::max (wire.input, wire.output)));
		let max_junction_gates = self.gates.iter ().fold (0, |max, gate| {
			let max_input = gate.inputs.iter ().max ();

			let max_junction_gate = match max_input {
				Option::Some (junction) => cmp::max (*junction, gate.output),
				Option::None => gate.output,
			};

			cmp::max (max, max_junction_gate)
		});

		cmp::max (max_junction_gates, max_junction_wires)
	}

	fn junction_count (&self) -> JunctionIndex {
		self.max_junction () + 1
	}

	fn has_fan_in (&self) -> bool {
		let mut junction_has_input = vec! [false; self.junction_count ()];

		for wire in self.wires.iter () {
			if junction_has_input [wire.output] {
				return true;
			}

			junction_has_input [wire.output] = true;
		}

		for gate in self.gates.iter () {
			if junction_has_input [gate.output] {
				return true;
			}

			junction_has_input [gate.output] = true;
		}

		false
	}
}

impl World {
	pub fn new_from_circuit (circuit: Circuit) -> Result <World, WorldCreationErr> {
		if circuit.has_fan_in () {
			return Err (WorldCreationErr::FanIn);
		}

		Ok (World {
			time: 0,
			signals: vec![],
			junctions: vec![false; circuit.junction_count ()],
			circuit: circuit,
		})
	}

	pub fn new (wires: Vec <Wire>, gates: Vec <Gate>) -> Result <World, WorldCreationErr> {
		World::new_from_circuit (Circuit {
			wires: wires,
			gates: gates,
		})
	}

	pub fn new_half_adder () -> World {
		World::new_from_circuit (Circuit::new_half_adder ()).ok ().expect ("Half adder circuit is invalid")
	}

	pub fn new_full_adder () -> World {
		World::new_from_circuit (Circuit::new_full_adder ()).ok ().expect ("Full adder circuit is invalid")
	}

	pub fn is_settled (& self) -> bool {
		self.signals.len () == 0
	}

	fn sort_signals (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.signals.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_signals = Vec::<Signal>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.circuit.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Not => ! inputs [0],
				GateBehavior::Or => inputs.iter ().fold (false, |sum, a| sum || *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
			};

			let destiny_level = self.get_junction_destiny (gate.output);

			if destiny_level != output {
				new_signals.push (Signal {
					junction: gate.output,
					time: self.time,
					level: output,
				});
			}
		};

		// TODO: Proper insertion sorting
		// If the number of new signals is small compared to the number of
		// in-flight signals, I could do a few binary insertions sorts.
		// If the number is large, it might be better to do a mergesort.
		for signal in new_signals {
			self.signals.push (signal);
		}

		self.sort_signals ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> Level {
		if self.signals.len () > 0 {
			// Find the last signal that was heading for that junction
			// Remember that junctions are not allowed to fan in
			for i in 0 .. self.signals.len () {
				let signals = self.signals [self.signals.len () - i - 1];

				if signals.junction == junction {
					return signals.level;
				}
			}
		}

		self.junctions [junction]
	}

	fn step_wires (&mut self) {
		for wire in self.circuit.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny_level = self.get_junction_destiny (wire.output);

			if input != destiny_level {
				self.signals.push (Signal {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});
			}
		};

		// TODO: Proper insertion sorting
		self.sort_signals ();
	}

	fn propagate_signals (&mut self) {
		let next_time = self.signals [0].time;

		for signal in self.signals.iter () {
			if signal.time == next_time {
				self.junctions [signal.junction] = signal.level;
			}
			else if signal.time > next_time {
				break;
			}
		}

		self.signals.retain (|signal| signal.time > next_time);

		self.time = next_time;
	}

	pub fn set_junction (&mut self, junction: JunctionIndex, level: Level) {
		self.signals.push (Signal {
			junction: junction,
			level: level,
			time: self.time,
		});
	}

	pub fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_signals ();

		self.propagate_signals ();

		self.step_gates ();
		self.step_wires ();
	}

	pub fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}

#[test]
pub fn test_fan_in () {
	let world_or_err = World::new (
		Circuit::wires_from_tuples (vec! [
		(0, 2, 1),
		(1, 2, 1),
		]),
		vec! []
	);

	if let Err (WorldCreationErr::FanIn) = world_or_err {
		// Good
	}
	else {
		panic! ("World creation should have thrown a FanIn error");
	}
}

#[test]
pub fn test_half_adder () {
	let mut world = World::new_half_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &World, msb: Level, lsb: Level| {
		assert_eq! (world.junctions [3], msb);
		assert_eq! (world.junctions [7], lsb);
	};

	assert_outputs (&world, false, false);

	// Junctions 0 and 8 are the input bits

	world.set_junction (0, true);
	world.step_to_settled ();
	assert_outputs (&world, false, true);

	world.set_junction (8, true);
	world.step_to_settled ();
	assert_outputs (&world, true, false);

	world.set_junction (0, false);
	world.step_to_settled ();
	assert_outputs (&world, false, true);
}

#[test]
pub fn test_full_adder () {
	let mut world = World::new_full_adder ();
	world.step_to_settled ();

	let assert_outputs = |world: &mut World, a: Level, b: Level, c: Level, carry: Level, sum: Level| {
		world.set_junction (0, a);
		world.set_junction (1, b);
		world.set_junction (2, c);

		world.step_to_settled ();

		assert_eq! (world.junctions [17], carry);
		assert_eq! (world.junctions [16], sum);
	};

	// Truth table for a full adder
	assert_outputs (&mut world, false, false, false, false, false);
	assert_outputs (&mut world, false, false, true, false, true);
	assert_outputs (&mut world, false, true, true, true, false);
	assert_outputs (&mut world, false, true, false, false, true);

	assert_outputs (&mut world, true, true, false, true, false);
	assert_outputs (&mut world, true, true, true, true, true);
	assert_outputs (&mut world, true, false, true, true, false);
	assert_outputs (&mut world, true, false, false, false, true);
}

#[test]
pub fn test_ripple_adder () {
	let adders = vec![Circuit::new_full_adder (); 8];
}<|endoftext|>


<commit_before>use std::process::{Command, Stdio};
use std::collections::HashSet;

struct ProcessSets {
    prev_set: HashSet<u32>,
    curr_set: HashSet<u32>,
}

pub trait ProcessWatcherCallback {
    fn on_open(&self, pid: u32) -> ();
    fn on_close(&self, pid: u32) -> ();
}

fn get_processes(sets: &mut ProcessSets) -> (HashSet<u32>, HashSet<u32>) {

    let child = Command::new("/bin/ps").arg("-e")
        .stdout(Stdio::piped()).spawn().expect("process spawn failed");

    let output = child.wait_with_output().expect("failed to wait on process");
    let vector = output.stdout.as_slice();
    let newline : u8 = 10;
    let iter = vector.split(|num| num == &newline);

    for line in iter {
        let str_line = String::from_utf8_lossy(line);
        let mut fields = str_line.split_whitespace();

        let field = fields.next();
        if field.is_some() {
            let pid: u32 = match field.unwrap().trim().parse() {
                Ok(num) => num,
                Err(_) => continue,
            };

            sets.curr_set.insert(pid);
        }
    }

    let open_set;
    let mut closed_set: HashSet<u32> = HashSet::new();

    //first run, the previous set will be empty
    if sets.prev_set.is_empty() {
        open_set = sets.curr_set.iter().cloned().collect();
    }
    else {
        open_set = sets.curr_set.difference(&sets.prev_set).cloned().collect();
        closed_set = sets.prev_set.difference(&sets.curr_set).cloned().collect();
    }

    sets.prev_set = sets.curr_set.clone();
    sets.curr_set.clear();

    return (open_set, closed_set);
}

pub fn watch_with_callback(callback: &ProcessWatcherCallback) -> () {
    let mut sets = ProcessSets { prev_set: HashSet::new(), curr_set: HashSet::new() };
	let changed_sets = get_processes(&mut sets);

    for open in changed_sets.0.iter() {
        callback.on_open(open.clone());
    }

    for close in changed_sets.1.iter() {
        callback.on_close(close.clone());
    }
}

pub fn watch_with_closure(on_open: &Fn(i32) -> (), on_close: &Fn(i32) -> ()) {
    //Implement me
}<commit_msg>Adding watch_with_closure implementation<commit_after>use std::process::{Command, Stdio};
use std::collections::HashSet;

struct ProcessSets {
    prev_set: HashSet<u32>,
    curr_set: HashSet<u32>,
}

pub trait ProcessWatcherCallback {
    fn on_open(&self, pid: u32) -> ();
    fn on_close(&self, pid: u32) -> ();
}

fn get_processes(sets: &mut ProcessSets) -> (HashSet<u32>, HashSet<u32>) {

    let child = Command::new("/bin/ps").arg("-e")
        .stdout(Stdio::piped()).spawn().expect("process spawn failed");

    let output = child.wait_with_output().expect("failed to wait on process");
    let vector = output.stdout.as_slice();
    let newline : u8 = 10;
    let iter = vector.split(|num| num == &newline);

    for line in iter {
        let str_line = String::from_utf8_lossy(line);
        let mut fields = str_line.split_whitespace();

        let field = fields.next();
        if field.is_some() {
            let pid: u32 = match field.unwrap().trim().parse() {
                Ok(num) => num,
                Err(_) => continue,
            };

            sets.curr_set.insert(pid);
        }
    }

    let open_set;
    let mut closed_set: HashSet<u32> = HashSet::new();

    //first run, the previous set will be empty
    if sets.prev_set.is_empty() {
        open_set = sets.curr_set.iter().cloned().collect();
    }
    else {
        open_set = sets.curr_set.difference(&sets.prev_set).cloned().collect();
        closed_set = sets.prev_set.difference(&sets.curr_set).cloned().collect();
    }

    sets.prev_set = sets.curr_set.clone();
    sets.curr_set.clear();

    return (open_set, closed_set);
}

pub fn watch_with_callback(callback: &ProcessWatcherCallback) -> () {
    let mut sets = ProcessSets { prev_set: HashSet::new(), curr_set: HashSet::new() };
	let changed_sets = get_processes(&mut sets);

    for open in changed_sets.0.iter() {
        callback.on_open(open.clone());
    }

    for close in changed_sets.1.iter() {
        callback.on_close(close.clone());
    }
}

pub fn watch_with_closure(on_open: &Fn(u32) -> (), on_close: &Fn(u32) -> ()) {
    let mut sets = ProcessSets { prev_set: HashSet::new(), curr_set: HashSet::new() };
    let changed_sets = get_processes(&mut sets);

    for open in changed_sets.0.iter() {
        on_open(open.clone());
    }

    for close in changed_sets.1.iter() {
        on_close(close.clone());
    }
}<|endoftext|>