<commit_before>// This file is part of Caribon.
//
// Caribon is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Caribon.  If not, see <http://www.gnu.org/licenses/>.

/*! Repetition detector library

Detects the repetitions in an input file, using a stemming library in order to detect
words that are not technically identical but are quite the same, such as singular and plural (e.g. "cat" and "cats").

Here's a short example (more details below):

```
use caribon::Parser;
let parser = Parser::new("english").unwrap();
let words = parser.tokenize("Some text where you want to detect repetitions").unwrap();
let mut repetitions = parser.detect_local(words, 1.5);
repetitions = parser.detect_global(repetitions, 0.01); // actually doesn't make sens on a string so small
let html = parser.words_to_html(&repetitions, true);
println!("{}", html);
```

Since this stemming is dependent on the language, you must first create a new `Parser` with the
appropriate language. `Parser::new` returns a `caribon::Result<Parser>`, which will contain `Ok(Parser)`
if the language is implemented, `Err(caribon::Error)` else:

```
use caribon::Parser;
let result = Parser::new("foo");
assert!(result.is_err());
```

Once you have a parser, you can then configure it with various options:

```
use caribon::Parser;
let parser = Parser::new("english").unwrap()
                                            .with_html(true)
                                            .with_ignore_proper(true)
                                            .with_max_distance(20)
                                            .with_ignored("some, words, to, ignore");
```

The next step is to read some string and convert it to some inner format (currently `Vec<Word>`
but it is possible that it will change):

```ignore
let words = parser.tokenize(some_string).unwrap();
```

As `new`, this method can fail, so it returns a `Result`.

You then have a choice between multiple repetition detection algorithms. `detect_local` is probably
the one you want to use:

```ignore
let repetitions = parser.detect_local(words, 1.5);
```

There is also `detect_leak`, which is a particular algorithm which probably will be removed at some
point:

```ignore
let repetitions = parser.detect_leak(words, 1.5);
```

The last one is `detect_global`, which detects repetiion in the whole file:

```ignore
let repetitions = parser.detect_global(words, 0.01);
```

Once you have detected those repetitions, the final step is to print them.
`words_to_html` does this. Besides a reference to a <Vec<Word>>, it takes two arguments:
a threshold (basically, the number of repetitions to trigger underlining in HTML), and a
boolean that tests whether the HTML code must be a standalone file or not (you will probably
want to set it to true).

```ignore
let html = parser.words_to_html(&repetitions, true):
```
*/

// Uncomment this if you use nightly and want to run benchmarks
//#![feature(test)]
//mod bench;

extern crate stemmer;
extern crate edit_distance;

mod error;
mod word;
mod parser;

pub use error::Error;
pub use error::Result;
pub use word::Word;
pub use word::Ast;
pub use parser::Parser;
<commit_msg>doc examples now pass the test<commit_after>// This file is part of Caribon.
//
// Caribon is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Caribon.  If not, see <http://www.gnu.org/licenses/>.

/*! Repetition detector library

Detects the repetitions in an input file, using a stemming library in order to detect
words that are not technically identical but are quite the same, such as singular and plural (e.g. "cat" and "cats").

Here's a short example (more details below):

```
use caribon::Parser;
let parser = Parser::new("english").unwrap();
let mut ast = parser.tokenize("Some text where you want to detect repetitions").unwrap();
parser.detect_local(&mut ast, 1.5);
parser.detect_global(&mut ast, 0.01); // actually doesn't make sens on a string so small
let html = parser.ast_to_html(&mut ast, true);
println!("{}", html);
```

Since this stemming is dependent on the language, you must first create a new `Parser` with the
appropriate language. `Parser::new` returns a `caribon::Result<Parser>`, which will contain `Ok(Parser)`
if the language is implemented, `Err(caribon::Error)` else:

```
use caribon::Parser;
let result = Parser::new("foo");
assert!(result.is_err());
```

Once you have a parser, you can then configure it with various options:

```
use caribon::Parser;
let parser = Parser::new("english").unwrap()
                                            .with_html(true)
                                            .with_ignore_proper(true)
                                            .with_max_distance(20)
                                            .with_ignored("some, words, to, ignore");
```

The next step is to read some string and convert it to some inner format (see the `Ast` structure).

```ignore
let mut ast = parser.tokenize(some_string).unwrap();
```

As `new`, this method can fail, so it returns a `Result`.

You then have a choice between multiple repetition detection algorithms. `detect_local` is probably
the one you want to use:

```ignore
parser.detect_local(&mut ast, 1.5);
```

There is also `detect_global`, which detects repetiion in the whole file:

```ignore
parser.detect_global(&mut ast, 0.01);
```

Once you have detected those repetitions, the final step is to print them.
`ast_to_html` does this. Besides a reference to an `Ast`, it takes one argument: a
boolean that tests whether the HTML code must be a standalone file or not (you will probably
want to set it to true).

```ignore
let html = parser.ast_to_html(&mut ast, true):
```
*/

// Uncomment this if you use nightly and want to run benchmarks
//#![feature(test)]
//mod bench;

extern crate stemmer;
extern crate edit_distance;

mod error;
mod word;
mod parser;

pub use error::Error;
pub use error::Result;
pub use word::Word;
pub use word::Ast;
pub use parser::Parser;
<|endoftext|>


<commit_before>//! Async WebSocket usage.
//!
//! This library is an implementation of WebSocket handshakes and streams. It
//! is based on the crate which implements all required WebSocket protocol
//! logic. So this crate basically just brings tokio support / tokio integration
//! to it.
//!
//! Each WebSocket stream implements the required `Stream` and `Sink` traits,
//! so the socket is just a stream of messages coming in and going out.

#![deny(missing_docs, unused_must_use, unused_mut, unused_imports, unused_import_braces)]

pub use tungstenite;

mod compat;
#[cfg(feature = "connect")]
mod connect;
mod handshake;
#[cfg(feature = "stream")]
mod stream;
#[cfg(any(feature = "native-tls", feature = "__rustls-tls", feature = "connect"))]
mod tls;

use std::io::{Read, Write};

use compat::{cvt, AllowStd, ContextWaker};
use futures_util::{
    sink::{Sink, SinkExt},
    stream::Stream,
};
use log::*;
use std::{
    pin::Pin,
    task::{Context, Poll},
};
use tokio::io::{AsyncRead, AsyncWrite};

use tungstenite::{
    client::IntoClientRequest,
    error::Error as WsError,
    handshake::{
        client::{ClientHandshake, Response},
        server::{Callback, NoCallback},
        HandshakeError,
    },
    protocol::{Message, Role, WebSocket, WebSocketConfig},
};

#[cfg(any(feature = "native-tls", feature = "__rustls-tls", feature = "connect"))]
pub use tls::Connector;
#[cfg(any(feature = "native-tls", feature = "__rustls-tls"))]
pub use tls::{client_async_tls, client_async_tls_with_config};

#[cfg(feature = "connect")]
pub use connect::{connect_async, connect_async_with_config};

#[cfg(all(any(feature = "native-tls", feature = "__rustls-tls"), feature = "connect"))]
pub use connect::connect_async_tls_with_config;

#[cfg(feature = "stream")]
pub use stream::MaybeTlsStream;

use tungstenite::protocol::CloseFrame;

/// Creates a WebSocket handshake from a request and a stream.
/// For convenience, the user may call this with a url string, a URL,
/// or a `Request`. Calling with `Request` allows the user to add
/// a WebSocket protocol or other custom headers.
///
/// Internally, this custom creates a handshake representation and returns
/// a future representing the resolution of the WebSocket handshake. The
/// returned future will resolve to either `WebSocketStream<S>` or `Error`
/// depending on whether the handshake is successful.
///
/// This is typically used for clients who have already established, for
/// example, a TCP connection to the remote server.
pub async fn client_async<'a, R, S>(
    request: R,
    stream: S,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    client_async_with_config(request, stream, None).await
}

/// The same as `client_async()` but the one can specify a websocket configuration.
/// Please refer to `client_async()` for more details.
pub async fn client_async_with_config<'a, R, S>(
    request: R,
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    let f = handshake::client_handshake(stream, move |allow_std| {
        let request = request.into_client_request()?;
        let cli_handshake = ClientHandshake::start(allow_std, request, config)?;
        cli_handshake.handshake()
    });
    f.await.map_err(|e| match e {
        HandshakeError::Failure(e) => e,
        e => WsError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
    })
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function will internally call `server::accept` to create a
/// handshake representation and returns a future representing the
/// resolution of the WebSocket handshake. The returned future will resolve
/// to either `WebSocketStream<S>` or `Error` depending if it's successful
/// or not.
///
/// This is typically used after a socket has been accepted from a
/// `TcpListener`. That socket is then passed to this function to perform
/// the server half of the accepting a client's websocket connection.
pub async fn accept_async<S>(stream: S) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async(stream, NoCallback).await
}

/// The same as `accept_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_async()` for more details.
pub async fn accept_async_with_config<S>(
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async_with_config(stream, NoCallback, config).await
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function does the same as `accept_async()` but accepts an extra callback
/// for header processing. The callback receives headers of the incoming
/// requests and is able to add extra headers to the reply.
pub async fn accept_hdr_async<S, C>(stream: S, callback: C) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    accept_hdr_async_with_config(stream, callback, None).await
}

/// The same as `accept_hdr_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_hdr_async()` for more details.
pub async fn accept_hdr_async_with_config<S, C>(
    stream: S,
    callback: C,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    let f = handshake::server_handshake(stream, move |allow_std| {
        tungstenite::accept_hdr_with_config(allow_std, callback, config)
    });
    f.await.map_err(|e| match e {
        HandshakeError::Failure(e) => e,
        e => WsError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
    })
}

/// A wrapper around an underlying raw stream which implements the WebSocket
/// protocol.
///
/// A `WebSocketStream<S>` represents a handshake that has been completed
/// successfully and both the server and the client are ready for receiving
/// and sending data. Message from a `WebSocketStream<S>` are accessible
/// through the respective `Stream` and `Sink`. Check more information about
/// them in `futures-rs` crate documentation or have a look on the examples
/// and unit tests for this crate.
#[derive(Debug)]
pub struct WebSocketStream<S> {
    inner: WebSocket<AllowStd<S>>,
    closing: bool,
}

impl<S> WebSocketStream<S> {
    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_raw_socket(stream: S, role: Role, config: Option<WebSocketConfig>) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_raw_socket(allow_std, role, config)
        })
        .await
    }

    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_partially_read(
        stream: S,
        part: Vec<u8>,
        role: Role,
        config: Option<WebSocketConfig>,
    ) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_partially_read(allow_std, part, role, config)
        })
        .await
    }

    pub(crate) fn new(ws: WebSocket<AllowStd<S>>) -> Self {
        WebSocketStream { inner: ws, closing: false }
    }

    fn with_context<F, R>(&mut self, ctx: Option<(ContextWaker, &mut Context<'_>)>, f: F) -> R
    where
        S: Unpin,
        F: FnOnce(&mut WebSocket<AllowStd<S>>) -> R,
        AllowStd<S>: Read + Write,
    {
        trace!("{}:{} WebSocketStream.with_context", file!(), line!());
        if let Some((kind, ctx)) = ctx {
            self.inner.get_mut().set_waker(kind, ctx.waker());
        }
        f(&mut self.inner)
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        self.inner.get_ref().get_ref()
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        self.inner.get_mut().get_mut()
    }

    /// Returns a reference to the configuration of the tungstenite stream.
    pub fn get_config(&self) -> &WebSocketConfig {
        self.inner.get_config()
    }

    /// Close the underlying web socket
    pub async fn close(&mut self, msg: Option<CloseFrame<'_>>) -> Result<(), WsError>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        let msg = msg.map(|msg| msg.into_owned());
        self.send(Message::Close(msg)).await
    }
}

impl<T> Stream for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Item = Result<Message, WsError>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("{}:{} Stream.poll_next", file!(), line!());
        match futures_util::ready!(self.with_context(Some((ContextWaker::Read, cx)), |s| {
            trace!("{}:{} Stream.with_context poll_next -> read_message()", file!(), line!());
            cvt(s.read_message())
        })) {
            Ok(v) => Poll::Ready(Some(Ok(v))),
            Err(WsError::AlreadyClosed) | Err(WsError::ConnectionClosed) => Poll::Ready(None),
            Err(e) => Poll::Ready(Some(Err(e))),
        }
    }
}

impl<T> Sink<Message> for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Error = WsError;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        match (*self).with_context(None, |s| s.write_message(item)) {
            Ok(()) => Ok(()),
            Err(::tungstenite::Error::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => {
                // the message was accepted and queued
                // isn't an error.
                Ok(())
            }
            Err(e) => {
                debug!("websocket start_send error: {}", e);
                Err(e)
            }
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        let res = if self.closing {
            // After queueing it, we call `write_pending` to drive the close handshake to completion.
            (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.write_pending())
        } else {
            (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.close(None))
        };

        match res {
            Ok(()) => Poll::Ready(Ok(())),
            Err(::tungstenite::Error::ConnectionClosed) => Poll::Ready(Ok(())),
            Err(::tungstenite::Error::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => {
                trace!("WouldBlock");
                self.closing = true;
                Poll::Pending
            }
            Err(err) => {
                debug!("websocket close error: {}", err);
                Poll::Ready(Err(err))
            }
        }
    }
}

/// Get a domain from an URL.
#[cfg(any(feature = "connect", feature = "native-tls", feature = "__rustls-tls"))]
#[inline]
fn domain(request: &tungstenite::handshake::client::Request) -> Result<String, WsError> {
    match request.uri().host() {
        Some(d) => Ok(d.to_string()),
        None => Err(WsError::Url(tungstenite::error::UrlError::NoHostName)),
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "connect")]
    use crate::stream::MaybeTlsStream;
    use crate::{compat::AllowStd, WebSocketStream};
    use std::io::{Read, Write};
    #[cfg(feature = "connect")]
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    fn is_read<T: Read>() {}
    fn is_write<T: Write>() {}
    #[cfg(feature = "connect")]
    fn is_async_read<T: AsyncReadExt>() {}
    #[cfg(feature = "connect")]
    fn is_async_write<T: AsyncWriteExt>() {}
    fn is_unpin<T: Unpin>() {}

    #[test]
    fn web_socket_stream_has_traits() {
        is_read::<AllowStd<tokio::net::TcpStream>>();
        is_write::<AllowStd<tokio::net::TcpStream>>();

        #[cfg(feature = "connect")]
        is_async_read::<MaybeTlsStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_async_write::<MaybeTlsStream<tokio::net::TcpStream>>();

        is_unpin::<WebSocketStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_unpin::<WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>>();
    }
}
<commit_msg>Make the semantics of `Stream` more reasonable<commit_after>//! Async WebSocket usage.
//!
//! This library is an implementation of WebSocket handshakes and streams. It
//! is based on the crate which implements all required WebSocket protocol
//! logic. So this crate basically just brings tokio support / tokio integration
//! to it.
//!
//! Each WebSocket stream implements the required `Stream` and `Sink` traits,
//! so the socket is just a stream of messages coming in and going out.

#![deny(missing_docs, unused_must_use, unused_mut, unused_imports, unused_import_braces)]

pub use tungstenite;

mod compat;
#[cfg(feature = "connect")]
mod connect;
mod handshake;
#[cfg(feature = "stream")]
mod stream;
#[cfg(any(feature = "native-tls", feature = "__rustls-tls", feature = "connect"))]
mod tls;

use std::io::{Read, Write};

use compat::{cvt, AllowStd, ContextWaker};
use futures_util::{
    sink::{Sink, SinkExt},
    stream::Stream,
};
use log::*;
use std::{
    pin::Pin,
    task::{Context, Poll},
};
use tokio::io::{AsyncRead, AsyncWrite};

use tungstenite::{
    client::IntoClientRequest,
    error::Error as WsError,
    handshake::{
        client::{ClientHandshake, Response},
        server::{Callback, NoCallback},
        HandshakeError,
    },
    protocol::{Message, Role, WebSocket, WebSocketConfig},
};

#[cfg(any(feature = "native-tls", feature = "__rustls-tls", feature = "connect"))]
pub use tls::Connector;
#[cfg(any(feature = "native-tls", feature = "__rustls-tls"))]
pub use tls::{client_async_tls, client_async_tls_with_config};

#[cfg(feature = "connect")]
pub use connect::{connect_async, connect_async_with_config};

#[cfg(all(any(feature = "native-tls", feature = "__rustls-tls"), feature = "connect"))]
pub use connect::connect_async_tls_with_config;

#[cfg(feature = "stream")]
pub use stream::MaybeTlsStream;

use tungstenite::protocol::CloseFrame;

/// Creates a WebSocket handshake from a request and a stream.
/// For convenience, the user may call this with a url string, a URL,
/// or a `Request`. Calling with `Request` allows the user to add
/// a WebSocket protocol or other custom headers.
///
/// Internally, this custom creates a handshake representation and returns
/// a future representing the resolution of the WebSocket handshake. The
/// returned future will resolve to either `WebSocketStream<S>` or `Error`
/// depending on whether the handshake is successful.
///
/// This is typically used for clients who have already established, for
/// example, a TCP connection to the remote server.
pub async fn client_async<'a, R, S>(
    request: R,
    stream: S,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    client_async_with_config(request, stream, None).await
}

/// The same as `client_async()` but the one can specify a websocket configuration.
/// Please refer to `client_async()` for more details.
pub async fn client_async_with_config<'a, R, S>(
    request: R,
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<(WebSocketStream<S>, Response), WsError>
where
    R: IntoClientRequest + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    let f = handshake::client_handshake(stream, move |allow_std| {
        let request = request.into_client_request()?;
        let cli_handshake = ClientHandshake::start(allow_std, request, config)?;
        cli_handshake.handshake()
    });
    f.await.map_err(|e| match e {
        HandshakeError::Failure(e) => e,
        e => WsError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
    })
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function will internally call `server::accept` to create a
/// handshake representation and returns a future representing the
/// resolution of the WebSocket handshake. The returned future will resolve
/// to either `WebSocketStream<S>` or `Error` depending if it's successful
/// or not.
///
/// This is typically used after a socket has been accepted from a
/// `TcpListener`. That socket is then passed to this function to perform
/// the server half of the accepting a client's websocket connection.
pub async fn accept_async<S>(stream: S) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async(stream, NoCallback).await
}

/// The same as `accept_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_async()` for more details.
pub async fn accept_async_with_config<S>(
    stream: S,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    accept_hdr_async_with_config(stream, NoCallback, config).await
}

/// Accepts a new WebSocket connection with the provided stream.
///
/// This function does the same as `accept_async()` but accepts an extra callback
/// for header processing. The callback receives headers of the incoming
/// requests and is able to add extra headers to the reply.
pub async fn accept_hdr_async<S, C>(stream: S, callback: C) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    accept_hdr_async_with_config(stream, callback, None).await
}

/// The same as `accept_hdr_async()` but the one can specify a websocket configuration.
/// Please refer to `accept_hdr_async()` for more details.
pub async fn accept_hdr_async_with_config<S, C>(
    stream: S,
    callback: C,
    config: Option<WebSocketConfig>,
) -> Result<WebSocketStream<S>, WsError>
where
    S: AsyncRead + AsyncWrite + Unpin,
    C: Callback + Unpin,
{
    let f = handshake::server_handshake(stream, move |allow_std| {
        tungstenite::accept_hdr_with_config(allow_std, callback, config)
    });
    f.await.map_err(|e| match e {
        HandshakeError::Failure(e) => e,
        e => WsError::Io(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),
    })
}

/// A wrapper around an underlying raw stream which implements the WebSocket
/// protocol.
///
/// A `WebSocketStream<S>` represents a handshake that has been completed
/// successfully and both the server and the client are ready for receiving
/// and sending data. Message from a `WebSocketStream<S>` are accessible
/// through the respective `Stream` and `Sink`. Check more information about
/// them in `futures-rs` crate documentation or have a look on the examples
/// and unit tests for this crate.
#[derive(Debug)]
pub struct WebSocketStream<S> {
    inner: WebSocket<AllowStd<S>>,
    closing: bool,
    ended: bool,
}

impl<S> WebSocketStream<S> {
    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_raw_socket(stream: S, role: Role, config: Option<WebSocketConfig>) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_raw_socket(allow_std, role, config)
        })
        .await
    }

    /// Convert a raw socket into a WebSocketStream without performing a
    /// handshake.
    pub async fn from_partially_read(
        stream: S,
        part: Vec<u8>,
        role: Role,
        config: Option<WebSocketConfig>,
    ) -> Self
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake::without_handshake(stream, move |allow_std| {
            WebSocket::from_partially_read(allow_std, part, role, config)
        })
        .await
    }

    pub(crate) fn new(ws: WebSocket<AllowStd<S>>) -> Self {
        WebSocketStream { inner: ws, closing: false, ended: false }
    }

    fn with_context<F, R>(&mut self, ctx: Option<(ContextWaker, &mut Context<'_>)>, f: F) -> R
    where
        S: Unpin,
        F: FnOnce(&mut WebSocket<AllowStd<S>>) -> R,
        AllowStd<S>: Read + Write,
    {
        trace!("{}:{} WebSocketStream.with_context", file!(), line!());
        if let Some((kind, ctx)) = ctx {
            self.inner.get_mut().set_waker(kind, ctx.waker());
        }
        f(&mut self.inner)
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        self.inner.get_ref().get_ref()
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        self.inner.get_mut().get_mut()
    }

    /// Returns a reference to the configuration of the tungstenite stream.
    pub fn get_config(&self) -> &WebSocketConfig {
        self.inner.get_config()
    }

    /// Close the underlying web socket
    pub async fn close(&mut self, msg: Option<CloseFrame<'_>>) -> Result<(), WsError>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        let msg = msg.map(|msg| msg.into_owned());
        self.send(Message::Close(msg)).await
    }
}

impl<T> Stream for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Item = Result<Message, WsError>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("{}:{} Stream.poll_next", file!(), line!());

        // The connection has been closed or a critical error has occurred.
        // We have already returned the error to the user, the `Stream` is unusable,
        // so we assume that the stream has been "fused".
        if self.ended {
            return Poll::Ready(None);
        }

        match futures_util::ready!(self.with_context(Some((ContextWaker::Read, cx)), |s| {
            trace!("{}:{} Stream.with_context poll_next -> read_message()", file!(), line!());
            cvt(s.read_message())
        })) {
            Ok(v) => Poll::Ready(Some(Ok(v))),
            Err(e) => {
                self.ended = true;
                if matches!(e, WsError::AlreadyClosed | WsError::ConnectionClosed) {
                    Poll::Ready(None)
                } else {
                    Poll::Ready(Some(Err(e)))
                }
            }
        }
    }
}

impl<T> Sink<Message> for WebSocketStream<T>
where
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Error = WsError;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        match (*self).with_context(None, |s| s.write_message(item)) {
            Ok(()) => Ok(()),
            Err(::tungstenite::Error::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => {
                // the message was accepted and queued
                // isn't an error.
                Ok(())
            }
            Err(e) => {
                debug!("websocket start_send error: {}", e);
                Err(e)
            }
        }
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        (*self).with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.write_pending()))
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        let res = if self.closing {
            // After queueing it, we call `write_pending` to drive the close handshake to completion.
            (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.write_pending())
        } else {
            (*self).with_context(Some((ContextWaker::Write, cx)), |s| s.close(None))
        };

        match res {
            Ok(()) => Poll::Ready(Ok(())),
            Err(::tungstenite::Error::ConnectionClosed) => Poll::Ready(Ok(())),
            Err(::tungstenite::Error::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => {
                trace!("WouldBlock");
                self.closing = true;
                Poll::Pending
            }
            Err(err) => {
                debug!("websocket close error: {}", err);
                Poll::Ready(Err(err))
            }
        }
    }
}

/// Get a domain from an URL.
#[cfg(any(feature = "connect", feature = "native-tls", feature = "__rustls-tls"))]
#[inline]
fn domain(request: &tungstenite::handshake::client::Request) -> Result<String, WsError> {
    match request.uri().host() {
        Some(d) => Ok(d.to_string()),
        None => Err(WsError::Url(tungstenite::error::UrlError::NoHostName)),
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "connect")]
    use crate::stream::MaybeTlsStream;
    use crate::{compat::AllowStd, WebSocketStream};
    use std::io::{Read, Write};
    #[cfg(feature = "connect")]
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    fn is_read<T: Read>() {}
    fn is_write<T: Write>() {}
    #[cfg(feature = "connect")]
    fn is_async_read<T: AsyncReadExt>() {}
    #[cfg(feature = "connect")]
    fn is_async_write<T: AsyncWriteExt>() {}
    fn is_unpin<T: Unpin>() {}

    #[test]
    fn web_socket_stream_has_traits() {
        is_read::<AllowStd<tokio::net::TcpStream>>();
        is_write::<AllowStd<tokio::net::TcpStream>>();

        #[cfg(feature = "connect")]
        is_async_read::<MaybeTlsStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_async_write::<MaybeTlsStream<tokio::net::TcpStream>>();

        is_unpin::<WebSocketStream<tokio::net::TcpStream>>();
        #[cfg(feature = "connect")]
        is_unpin::<WebSocketStream<MaybeTlsStream<tokio::net::TcpStream>>>();
    }
}
<|endoftext|>


<commit_before>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! Best paired with other libraries in the family:
//!
//! * [console](https://docs.rs/console)
//! * [dialoguer](https://docs.rs/dialoguer)
//!
//! # Crate Contents
//!
//! * **Progress bars**
//!   * [`ProgressBar`](struct.ProgressBar.html) for bars and spinners
//!   * [`MultiProgress`](struct.MultiProgress.html) for multiple bars
//! * **Data Formatting**
//!   * [`HumanBytes`](struct.HumanBytes.html) for formatting bytes
//!   * [`HumanDuration`](struct.HumanDuration.html) for formatting durations
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that support both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: for instance from
//! multiple threads).
//!
//! To wet your appetite, this is what this can look like:
//!
//!
//!
//! Progress bars are manually advanced and by default draw to stdout.
//! When you are done the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc(1);
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! General progress bar behaviors:
//!
//! * if a non terminal is detected the progress bar will be completely
//!   hidden.  This makes piping programs to logfiles make sense out of
//!   the box.
//! * progress bars should be explicitly finished to reset the rendering
//!   for others.  Either by also clearing them or by replacing them with
//!   a new message / retaining the current message.
//! * the default template renders neither message nor prefix.
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```text
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! Example configuration:
//!
//! ```ignore
//! bar.set_style(ProgressStyle::default_bar()
//!     .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
//!     .progress_chars("##-"));
//! ```
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `prefix`: renders the prefix set on the progress bar.
//! * `msg`: renders the currently set message on the progress bar.
//! * `wide_msg`: like `msg` but always fills the remaining space and truncates.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapsed`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
extern crate parking_lot;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate console;

mod progress;
mod utils;
mod format;

pub use progress::{ProgressBar, MultiProgress, ProgressBarIter,
                   ProgressDrawTarget, ProgressStyle};
pub use format::{HumanDuration, FormattedDuration, HumanBytes};
<commit_msg>Fix typos.<commit_after>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! Best paired with other libraries in the family:
//!
//! * [console](https://docs.rs/console)
//! * [dialoguer](https://docs.rs/dialoguer)
//!
//! # Crate Contents
//!
//! * **Progress bars**
//!   * [`ProgressBar`](struct.ProgressBar.html) for bars and spinners
//!   * [`MultiProgress`](struct.MultiProgress.html) for multiple bars
//! * **Data Formatting**
//!   * [`HumanBytes`](struct.HumanBytes.html) for formatting bytes
//!   * [`HumanDuration`](struct.HumanDuration.html) for formatting durations
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that supports both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: from multiple threads).
//!
//! To whet your appetite, this is what this can look like:
//!
//!
//!
//! Progress bars are manually advanced and by default draw to stdout.
//! When you are done, the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc(1);
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! General progress bar behaviors:
//!
//! * if a non terminal is detected the progress bar will be completely
//!   hidden.  This makes piping programs to logfiles make sense out of
//!   the box.
//! * progress bars should be explicitly finished to reset the rendering
//!   for others.  Either by also clearing them or by replacing them with
//!   a new message / retaining the current message.
//! * the default template renders neither message nor prefix.
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```text
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! Example configuration:
//!
//! ```ignore
//! bar.set_style(ProgressStyle::default_bar()
//!     .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
//!     .progress_chars("##-"));
//! ```
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `prefix`: renders the prefix set on the progress bar.
//! * `msg`: renders the currently set message on the progress bar.
//! * `wide_msg`: like `msg` but always fills the remaining space and truncates.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapsed`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
extern crate parking_lot;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate console;

mod progress;
mod utils;
mod format;

pub use progress::{ProgressBar, MultiProgress, ProgressBarIter,
                   ProgressDrawTarget, ProgressStyle};
pub use format::{HumanDuration, FormattedDuration, HumanBytes};
<|endoftext|>


<commit_before>#![crate_name = "libvorbisfile"]
#![doc(html_root_url = "http://www.rust-ci.org/tari/vorbisfile.rs/doc/libvorbisfile/")]

#![deny(dead_code, missing_doc)]
#![feature(unsafe_destructor)]

//! Ogg Vorbis file decoding, library bindings.

extern crate libc;
use libc::{c_void, c_int, c_long, size_t};

use std::c_str::CString;
use std::mem;
use std::str;
use std::ptr;
use std::raw;
use std::slice::raw::mut_buf_as_slice;

#[allow(dead_code, non_snake_case)]
mod ffi;

pub type OVResult<T> = Result<T, OVError>;

/// Decode error.
#[deriving(Show, Clone)]
pub enum OVError {
    /// Reached end of file.
    EndOfStream,
    /// Encounted missing or corrupt data.
    ///
    /// Recovery from this error is usually automatic and is returned for
    /// informational purposes only.
    StreamInterrupted,
    /// I/O error while reading compressed data to decode.
    ReadError,
    /// Internal inconsistency in encode or decode state. Recovery impossible.
    InternalFault,
    /// Feature not implemented.
    NotImplemented,
    /// User passed an invalid argument to a function.
    InvalidArgument,
    /// Provided data is not recognized as Ogg Vorbis.
    NotVorbis,
    /// Provided data appears to be Ogg Vorbis but has a corrupt or
    /// indecipherable header.
    InvalidHeader,
    /// Bitstream format revision is not supported.
    UnsupportedVersion,
    /// The specified Vorbis link exists but is corrupt.
    CorruptLink,
    /// The stream is not seekable.
    NotSeekable,
}

impl OVError {
    fn from_native(code: c_int) -> OVError {
        match code {
            ffi::OV_HOLE => StreamInterrupted,
            ffi::OV_EREAD => ReadError,
            ffi::OV_EFAULT => InternalFault,
            ffi::OV_EIMPL => NotImplemented,
            ffi::OV_EINVAL => InvalidArgument,
            ffi::OV_ENOTVORBIS => NotVorbis,
            ffi::OV_EBADHEADER => InvalidHeader,
            ffi::OV_EVERSION => UnsupportedVersion,
            ffi::OV_EBADLINK => CorruptLink,
            ffi::OV_ENOSEEK => NotSeekable,
            x => fail!("Unexpected OVError code: {}", x)
        }
    }
}

/// Ogg Vorbis file decoder.
pub struct VorbisFile<R> {
    src: R,
    decoder: ffi::OggVorbis_File,
    // Totally not 'static, but need a lifetime specifier to get a slice.
    channels: Vec<raw::Slice<f32>>,
}

/// File metadata
pub struct Comments<'a> {
    /// The Vorbis implementation that encoded the stream.
    pub vendor: CString,
    /// User-specified key-value pairs of the form KEY=VALUE.
    pub comments: Vec<&'a str>
}

#[allow(unused_variable)]
extern "C" fn seek(datasource: *mut c_void, offset: i64, whence: c_int) -> c_int {
    // TODO permit seeking
    -1
}
#[allow(unused_variable)]
extern "C" fn close(datasource: *mut c_void) -> c_int {
    // No need to do anything. VorbisFile owns the Reader we're using.
    0
}
#[allow(unused_variable)]
extern "C" fn tell(datasource: *mut c_void) -> c_long {
    // TODO permit seeking
    -1
}

// Don't expose ov_fopen and friends because that won't play nicely
// with non-libnative runtime.
impl<R: Reader> VorbisFile<R> {
    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `datasource` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn callback_setup(&mut self) {
        let ds = self as *mut _ as *mut c_void;
        self.decoder.datasource = ds;
    }

    /// Create a Ogg Vorbis decoder.
    pub fn new(src: R) -> OVResult<VorbisFile<R>> {
        let mut vf = VorbisFile {
            src: src,
            decoder: unsafe { mem::uninitialized() },
            channels: Vec::new()
        };
        let callbacks = ffi::ov_callbacks {
            read: VorbisFile::<R>::read,
            seek: seek,
            tell: tell,
            close: close,
        };

        let status = unsafe {
            ffi::ov_open_callbacks(&mut vf.src as *mut _ as *mut c_void,
                                   &mut vf.decoder as *mut _,
                                   ptr::null_mut(), 0, callbacks)
        };

        match status {
            0 => Ok(vf),
            f => {
                // Must not run the destructor. decoder is still uninitialized.
                unsafe {
                    mem::forget(vf.decoder);
                }
                Err(OVError::from_native(f))
            }
        }
    }

    /// Gets the comment struct for the specified bitstream.
    ///
    /// For nonseekable streams, returns the comments for the current
    /// bitstream. Otherwise, specify bitstream -1 to get the current
    /// bitstream.
    pub fn comment<'a>(&'a mut self, link: int) -> Option<Comments<'a>> {
        let cm = unsafe {
            let p = ffi::ov_comment(&mut self.decoder, link as c_int);
            if p.is_null() {
                return None;
            } else {
                *p
            }
        };

        unsafe fn make_str<'a>(data: *const u8, len: uint) -> Option<&'a str> {
            let slice = raw::Slice {
                data: data,
                len: len
            };
            str::from_utf8(mem::transmute(slice))
        }

        Some(Comments {
            vendor: unsafe {
                CString::new(cm.vendor as *const _, false)
            },
            comments: unsafe {
                let mut v = Vec::with_capacity(cm.comments as uint);
                for i in range(0, cm.comments) {
                    let len = *cm.comment_lengths.offset(i as int);
                    match make_str(*cm.user_comments.offset(i as int) as *const _,
                                   len as uint) {
                        Some(s) => {
                            v.push(s);
                        }
                        None => {
                            // Ignore. Vorbis specifies all comment data is valid
                            // UTF-8, but we need to protect against invalid input
                        }
                    }
                }
                v
            }
        })
    }

    /// Decode a block of samples.
    ///
    /// The emitted values are a slice of channels, each containing an equal
    /// number of samples.
    pub fn decode<'a>(&'a mut self) -> OVResult<&'a mut [&'a mut [f32]]> {
        let max_samples = 4096;
        self.callback_setup();
        let mut sample_buffer: *mut *mut f32 = unsafe {
            mem::uninitialized()
        };
        let mut bitstream_idx: c_int = unsafe {
            mem::uninitialized()
        };

        let n_samples = unsafe {
            match ffi::ov_read_float(&mut self.decoder, &mut sample_buffer,
                                     max_samples, &mut bitstream_idx) {
                0 => {
                    return Err(EndOfStream);
                }
                x if x < 0 => {
                    return Err(OVError::from_native(x as c_int));
                }
                x => x
            }
        };
        let n_channels = unsafe {
            (*ffi::ov_info(&mut self.decoder, bitstream_idx)).channels
        };

        self.channels.truncate(0);
        for i in range(0, n_channels) {
            unsafe {
                let channel_buffer = *sample_buffer.offset(i as int);
                let channel_slice = raw::Slice::<f32> {
                    data: channel_buffer as *const f32,
                    len: n_samples as uint
                };
                self.channels.push(channel_slice);
            };
        }
        Ok(unsafe {
            mem::transmute(self.channels.as_slice())
        })
    }

    /// Read `nmemb` items into `ptr` of `size` bytes each.
    ///
    /// If 0 is returned, error status is implied by errno. If nonzero, there was
    /// a read error. Otherwise, reached EOF.
    extern "C" fn read(buffer: *mut c_void, size: size_t, nmemb: size_t,
                       datasource: *mut c_void) -> size_t {
        let vf: &mut VorbisFile<R> = unsafe { mem::transmute(datasource) };
        let ptr = buffer as *mut u8;

        for i in range(0, nmemb) {
            let more = unsafe {
                mut_buf_as_slice(ptr.offset(i as int), size as uint, |buf| {
                    match vf.src.read_at_least(size as uint, buf) {
                        Ok(_) => true,
                        // Assume errno is set under the covers.
                        Err(_) => false
                    }
                })
            };
            if !more {
                // Got error, which might be EOF.
                return i;
            }
        }
        // Completed successfully
        return nmemb;
    }
}

#[unsafe_destructor]
impl<R: Reader> Drop for VorbisFile<R> {
    fn drop(&mut self) {
        self.callback_setup();
        unsafe {
            ffi::ov_clear(&mut self.decoder);
        }
    }
}
<commit_msg>fail! -> panic!<commit_after>#![crate_name = "libvorbisfile"]
#![doc(html_root_url = "http://www.rust-ci.org/tari/vorbisfile.rs/doc/libvorbisfile/")]

#![deny(dead_code, missing_doc)]
#![feature(unsafe_destructor)]

//! Ogg Vorbis file decoding, library bindings.

extern crate libc;
use libc::{c_void, c_int, c_long, size_t};

use std::c_str::CString;
use std::mem;
use std::str;
use std::ptr;
use std::raw;
use std::slice::raw::mut_buf_as_slice;

#[allow(dead_code, non_snake_case)]
mod ffi;

pub type OVResult<T> = Result<T, OVError>;

/// Decode error.
#[deriving(Show, Clone)]
pub enum OVError {
    /// Reached end of file.
    EndOfStream,
    /// Encounted missing or corrupt data.
    ///
    /// Recovery from this error is usually automatic and is returned for
    /// informational purposes only.
    StreamInterrupted,
    /// I/O error while reading compressed data to decode.
    ReadError,
    /// Internal inconsistency in encode or decode state. Recovery impossible.
    InternalFault,
    /// Feature not implemented.
    NotImplemented,
    /// User passed an invalid argument to a function.
    InvalidArgument,
    /// Provided data is not recognized as Ogg Vorbis.
    NotVorbis,
    /// Provided data appears to be Ogg Vorbis but has a corrupt or
    /// indecipherable header.
    InvalidHeader,
    /// Bitstream format revision is not supported.
    UnsupportedVersion,
    /// The specified Vorbis link exists but is corrupt.
    CorruptLink,
    /// The stream is not seekable.
    NotSeekable,
}

impl OVError {
    fn from_native(code: c_int) -> OVError {
        match code {
            ffi::OV_HOLE => StreamInterrupted,
            ffi::OV_EREAD => ReadError,
            ffi::OV_EFAULT => InternalFault,
            ffi::OV_EIMPL => NotImplemented,
            ffi::OV_EINVAL => InvalidArgument,
            ffi::OV_ENOTVORBIS => NotVorbis,
            ffi::OV_EBADHEADER => InvalidHeader,
            ffi::OV_EVERSION => UnsupportedVersion,
            ffi::OV_EBADLINK => CorruptLink,
            ffi::OV_ENOSEEK => NotSeekable,
            x => panic!("Unexpected OVError code: {}", x)
        }
    }
}

/// Ogg Vorbis file decoder.
pub struct VorbisFile<R> {
    src: R,
    decoder: ffi::OggVorbis_File,
    // Totally not 'static, but need a lifetime specifier to get a slice.
    channels: Vec<raw::Slice<f32>>,
}

/// File metadata
pub struct Comments<'a> {
    /// The Vorbis implementation that encoded the stream.
    pub vendor: CString,
    /// User-specified key-value pairs of the form KEY=VALUE.
    pub comments: Vec<&'a str>
}

#[allow(unused_variable)]
extern "C" fn seek(datasource: *mut c_void, offset: i64, whence: c_int) -> c_int {
    // TODO permit seeking
    -1
}
#[allow(unused_variable)]
extern "C" fn close(datasource: *mut c_void) -> c_int {
    // No need to do anything. VorbisFile owns the Reader we're using.
    0
}
#[allow(unused_variable)]
extern "C" fn tell(datasource: *mut c_void) -> c_long {
    // TODO permit seeking
    -1
}

// Don't expose ov_fopen and friends because that won't play nicely
// with non-libnative runtime.
impl<R: Reader> VorbisFile<R> {
    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `datasource` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn callback_setup(&mut self) {
        let ds = self as *mut _ as *mut c_void;
        self.decoder.datasource = ds;
    }

    /// Create a Ogg Vorbis decoder.
    pub fn new(src: R) -> OVResult<VorbisFile<R>> {
        let mut vf = VorbisFile {
            src: src,
            decoder: unsafe { mem::uninitialized() },
            channels: Vec::new()
        };
        let callbacks = ffi::ov_callbacks {
            read: VorbisFile::<R>::read,
            seek: seek,
            tell: tell,
            close: close,
        };

        let status = unsafe {
            ffi::ov_open_callbacks(&mut vf.src as *mut _ as *mut c_void,
                                   &mut vf.decoder as *mut _,
                                   ptr::null_mut(), 0, callbacks)
        };

        match status {
            0 => Ok(vf),
            f => {
                // Must not run the destructor. decoder is still uninitialized.
                unsafe {
                    mem::forget(vf.decoder);
                }
                Err(OVError::from_native(f))
            }
        }
    }

    /// Gets the comment struct for the specified bitstream.
    ///
    /// For nonseekable streams, returns the comments for the current
    /// bitstream. Otherwise, specify bitstream -1 to get the current
    /// bitstream.
    pub fn comment<'a>(&'a mut self, link: int) -> Option<Comments<'a>> {
        let cm = unsafe {
            let p = ffi::ov_comment(&mut self.decoder, link as c_int);
            if p.is_null() {
                return None;
            } else {
                *p
            }
        };

        unsafe fn make_str<'a>(data: *const u8, len: uint) -> Option<&'a str> {
            let slice = raw::Slice {
                data: data,
                len: len
            };
            str::from_utf8(mem::transmute(slice))
        }

        Some(Comments {
            vendor: unsafe {
                CString::new(cm.vendor as *const _, false)
            },
            comments: unsafe {
                let mut v = Vec::with_capacity(cm.comments as uint);
                for i in range(0, cm.comments) {
                    let len = *cm.comment_lengths.offset(i as int);
                    match make_str(*cm.user_comments.offset(i as int) as *const _,
                                   len as uint) {
                        Some(s) => {
                            v.push(s);
                        }
                        None => {
                            // Ignore. Vorbis specifies all comment data is valid
                            // UTF-8, but we need to protect against invalid input
                        }
                    }
                }
                v
            }
        })
    }

    /// Decode a block of samples.
    ///
    /// The emitted values are a slice of channels, each containing an equal
    /// number of samples.
    pub fn decode<'a>(&'a mut self) -> OVResult<&'a mut [&'a mut [f32]]> {
        let max_samples = 4096;
        self.callback_setup();
        let mut sample_buffer: *mut *mut f32 = unsafe {
            mem::uninitialized()
        };
        let mut bitstream_idx: c_int = unsafe {
            mem::uninitialized()
        };

        let n_samples = unsafe {
            match ffi::ov_read_float(&mut self.decoder, &mut sample_buffer,
                                     max_samples, &mut bitstream_idx) {
                0 => {
                    return Err(EndOfStream);
                }
                x if x < 0 => {
                    return Err(OVError::from_native(x as c_int));
                }
                x => x
            }
        };
        let n_channels = unsafe {
            (*ffi::ov_info(&mut self.decoder, bitstream_idx)).channels
        };

        self.channels.truncate(0);
        for i in range(0, n_channels) {
            unsafe {
                let channel_buffer = *sample_buffer.offset(i as int);
                let channel_slice = raw::Slice::<f32> {
                    data: channel_buffer as *const f32,
                    len: n_samples as uint
                };
                self.channels.push(channel_slice);
            };
        }
        Ok(unsafe {
            mem::transmute(self.channels.as_slice())
        })
    }

    /// Read `nmemb` items into `ptr` of `size` bytes each.
    ///
    /// If 0 is returned, error status is implied by errno. If nonzero, there was
    /// a read error. Otherwise, reached EOF.
    extern "C" fn read(buffer: *mut c_void, size: size_t, nmemb: size_t,
                       datasource: *mut c_void) -> size_t {
        let vf: &mut VorbisFile<R> = unsafe { mem::transmute(datasource) };
        let ptr = buffer as *mut u8;

        for i in range(0, nmemb) {
            let more = unsafe {
                mut_buf_as_slice(ptr.offset(i as int), size as uint, |buf| {
                    match vf.src.read_at_least(size as uint, buf) {
                        Ok(_) => true,
                        // Assume errno is set under the covers.
                        Err(_) => false
                    }
                })
            };
            if !more {
                // Got error, which might be EOF.
                return i;
            }
        }
        // Completed successfully
        return nmemb;
    }
}

#[unsafe_destructor]
impl<R: Reader> Drop for VorbisFile<R> {
    fn drop(&mut self) {
        self.callback_setup();
        unsafe {
            ffi::ov_clear(&mut self.decoder);
        }
    }
}
<|endoftext|>


<commit_before>// a Shiny test framework
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "shiny"]
#![crate_type = "dylib"]
#![feature(plugin_registrar)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use syntax::abi;
use syntax::ptr::P;
use syntax::ast;
use syntax::ast_util::empty_generics;
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::tts_to_parser;
use syntax::util::small_vector::SmallVector;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("describe", macro_describe);
}

pub fn macro_describe(cx: &mut ExtCtxt, _: Span, tts: &[ast::TokenTree]) -> Box<MacResult+'static> {
    let sess = cx.parse_sess();
    let ttsvec = tts.iter().map(|x| (*x).clone()).collect();

    let mut parser = tts_to_parser(sess, ttsvec, cx.cfg());

    let mut before_block = None;
    let mut test_blocks = vec!();

    loop {
        if parser.token == token::EOF {
            break;
        }

        let ident = parser.parse_ident();
        match ident.as_str() {
            "before_each" => {
                if before_block.is_some() {
                    fail!("only one before_each block is allowed");
                }
                before_block = Some(parser.parse_block());
            },
            "it" => {
                let (name, _) = parser.parse_str();
                let block = parser.parse_block();
                test_blocks.push((name.get().to_string(), block));
            }
            other => {
                let span = parser.span;
                parser.span_fatal(span, format!("expected one of: {} but found `{}`",
                    "`before_each`, `it`",
                    other).as_slice());
            },
        }
    }

    let mut funcs = vec!();

    for &(ref name, ref block) in test_blocks.iter() {
        let body = match before_block {
            None => block.clone(),
            Some(ref before) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items,
                    stmts: before.stmts + block.stmts,

                    ..block.deref().clone()
                })
            }
        };

        let attr_test = cx.attribute(DUMMY_SP,
            cx.meta_word(DUMMY_SP, token::InternedString::new("test")));

        let func = P(ast::Item {
            ident: cx.ident_of(name.replace(" ", "_").as_slice()),
            attrs: vec!(attr_test),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                cx.fn_decl(Vec::new(), cx.ty_nil()),
                ast::NormalFn,
                abi::Rust,
                empty_generics(),
                body),
            vis: ast::Inherited,
            span: DUMMY_SP,
        });
        funcs.push(func);
    }

    MacItems::new(funcs)
}

pub struct MacItems {
    items: Vec<P<ast::Item>>
}

impl MacItems {
    pub fn new(items: Vec<P<ast::Item>>) -> Box<MacResult+'static> {
        box MacItems { items: items } as Box<MacResult>
    }
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(SmallVector::many(self.items.clone()))
    }
}
<commit_msg>fail! is now panic!<commit_after>// a Shiny test framework
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "shiny"]
#![crate_type = "dylib"]
#![feature(plugin_registrar)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use syntax::abi;
use syntax::ptr::P;
use syntax::ast;
use syntax::ast_util::empty_generics;
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::tts_to_parser;
use syntax::util::small_vector::SmallVector;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("describe", macro_describe);
}

pub fn macro_describe(cx: &mut ExtCtxt, _: Span, tts: &[ast::TokenTree]) -> Box<MacResult+'static> {
    let sess = cx.parse_sess();
    let ttsvec = tts.iter().map(|x| (*x).clone()).collect();

    let mut parser = tts_to_parser(sess, ttsvec, cx.cfg());

    let mut before_block = None;
    let mut test_blocks = vec!();

    loop {
        if parser.token == token::EOF {
            break;
        }

        let ident = parser.parse_ident();
        match ident.as_str() {
            "before_each" => {
                if before_block.is_some() {
                    panic!("only one before_each block is allowed");
                }
                before_block = Some(parser.parse_block());
            },
            "it" => {
                let (name, _) = parser.parse_str();
                let block = parser.parse_block();
                test_blocks.push((name.get().to_string(), block));
            }
            other => {
                let span = parser.span;
                parser.span_fatal(span, format!("expected one of: {} but found `{}`",
                    "`before_each`, `it`",
                    other).as_slice());
            },
        }
    }

    let mut funcs = vec!();

    for &(ref name, ref block) in test_blocks.iter() {
        let body = match before_block {
            None => block.clone(),
            Some(ref before) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items,
                    stmts: before.stmts + block.stmts,

                    ..block.deref().clone()
                })
            }
        };

        let attr_test = cx.attribute(DUMMY_SP,
            cx.meta_word(DUMMY_SP, token::InternedString::new("test")));

        let func = P(ast::Item {
            ident: cx.ident_of(name.replace(" ", "_").as_slice()),
            attrs: vec!(attr_test),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                cx.fn_decl(Vec::new(), cx.ty_nil()),
                ast::NormalFn,
                abi::Rust,
                empty_generics(),
                body),
            vis: ast::Inherited,
            span: DUMMY_SP,
        });
        funcs.push(func);
    }

    MacItems::new(funcs)
}

pub struct MacItems {
    items: Vec<P<ast::Item>>
}

impl MacItems {
    pub fn new(items: Vec<P<ast::Item>>) -> Box<MacResult+'static> {
        box MacItems { items: items } as Box<MacResult>
    }
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(SmallVector::many(self.items.clone()))
    }
}
<|endoftext|>


<commit_before>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;

pub trait NodeType {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

pub struct Link<W: Clone> {
    pub node_idx: NodeIndex,
    pub weight: W,
}

pub struct Node<NT: NodeType, N, W: Clone> {
    pub node_type: NT,
    pub node_data: N,
    pub input_links: Vec<Link<W>>,
    pub output_links: Vec<Link<W>>,
}

pub struct Network<NT: NodeType, N, W: Clone> {
    nodes: Vec<Node<NT, N, W>>,
}

struct CycleDetector<'a, NT: NodeType + 'a, N: 'a, W: Clone + 'a> {
    nodes: &'a [Node<NT, N, W>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, NT: NodeType + 'a, N: 'a, W: Clone + 'a> CycleDetector<'a, NT, N, W> {
    fn new(network: &'a Network<NT, N, W>) -> CycleDetector<'a, NT, N, W> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn detect_cycle(&mut self, path_from: usize, path_to: usize) -> bool {
        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from this node and iterate all paths from there. If we hit the target node,
        // we found a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].output_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

impl<NT: NodeType, N, W: Clone> Network<NT, N, W> {
    pub fn new() -> Network<NT, N, W> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<NT, N, W>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: NT, node_data: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            node_data: node_data,
            input_links: Vec::new(),
            output_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.output_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix;

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order;

        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !self.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).detect_cycle(target_node_idx.index(), source_node_idx.index())
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: W) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].output_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });

        self.nodes[target_node_idx.index()].input_links.push(Link {
            node_idx: source_node_idx,
            weight: weight,
        });
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let h1 = g.add_node(NodeT::Hidden, ());
        let h2 = g.add_node(NodeT::Hidden, ());
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let o1 = g.add_node(NodeT::Output, ());
        let o2 = g.add_node(NodeT::Output, ());

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<commit_msg>Rename, add some comments, clarify<commit_after>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;

pub trait NodeType {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

pub struct Link<W: Clone> {
    pub node_idx: NodeIndex,
    pub weight: W,
}

pub struct Node<NT: NodeType, N, W: Clone> {
    pub node_type: NT,
    pub node_data: N,
    pub input_links: Vec<Link<W>>,
    pub output_links: Vec<Link<W>>,
}

pub struct Network<NT: NodeType, N, W: Clone> {
    nodes: Vec<Node<NT, N, W>>,
}

struct CycleDetector<'a, NT: NodeType + 'a, N: 'a, W: Clone + 'a> {
    nodes: &'a [Node<NT, N, W>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, NT: NodeType + 'a, N: 'a, W: Clone + 'a> CycleDetector<'a, NT, N, W> {
    fn new(network: &'a Network<NT, N, W>) -> CycleDetector<'a, NT, N, W> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn link_would_cycle(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        let path_from = target_node_idx.index();
        let path_to = source_node_idx.index();

        assert!(path_from != path_to);

        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from the target_node and iterate all paths from there. If we hit the source node,
        // the addition of this link would lead towards a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].output_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

impl<NT: NodeType, N, W: Clone> Network<NT, N, W> {
    pub fn new() -> Network<NT, N, W> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<NT, N, W>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: NT, node_data: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            node_data: node_data,
            input_links: Vec::new(),
            output_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.output_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix; // make immutable

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order; // make immutable

        let mut cycler = CycleDetector::new(self);
        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !cycler.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).link_would_cycle(source_node_idx, target_node_idx)
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: W) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].output_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });

        self.nodes[target_node_idx.index()].input_links.push(Link {
            node_idx: source_node_idx,
            weight: weight,
        });
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let h1 = g.add_node(NodeT::Hidden, ());
        let h2 = g.add_node(NodeT::Hidden, ());
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let o1 = g.add_node(NodeT::Output, ());
        let o2 = g.add_node(NodeT::Output, ());

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_op_in_unsafe_fn)]

extern crate alloc;

mod display;
mod error;
mod eval;
mod identifier;
mod impls;
mod parse;

#[cfg(feature = "serde")]
mod serde;

use crate::identifier::Identifier;
use alloc::vec::Vec;
use core::str::FromStr;

pub use crate::parse::Error;

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Version {
    pub major: u64,
    pub minor: u64,
    pub patch: u64,
    pub pre: Prerelease,
    pub build: BuildMetadata,
}

#[derive(Default, Clone, Eq, PartialEq, Hash, Debug)]
pub struct VersionReq {
    pub comparators: Vec<Comparator>,
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Comparator {
    pub op: Op,
    pub major: u64,
    pub minor: Option<u64>,
    pub patch: Option<u64>,
    pub pre: Prerelease,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum Op {
    Exact,
    Greater,
    GreaterEq,
    Less,
    LessEq,
    Tilde,
    Caret,
    Wildcard,
}

#[derive(Default, Clone, Eq, PartialEq, Hash)]
pub struct Prerelease {
    identifier: Identifier,
}

#[derive(Default, Clone, Eq, PartialEq, Hash)]
pub struct BuildMetadata {
    identifier: Identifier,
}

impl Version {
    pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
        Version {
            major,
            minor,
            patch,
            pre: Prerelease::EMPTY,
            build: BuildMetadata::EMPTY,
        }
    }

    pub fn parse(text: &str) -> Result<Self, Error> {
        Version::from_str(text)
    }
}

impl VersionReq {
    pub const STAR: Self = VersionReq {
        comparators: Vec::new(),
    };

    pub fn parse(text: &str) -> Result<Self, Error> {
        VersionReq::from_str(text)
    }

    pub fn matches(&self, version: &Version) -> bool {
        eval::matches_req(self, version)
    }
}

impl Comparator {
    pub fn parse(text: &str) -> Result<Self, Error> {
        Comparator::from_str(text)
    }

    pub fn matches(&self, version: &Version) -> bool {
        eval::matches_comparator(self, version)
    }
}

impl Prerelease {
    pub const EMPTY: Self = Prerelease {
        identifier: Identifier::empty(),
    };

    pub fn new(text: &str) -> Result<Self, Error> {
        Prerelease::from_str(text)
    }

    pub fn as_str(&self) -> &str {
        self.identifier.as_str()
    }

    pub fn is_empty(&self) -> bool {
        self.identifier.is_empty()
    }
}

impl BuildMetadata {
    pub const EMPTY: Self = BuildMetadata {
        identifier: Identifier::empty(),
    };

    pub fn new(text: &str) -> Result<Self, Error> {
        BuildMetadata::from_str(text)
    }

    pub fn as_str(&self) -> &str {
        self.identifier.as_str()
    }

    pub fn is_empty(&self) -> bool {
        self.identifier.is_empty()
    }
}
<commit_msg>Set html_root_url<commit_after>#![doc(html_root_url = "https://docs.rs/semver/0.0.0")]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_op_in_unsafe_fn)]

extern crate alloc;

mod display;
mod error;
mod eval;
mod identifier;
mod impls;
mod parse;

#[cfg(feature = "serde")]
mod serde;

use crate::identifier::Identifier;
use alloc::vec::Vec;
use core::str::FromStr;

pub use crate::parse::Error;

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Version {
    pub major: u64,
    pub minor: u64,
    pub patch: u64,
    pub pre: Prerelease,
    pub build: BuildMetadata,
}

#[derive(Default, Clone, Eq, PartialEq, Hash, Debug)]
pub struct VersionReq {
    pub comparators: Vec<Comparator>,
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Comparator {
    pub op: Op,
    pub major: u64,
    pub minor: Option<u64>,
    pub patch: Option<u64>,
    pub pre: Prerelease,
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum Op {
    Exact,
    Greater,
    GreaterEq,
    Less,
    LessEq,
    Tilde,
    Caret,
    Wildcard,
}

#[derive(Default, Clone, Eq, PartialEq, Hash)]
pub struct Prerelease {
    identifier: Identifier,
}

#[derive(Default, Clone, Eq, PartialEq, Hash)]
pub struct BuildMetadata {
    identifier: Identifier,
}

impl Version {
    pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
        Version {
            major,
            minor,
            patch,
            pre: Prerelease::EMPTY,
            build: BuildMetadata::EMPTY,
        }
    }

    pub fn parse(text: &str) -> Result<Self, Error> {
        Version::from_str(text)
    }
}

impl VersionReq {
    pub const STAR: Self = VersionReq {
        comparators: Vec::new(),
    };

    pub fn parse(text: &str) -> Result<Self, Error> {
        VersionReq::from_str(text)
    }

    pub fn matches(&self, version: &Version) -> bool {
        eval::matches_req(self, version)
    }
}

impl Comparator {
    pub fn parse(text: &str) -> Result<Self, Error> {
        Comparator::from_str(text)
    }

    pub fn matches(&self, version: &Version) -> bool {
        eval::matches_comparator(self, version)
    }
}

impl Prerelease {
    pub const EMPTY: Self = Prerelease {
        identifier: Identifier::empty(),
    };

    pub fn new(text: &str) -> Result<Self, Error> {
        Prerelease::from_str(text)
    }

    pub fn as_str(&self) -> &str {
        self.identifier.as_str()
    }

    pub fn is_empty(&self) -> bool {
        self.identifier.is_empty()
    }
}

impl BuildMetadata {
    pub const EMPTY: Self = BuildMetadata {
        identifier: Identifier::empty(),
    };

    pub fn new(text: &str) -> Result<Self, Error> {
        BuildMetadata::from_str(text)
    }

    pub fn as_str(&self) -> &str {
        self.identifier.as_str()
    }

    pub fn is_empty(&self) -> bool {
        self.identifier.is_empty()
    }
}
<|endoftext|>