<commit_before>//! # Examples
//!
//! ```
//! use objpool::Pool;
//! use std::thread;
//!
//! let pool = Pool::with_capacity(5, || 0);
//! let mut handles = Vec::new();
//! for _ in 0..10 {
//!     let pool = pool.clone();
//!     handles.push(thread::spawn(move || {
//!         for _ in 0..1000 {
//!             *pool.get() += 1;
//!         }
//!     }));
//! }
//!
//! for handle in handles {
//!     handle.join().unwrap();
//! }
//! assert_eq!(*pool.get() + *pool.get() + *pool.get() + *pool.get() + *pool.get(), 10000);
//! ```

use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Condvar, Mutex, Weak};
use std::time::{Duration, SystemTime};

pub struct Pool<T, F> where F: Fn() -> T {
    create: F,
    items: Mutex<Items<T>>,
    item_available: Condvar,
    weak_self: Weak<Pool<T, F>>,
}

impl<T, F> Pool<T, F> where F: Fn() -> T {
    pub fn new(create: F) -> Arc<Pool<T, F>> {
        Pool::with_capacity(std::usize::MAX, create)
    }

    pub fn with_capacity(capacity: usize, create: F) -> Arc<Pool<T, F>> {
        let pool = Arc::new(Pool {
            create: create,
            items: Mutex::new(Items {
                available: Vec::new(),
                count: 0,
                max: Some(capacity),
            }),
            item_available: Condvar::new(),
            weak_self: Weak::new(),
        });
        unsafe {
            let ptr = &pool.weak_self as *const Weak<Pool<T, F>> as *mut Weak<Pool<T, F>>;
            *ptr = Arc::downgrade(&pool);
        }
        pool
    }

    pub fn get(&self) -> Item<T, F> {
        self.get_impl(None).unwrap()
    }

    pub fn get_timeout(&self, duration: Duration) -> Result<Item<T, F>, TimeoutError> {
        self.get_impl(Some(duration))
    }

    fn get_impl(&self, duration: Option<Duration>) -> Result<Item<T, F>, TimeoutError> {
        let mut items = self.items.lock().unwrap();

        if let Some(item) = items.available.pop() {
            return Ok(self.wrap(item));
        }

        if items.count < items.max.unwrap_or(std::usize::MAX) {
            items.count += 1;
            drop(items);
            return Ok(self.wrap((self.create)()));
        }

        if duration.is_some() {
            let duration = duration.unwrap();
            let start = SystemTime::now();
            while items.available.is_empty() {
                let elapsed = start.elapsed().unwrap_or(Duration::from_secs(0));
                if elapsed >= duration {
                    return Err(TimeoutError);
                }
                items = self.item_available.wait_timeout(items, duration - elapsed).unwrap().0;
            }
        } else {
            while items.available.is_empty() {
                items = self.item_available.wait(items).unwrap();
            }
        }

        Ok(self.wrap(items.available.pop().unwrap()))
    }

    fn wrap(&self, item: T) -> Item<T, F> {
        Item {
            item: Some(item),
            pool: self.weak_self.upgrade().unwrap(),
        }
    }

    fn put(&self, item: T) {
        self.items.lock().unwrap().available.push(item);
        self.item_available.notify_one();
    }
}

impl<T, F> Debug for Pool<T, F> where F: Fn() -> T {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Pool")
            .field("items", &*self.items.lock().unwrap())
            .finish()
    }
}

struct Items<T> {
    available: Vec<T>,
    count: usize,
    max: Option<usize>,
}

impl<T> Debug for Items<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Items")
            .field("available", &self.available.len())
            .field("count", &self.count)
            .field("max", &self.max)
            .finish()
    }
}

pub struct Item<T, F> where F: Fn() -> T {
    item: Option<T>,
    pool: Arc<Pool<T, F>>,
}

impl<T, F> Debug for Item<T, F> where T: Debug, F: Fn() -> T {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Item")
            .field("item", &self.item)
            .finish()
    }
}

impl<T, F> Deref for Item<T, F> where F: Fn() -> T {
    type Target = T;

    fn deref(&self) -> &T {
        self.item.as_ref().unwrap()
    }
}

impl<T, F> DerefMut for Item<T, F> where F: Fn() -> T {
    fn deref_mut(&mut self) -> &mut T {
        self.item.as_mut().unwrap()
    }
}

impl<T, F> Drop for Item<T, F> where F: Fn() -> T {
    fn drop(&mut self) {
        self.pool.put(self.item.take().unwrap());
    }
}

#[derive(Debug, Eq, PartialEq)]
pub struct TimeoutError;

impl Display for TimeoutError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.write_str("wait timed out")
    }
}

impl Error for TimeoutError {
    fn description(&self) -> &str {
        "wait timed out"
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error;
    use std::time::{Duration, SystemTime};
    use std::thread;
    use super::*;

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + self.subsec_nanos() as u64 / 1000000
        }
    }

    #[test]
    fn pool_builder() {
        let pool = Pool::with_capacity(1, || 0);
        let _x = pool.get();
        assert_eq!(pool.get_timeout(Duration::from_secs(0)).err(), Some(TimeoutError));
    }

    #[test]
    fn pool_get() {
        let pool = Pool::with_capacity(1, || 0);
        let x = pool.get();
        let start = SystemTime::now();
        let handle = thread::spawn(move || {
            let _ = pool.get();
        });
        thread::sleep(Duration::from_millis(100));
        drop(x);
        handle.join().unwrap();
        let elapsed_ms = start.elapsed().unwrap().as_millis();
        assert!(elapsed_ms >= 50 && elapsed_ms < 150);
    }

    #[test]
    fn pool_get_mut() {
        let pool = Pool::new(|| 0);
        *pool.get() = 4;
        assert_eq!(*pool.get(), 4);
    }

    #[test]
    fn pool_get_timeout_ok() {
        let pool = Pool::with_capacity(1, || 0);
        let x = pool.get();
        let start = SystemTime::now();
        let handle = thread::spawn(move || {
            let _ = pool.get_timeout(Duration::from_secs(1)).unwrap();
        });
        thread::sleep(Duration::from_millis(100));
        drop(x);
        handle.join().unwrap();
        let elapsed_ms = start.elapsed().unwrap().as_millis();
        assert!(elapsed_ms >= 50 && elapsed_ms < 150);
    }

    #[test]
    fn pool_get_timeout_err() {
        let pool = Pool::with_capacity(1, || 0);
        let _x = pool.get();
        let start = SystemTime::now();
        let handle = {
            let pool = pool.clone();
            thread::spawn(move || {
                assert_eq!(pool.get_timeout(Duration::from_millis(100)).err(), Some(TimeoutError));
            })
        };
        while start.elapsed().unwrap().as_millis() < 100 {
            pool.item_available.notify_one();
        }
        handle.join().unwrap();
        let elapsed_ms = start.elapsed().unwrap().as_millis();
        assert!(elapsed_ms >= 50 && elapsed_ms < 150);
    }

    #[test]
    fn pool_debug() {
        let pool = Pool::with_capacity(5, || 0);
        assert_eq!(format!("{:?}", pool),
            "Pool { items: Items { available: 0, count: 0, max: Some(5) } }");
        let x = pool.get();
        let _y = pool.get();
        let _z = pool.get();
        drop(x);
        assert_eq!(format!("{:?}", pool),
            "Pool { items: Items { available: 1, count: 3, max: Some(5) } }");
    }

    #[test]
    fn item_debug() {
        let pool = Pool::new(|| 0);
        let x = pool.get();
        assert_eq!(format!("{:?}", x), "Item { item: Some(0) }");
    }

    #[test]
    fn timeout_error() {
        assert_eq!(format!("{}", TimeoutError), "wait timed out");
        assert_eq!(TimeoutError.description(), "wait timed out");
    }
}
<commit_msg>store constructor in a Box to simplify code<commit_after>//! # Examples
//!
//! ```
//! use objpool::Pool;
//! use std::thread;
//!
//! let pool = Pool::with_capacity(5, || 0);
//! let mut handles = Vec::new();
//! for _ in 0..10 {
//!     let pool = pool.clone();
//!     handles.push(thread::spawn(move || {
//!         for _ in 0..1000 {
//!             *pool.get() += 1;
//!         }
//!     }));
//! }
//!
//! for handle in handles {
//!     handle.join().unwrap();
//! }
//! assert_eq!(*pool.get() + *pool.get() + *pool.get() + *pool.get() + *pool.get(), 10000);
//! ```

use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Condvar, Mutex, Weak};
use std::time::{Duration, SystemTime};

pub struct Pool<T> {
    constructor: Box<Fn() -> T + Send + Sync + 'static>,
    items: Mutex<Items<T>>,
    item_available: Condvar,
    weak_self: Weak<Pool<T>>,
}

impl<T> Pool<T> {
    pub fn new<C>(constructor: C) -> Arc<Pool<T>>
        where C: Fn() -> T + Send + Sync + 'static {

        Pool::with_capacity(std::usize::MAX, constructor)
    }

    pub fn with_capacity<C>(capacity: usize, constructor: C) -> Arc<Pool<T>>
        where C: Fn() -> T + Send + Sync + 'static {

        let pool = Arc::new(Pool {
            constructor: Box::new(constructor),
            items: Mutex::new(Items {
                available: Vec::new(),
                count: 0,
                max: Some(capacity),
            }),
            item_available: Condvar::new(),
            weak_self: Weak::new(),
        });
        unsafe {
            let ptr = &pool.weak_self as *const Weak<Pool<T>> as *mut Weak<Pool<T>>;
            *ptr = Arc::downgrade(&pool);
        }
        pool
    }

    pub fn get(&self) -> Item<T> {
        self.get_impl(None).unwrap()
    }

    pub fn get_timeout(&self, duration: Duration) -> Result<Item<T>, TimeoutError> {
        self.get_impl(Some(duration))
    }

    fn get_impl(&self, duration: Option<Duration>) -> Result<Item<T>, TimeoutError> {
        let mut items = self.items.lock().unwrap();

        if let Some(item) = items.available.pop() {
            return Ok(self.wrap(item));
        }

        if items.count < items.max.unwrap_or(std::usize::MAX) {
            items.count += 1;
            drop(items);
            return Ok(self.wrap((self.constructor)()));
        }

        if duration.is_some() {
            let duration = duration.unwrap();
            let start = SystemTime::now();
            while items.available.is_empty() {
                let elapsed = start.elapsed().unwrap_or(Duration::from_secs(0));
                if elapsed >= duration {
                    return Err(TimeoutError);
                }
                items = self.item_available.wait_timeout(items, duration - elapsed).unwrap().0;
            }
        } else {
            while items.available.is_empty() {
                items = self.item_available.wait(items).unwrap();
            }
        }

        Ok(self.wrap(items.available.pop().unwrap()))
    }

    fn wrap(&self, item: T) -> Item<T> {
        Item {
            item: Some(item),
            pool: self.weak_self.upgrade().unwrap(),
        }
    }

    fn put(&self, item: T) {
        self.items.lock().unwrap().available.push(item);
        self.item_available.notify_one();
    }
}

impl<T> Debug for Pool<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Pool")
            .field("items", &*self.items.lock().unwrap())
            .finish()
    }
}

struct Items<T> {
    available: Vec<T>,
    count: usize,
    max: Option<usize>,
}

impl<T> Debug for Items<T> {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Items")
            .field("available", &self.available.len())
            .field("count", &self.count)
            .field("max", &self.max)
            .finish()
    }
}

pub struct Item<T> {
    item: Option<T>,
    pool: Arc<Pool<T>>,
}

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

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

    fn deref(&self) -> &T {
        self.item.as_ref().unwrap()
    }
}

impl<T> DerefMut for Item<T> {
    fn deref_mut(&mut self) -> &mut T {
        self.item.as_mut().unwrap()
    }
}

impl<T> Drop for Item<T> {
    fn drop(&mut self) {
        self.pool.put(self.item.take().unwrap());
    }
}

#[derive(Debug, Eq, PartialEq)]
pub struct TimeoutError;

impl Display for TimeoutError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.write_str("wait timed out")
    }
}

impl Error for TimeoutError {
    fn description(&self) -> &str {
        "wait timed out"
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error;
    use std::time::{Duration, SystemTime};
    use std::thread;
    use super::*;

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + self.subsec_nanos() as u64 / 1000000
        }
    }

    #[test]
    fn pool_get() {
        let pool = Pool::with_capacity(1, || 0);
        let x = pool.get();
        let start = SystemTime::now();
        let handle = thread::spawn(move || {
            let _ = pool.get();
        });
        thread::sleep(Duration::from_millis(100));
        drop(x);
        handle.join().unwrap();
        let elapsed_ms = start.elapsed().unwrap().as_millis();
        assert!(elapsed_ms >= 50 && elapsed_ms < 150);
    }

    #[test]
    fn pool_get_mut() {
        let pool = Pool::new(|| 0);
        *pool.get() = 4;
        assert_eq!(*pool.get(), 4);
    }

    #[test]
    fn pool_get_timeout_ok() {
        let pool = Pool::with_capacity(1, || 0);
        let x = pool.get();
        let start = SystemTime::now();
        let handle = thread::spawn(move || {
            let _ = pool.get_timeout(Duration::from_secs(1)).unwrap();
        });
        thread::sleep(Duration::from_millis(100));
        drop(x);
        handle.join().unwrap();
        let elapsed_ms = start.elapsed().unwrap().as_millis();
        assert!(elapsed_ms >= 50 && elapsed_ms < 150);
    }

    #[test]
    fn pool_get_timeout_err() {
        let pool = Pool::with_capacity(1, || 0);
        let _x = pool.get();
        let start = SystemTime::now();
        let handle = {
            let pool = pool.clone();
            thread::spawn(move || {
                assert_eq!(pool.get_timeout(Duration::from_millis(100)).err(), Some(TimeoutError));
            })
        };
        while start.elapsed().unwrap().as_millis() < 100 {
            pool.item_available.notify_one();
        }
        handle.join().unwrap();
        let elapsed_ms = start.elapsed().unwrap().as_millis();
        assert!(elapsed_ms >= 50 && elapsed_ms < 150);
    }

    #[test]
    fn pool_debug() {
        let pool = Pool::with_capacity(5, || 0);
        assert_eq!(format!("{:?}", pool),
            "Pool { items: Items { available: 0, count: 0, max: Some(5) } }");
        let x = pool.get();
        let _y = pool.get();
        let _z = pool.get();
        drop(x);
        assert_eq!(format!("{:?}", pool),
            "Pool { items: Items { available: 1, count: 3, max: Some(5) } }");
    }

    #[test]
    fn item_debug() {
        let pool = Pool::new(|| 0);
        let x = pool.get();
        assert_eq!(format!("{:?}", x), "Item { item: Some(0) }");
    }

    #[test]
    fn timeout_error() {
        assert_eq!(format!("{}", TimeoutError), "wait timed out");
        assert_eq!(TimeoutError.description(), "wait timed out");
    }
}
<|endoftext|>


<commit_before>//! # Configs
//!
//! There isn't just one type of Base64; that would be too simple. You need to choose a character
//! set (standard, URL-safe, etc) and padding suffix (yes/no).
//! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`,
//! `URL_SAFE`, etc. You can also make your own `Config` if needed.
//!
//! The functions that don't have `config` in the name (e.g. `encode()` and `decode()`) use the
//! `STANDARD` config .
//!
//! The functions that write to a slice (the ones that end in `_slice`) are generally the fastest
//! because they don't need to resize anything. If it fits in your workflow and you care about
//! performance, keep using the same buffer (growing as need be) and use the `_slice` methods for
//! the best performance.
//!
//! # Encoding
//!
//! Several different encoding functions are available to you depending on your desire for
//! convenience vs performance.
//!
//! | Function                | Output                       | Allocates                      |
//! | ----------------------- | ---------------------------- | ------------------------------ |
//! | `encode`                | Returns a new `String`       | Always                         |
//! | `encode_config`         | Returns a new `String`       | Always                         |
//! | `encode_config_buf`     | Appends to provided `String` | Only if `String` needs to grow |
//! | `encode_config_slice`   | Writes to provided `&[u8]`   | Never                          |
//!
//! All of the encoding functions that take a `Config` will pad as per the config.
//!
//! # Decoding
//!
//! Just as for encoding, there are different decoding functions available.
//!
//! | Function                | Output                        | Allocates                      |
//! | ----------------------- | ----------------------------- | ------------------------------ |
//! | `decode`                | Returns a new `Vec<u8>`       | Always                         |
//! | `decode_config`         | Returns a new `Vec<u8>`       | Always                         |
//! | `decode_config_buf`     | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow    |
//! | `decode_config_slice`   | Writes to provided `&[u8]`    | Never                          |
//!
//! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`).
//!
//! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is
//! valid, but excess padding is not.) Whitespace in the input is invalid.
//!
//! # `Read` and `Write`
//!
//! To map a `Read` of b64 bytes to the decoded bytes, wrap a reader (file, network socket, etc)
//! with `base64::read::DecoderReader`. To write raw bytes and have them b64 encoded on the fly,
//! wrap a writer with `base64::write::EncoderWriter`. There is some performance overhead (15% or
//! so) because of the necessary buffer shuffling -- still fast enough that almost nobody cares.
//! Also, these implementations do not heap allocate.
//!
//! # Panics
//!
//! If length calculations result in overflowing `usize`, a panic will result.
//!
//! The `_slice` flavors of encode or decode will panic if the provided output slice is too small,

#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
#![deny(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_results,
    variant_size_differences,
    warnings
)]
#![forbid(unsafe_code)]
#![cfg_attr(not(any(feature = "std", test)), no_std)]

#[cfg(all(feature = "alloc", not(any(feature = "std", test))))]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate std as alloc;

#[cfg(test)]
#[macro_use]
extern crate doc_comment;

#[cfg(test)]
doctest!("../README.md");

mod chunked_encoder;
pub mod display;
#[cfg(any(feature = "std", test))]
pub mod read;
mod tables;
#[cfg(any(feature = "std", test))]
pub mod write;

mod encode;
pub use crate::encode::encode_config_slice;
#[cfg(any(feature = "alloc", feature = "std", test))]
pub use crate::encode::{encode, encode_config, encode_config_buf};

mod decode;
#[cfg(any(feature = "alloc", feature = "std", test))]
pub use crate::decode::{decode, decode_config, decode_config_buf};
pub use crate::decode::{decode_config_slice, DecodeError};

#[cfg(test)]
mod tests;

/// Available encoding character sets
#[derive(Clone, Copy, Debug)]
pub enum CharacterSet {
    /// The standard character set (uses `+` and `/`).
    ///
    /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
    Standard,
    /// The URL safe character set (uses `-` and `_`).
    ///
    /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
    UrlSafe,
    /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
    ///
    /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
    Crypt,
    /// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`).
    Bcrypt,
    /// The character set used in IMAP-modified UTF-7 (uses `+` and `,`).
    ///
    /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3)
    ImapMutf7,
}

impl CharacterSet {
    fn encode_table(self) -> &'static [u8; 64] {
        match self {
            CharacterSet::Standard => tables::STANDARD_ENCODE,
            CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
            CharacterSet::Crypt => tables::CRYPT_ENCODE,
            CharacterSet::Bcrypt => tables::BCRYPT_ENCODE,
            CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_ENCODE,
        }
    }

    fn decode_table(self) -> &'static [u8; 256] {
        match self {
            CharacterSet::Standard => tables::STANDARD_DECODE,
            CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
            CharacterSet::Crypt => tables::CRYPT_DECODE,
            CharacterSet::Bcrypt => tables::BCRYPT_DECODE,
            CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_DECODE,
        }
    }
}

/// Contains configuration parameters for base64 encoding
#[derive(Clone, Copy, Debug)]
pub struct Config {
    /// Character set to use
    char_set: CharacterSet,
    /// True to pad output with `=` characters
    pad: bool,
    /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned.
    decode_allow_trailing_bits: bool,
}

impl Config {
    /// Create a new `Config`.
    pub fn new(char_set: CharacterSet, pad: bool) -> Config {
        Config {
            char_set,
            pad,
            decode_allow_trailing_bits: false,
        }
    }

    /// Sets whether to pad output with `=` characters.
    pub fn pad(self, pad: bool) -> Config {
        Config { pad, ..self }
    }

    /// Sets whether to emit errors for nonzero trailing bits.
    ///
    /// This is useful when implementing
    /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode).
    pub fn decode_allow_trailing_bits(self, allow: bool) -> Config {
        Config {
            decode_allow_trailing_bits: allow,
            ..self
        }
    }
}

/// Standard character set with padding.
pub const STANDARD: Config = Config {
    char_set: CharacterSet::Standard,
    pad: true,
    decode_allow_trailing_bits: false,
};

/// Standard character set without padding.
pub const STANDARD_NO_PAD: Config = Config {
    char_set: CharacterSet::Standard,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// URL-safe character set with padding
pub const URL_SAFE: Config = Config {
    char_set: CharacterSet::UrlSafe,
    pad: true,
    decode_allow_trailing_bits: false,
};

/// URL-safe character set without padding
pub const URL_SAFE_NO_PAD: Config = Config {
    char_set: CharacterSet::UrlSafe,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// As per `crypt(3)` requirements
pub const CRYPT: Config = Config {
    char_set: CharacterSet::Crypt,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// Bcrypt character set
pub const BCRYPT: Config = Config {
    char_set: CharacterSet::Bcrypt,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// IMAP modified UTF-7 requirements
pub const IMAP_MUTF7: Config = Config {
    char_set: CharacterSet::ImapMutf7,
    pad: false,
    decode_allow_trailing_bits: false,
};
<commit_msg>Replace "cfg(test)" with "cfg(doctest)" for readme testing<commit_after>//! # Configs
//!
//! There isn't just one type of Base64; that would be too simple. You need to choose a character
//! set (standard, URL-safe, etc) and padding suffix (yes/no).
//! The `Config` struct encapsulates this info. There are some common configs included: `STANDARD`,
//! `URL_SAFE`, etc. You can also make your own `Config` if needed.
//!
//! The functions that don't have `config` in the name (e.g. `encode()` and `decode()`) use the
//! `STANDARD` config .
//!
//! The functions that write to a slice (the ones that end in `_slice`) are generally the fastest
//! because they don't need to resize anything. If it fits in your workflow and you care about
//! performance, keep using the same buffer (growing as need be) and use the `_slice` methods for
//! the best performance.
//!
//! # Encoding
//!
//! Several different encoding functions are available to you depending on your desire for
//! convenience vs performance.
//!
//! | Function                | Output                       | Allocates                      |
//! | ----------------------- | ---------------------------- | ------------------------------ |
//! | `encode`                | Returns a new `String`       | Always                         |
//! | `encode_config`         | Returns a new `String`       | Always                         |
//! | `encode_config_buf`     | Appends to provided `String` | Only if `String` needs to grow |
//! | `encode_config_slice`   | Writes to provided `&[u8]`   | Never                          |
//!
//! All of the encoding functions that take a `Config` will pad as per the config.
//!
//! # Decoding
//!
//! Just as for encoding, there are different decoding functions available.
//!
//! | Function                | Output                        | Allocates                      |
//! | ----------------------- | ----------------------------- | ------------------------------ |
//! | `decode`                | Returns a new `Vec<u8>`       | Always                         |
//! | `decode_config`         | Returns a new `Vec<u8>`       | Always                         |
//! | `decode_config_buf`     | Appends to provided `Vec<u8>` | Only if `Vec` needs to grow    |
//! | `decode_config_slice`   | Writes to provided `&[u8]`    | Never                          |
//!
//! Unlike encoding, where all possible input is valid, decoding can fail (see `DecodeError`).
//!
//! Input can be invalid because it has invalid characters or invalid padding. (No padding at all is
//! valid, but excess padding is not.) Whitespace in the input is invalid.
//!
//! # `Read` and `Write`
//!
//! To map a `Read` of b64 bytes to the decoded bytes, wrap a reader (file, network socket, etc)
//! with `base64::read::DecoderReader`. To write raw bytes and have them b64 encoded on the fly,
//! wrap a writer with `base64::write::EncoderWriter`. There is some performance overhead (15% or
//! so) because of the necessary buffer shuffling -- still fast enough that almost nobody cares.
//! Also, these implementations do not heap allocate.
//!
//! # Panics
//!
//! If length calculations result in overflowing `usize`, a panic will result.
//!
//! The `_slice` flavors of encode or decode will panic if the provided output slice is too small,

#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
#![deny(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_results,
    variant_size_differences,
    warnings
)]
#![forbid(unsafe_code)]
#![cfg_attr(not(any(feature = "std", test)), no_std)]

#[cfg(all(feature = "alloc", not(any(feature = "std", test))))]
extern crate alloc;
#[cfg(any(feature = "std", test))]
extern crate std as alloc;

#[cfg(doctest)]
#[macro_use]
extern crate doc_comment;

#[cfg(doctest)]
doctest!("../README.md");

mod chunked_encoder;
pub mod display;
#[cfg(any(feature = "std", test))]
pub mod read;
mod tables;
#[cfg(any(feature = "std", test))]
pub mod write;

mod encode;
pub use crate::encode::encode_config_slice;
#[cfg(any(feature = "alloc", feature = "std", test))]
pub use crate::encode::{encode, encode_config, encode_config_buf};

mod decode;
#[cfg(any(feature = "alloc", feature = "std", test))]
pub use crate::decode::{decode, decode_config, decode_config_buf};
pub use crate::decode::{decode_config_slice, DecodeError};

#[cfg(test)]
mod tests;

/// Available encoding character sets
#[derive(Clone, Copy, Debug)]
pub enum CharacterSet {
    /// The standard character set (uses `+` and `/`).
    ///
    /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
    Standard,
    /// The URL safe character set (uses `-` and `_`).
    ///
    /// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4).
    UrlSafe,
    /// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
    ///
    /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
    Crypt,
    /// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`).
    Bcrypt,
    /// The character set used in IMAP-modified UTF-7 (uses `+` and `,`).
    ///
    /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3)
    ImapMutf7,
}

impl CharacterSet {
    fn encode_table(self) -> &'static [u8; 64] {
        match self {
            CharacterSet::Standard => tables::STANDARD_ENCODE,
            CharacterSet::UrlSafe => tables::URL_SAFE_ENCODE,
            CharacterSet::Crypt => tables::CRYPT_ENCODE,
            CharacterSet::Bcrypt => tables::BCRYPT_ENCODE,
            CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_ENCODE,
        }
    }

    fn decode_table(self) -> &'static [u8; 256] {
        match self {
            CharacterSet::Standard => tables::STANDARD_DECODE,
            CharacterSet::UrlSafe => tables::URL_SAFE_DECODE,
            CharacterSet::Crypt => tables::CRYPT_DECODE,
            CharacterSet::Bcrypt => tables::BCRYPT_DECODE,
            CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_DECODE,
        }
    }
}

/// Contains configuration parameters for base64 encoding
#[derive(Clone, Copy, Debug)]
pub struct Config {
    /// Character set to use
    char_set: CharacterSet,
    /// True to pad output with `=` characters
    pad: bool,
    /// True to ignore excess nonzero bits in the last few symbols, otherwise an error is returned.
    decode_allow_trailing_bits: bool,
}

impl Config {
    /// Create a new `Config`.
    pub fn new(char_set: CharacterSet, pad: bool) -> Config {
        Config {
            char_set,
            pad,
            decode_allow_trailing_bits: false,
        }
    }

    /// Sets whether to pad output with `=` characters.
    pub fn pad(self, pad: bool) -> Config {
        Config { pad, ..self }
    }

    /// Sets whether to emit errors for nonzero trailing bits.
    ///
    /// This is useful when implementing
    /// [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode).
    pub fn decode_allow_trailing_bits(self, allow: bool) -> Config {
        Config {
            decode_allow_trailing_bits: allow,
            ..self
        }
    }
}

/// Standard character set with padding.
pub const STANDARD: Config = Config {
    char_set: CharacterSet::Standard,
    pad: true,
    decode_allow_trailing_bits: false,
};

/// Standard character set without padding.
pub const STANDARD_NO_PAD: Config = Config {
    char_set: CharacterSet::Standard,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// URL-safe character set with padding
pub const URL_SAFE: Config = Config {
    char_set: CharacterSet::UrlSafe,
    pad: true,
    decode_allow_trailing_bits: false,
};

/// URL-safe character set without padding
pub const URL_SAFE_NO_PAD: Config = Config {
    char_set: CharacterSet::UrlSafe,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// As per `crypt(3)` requirements
pub const CRYPT: Config = Config {
    char_set: CharacterSet::Crypt,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// Bcrypt character set
pub const BCRYPT: Config = Config {
    char_set: CharacterSet::Bcrypt,
    pad: false,
    decode_allow_trailing_bits: false,
};

/// IMAP modified UTF-7 requirements
pub const IMAP_MUTF7: Config = Config {
    char_set: CharacterSet::ImapMutf7,
    pad: false,
    decode_allow_trailing_bits: false,
};
<|endoftext|>


<commit_before>#[cfg(not(test))] pub const WIDTH: usize = 5;
#[cfg(not(test))] pub const HEIGHT: usize = 5;
#[cfg(not(test))] pub const X_ROW: usize = 4;

#[cfg(test)] pub const WIDTH: usize = 4;
#[cfg(test)] pub const HEIGHT: usize = 3;
#[cfg(test)] pub const X_ROW: usize = 2;

pub struct Game {
    turns: u32,
    current_turn: Player,
    winner: Option<Player>,
    field: Field,
}

impl Game {
    pub fn new() -> Game {
        Game {
            turns: 0,
            current_turn: Player::Red,
            winner : None,
		    field: Field::new(),
		}
    }

    pub fn current_turn(&self) -> Player {
        self.current_turn
    }

    pub fn winner(&self) -> Option<Player> {
        self.winner
    }

    pub fn is_full(&self) -> bool {
        self.turns as usize == WIDTH * HEIGHT
    }

    pub fn make_turn(&mut self, column: usize) -> Result<(), GameError> {
        if self.winner.is_some() { return Err(GameError::AlreadyEnded); }
        try!(self.field.throw_token(column, self.current_turn));
        self.winner = self.field.win_check();
        self.turns += 1;
        self.current_turn = self.current_turn.next();
        Ok(())
    }

    pub fn current_state(&self) -> &[Option<Player>; WIDTH * HEIGHT] {
        &self.field.cells
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GameError {
    NoSuchColumn,
    ColumnIsFull,
    AlreadyEnded,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Player {
    Red,
    Blue,
}

impl Player {
    fn next(self) -> Player {
        match self {
            Player::Red => Player::Blue,
            Player::Blue => Player::Red,
        }
    }
}

pub struct Field {
    cells: [Option<Player>; WIDTH * HEIGHT],
}

impl Field {

    pub fn with_cells(cells: [Option<Player>; WIDTH * HEIGHT]) -> Field {
        Field {
            cells: cells,
        }
    }

    pub fn free_columns(&self) -> Option<Vec<usize>> {
        let mut res = Vec::new();

        for (index, Column { cells }) in self.columns().enumerate() {
            if cells.iter().any(|x| x.is_none()) {
                res.push(index);
            }
        }

        if res.is_empty() { None } else { Some(res) }
    }

    fn new() -> Field {
        Field {
		    cells: [None; (WIDTH * HEIGHT) as usize],
		}
    }

    fn throw_token(&mut self, column_index: usize, player: Player) -> Result<(), GameError> {
        if column_index > WIDTH { return Err(GameError::NoSuchColumn); }
        let Column { cells } = Columns::index(&self.cells, column_index).next().unwrap();
        let row_index = try!( cells.iter().position(|x| x.is_none() ).ok_or(GameError::ColumnIsFull) );
        let position = row_index * WIDTH + column_index;
        self.cells[position] = Some(player);
        Ok(())
    }

    fn win_check(&self) -> Option<Player> {
        for Row { cells } in self.rows() {
            match Field::max_series(&cells[..]) {
                (Some(player), length) => {
                	if length >= X_ROW {
                	    return Some(player);
                	}
                },
                _ => {}
            }
        }

        for Column { cells } in self.columns() {
            match Field::max_series(&cells[..]) {
                (Some(player), length) => {
                	if length >= X_ROW {
                	    return Some(player);
                	}
                },
                _ => {}
            }
        }

        for Diagonal { cells, length } in self.diagonals() {
            match Field::max_series(&cells[0..length]) {
                (Some(player), length) => {
                	if length >= X_ROW {
                	    return Some(player);
                	}
                },
                _ => {}
            }
        }

        None
    }

    fn rows<'a>(&'a self) -> Rows<'a>{
        Rows::new(&self.cells)
    }

    fn columns<'a, 'b>(&'a self) -> Columns<'a> {
        Columns::new(&self.cells)
    }

    fn diagonals<'a>(&'a self) -> Diagonals<'a> {
        Diagonals::new(&self.cells)
    }

    fn max_series(cells: &[Option<Player>]) -> (Option<Player>, usize) {
        const RED: Option<Player> = Some(Player::Red);
        const BLUE: Option<Player> = Some(Player::Blue);
        let mut red_max = 0;
        let mut blue_max = 0;
        let mut prev_player = None;
        let mut series = 0;

        for curr_player in cells.iter() {
            match (*curr_player, prev_player) {
                (Some(_), None) => { series = 1; },
                (RED, RED) | (BLUE, BLUE) => { series += 1; },
                (None, RED) | (BLUE, RED) => {
					if series > red_max { red_max = series; }
					series = 1;
				},
                (None, BLUE) | (RED, BLUE) => {
					if series > blue_max { blue_max = series; }
					series = 1;
				},
                _ => {}
            }
            prev_player = *curr_player;
        }

        match prev_player {
            BLUE => if series > blue_max { blue_max = series; },
            RED  => if series > red_max { red_max = series; },
            _ => {},
        }

        if red_max == blue_max { return (None, red_max); }
        if red_max > blue_max { return (RED, red_max); } else { return (BLUE, blue_max); }
    }
}

struct Rows<'a> {
    field: &'a [Option<Player>; WIDTH * HEIGHT],
    current_row: usize,
}

impl<'a> Rows<'a> {
    fn new(field: &'a [Option<Player>; WIDTH * HEIGHT]) -> Rows<'a> {
        Rows {
		    field: field,
		    current_row: 0,
		}
    }

    fn index(field: &'a [Option<Player>; WIDTH * HEIGHT], index: usize) -> Rows<'a> {
        Rows {
		    field: field,
		    current_row: index,
		}
    }
}

impl<'a> Iterator for Rows<'a> {
    type Item = Row;

    fn next(&mut self) -> Option<Row> {
        if self.current_row < HEIGHT {
            let from = self.current_row * WIDTH;
            let to = from + WIDTH;
            let mut cells = [None; WIDTH];
            for (val, index) in (&self.field[from .. to]).iter().zip(0..WIDTH) {
                cells[index] = *val;
            }
            self.current_row += 1;
            Some( Row { cells: cells} )
        } else {
            None
        }
    }
}

struct Row {
    cells: [Option<Player>; WIDTH],
}

struct Columns<'a> {
    field: &'a [Option<Player>; WIDTH * HEIGHT],
    current_column: usize,
}

impl<'a> Columns<'a> {
    fn new(field: &'a [Option<Player>; WIDTH * HEIGHT]) -> Columns<'a> {
        Columns {
		    field: field,
			current_column: 0,
		}
    }

    fn index(field: &'a [Option<Player>; WIDTH * HEIGHT], index: usize) -> Columns<'a> {
        Columns {
            field: field,
            current_column: index,
		}
    }
}

impl<'a> Iterator for Columns<'a> {
    type Item = Column;

    fn next(&mut self) -> Option<Column> {
        if self.current_column < WIDTH {
            let mut cells = [None; HEIGHT];
            for i in 0..HEIGHT {
                let index: usize = (i * WIDTH as usize) + self.current_column as usize;
                cells[i] = self.field[index];
            }
            self.current_column += 1;
            Some( Column { cells: cells} )
        } else {
            None
        }
    }
}

struct Column {
    cells: [Option<Player>; HEIGHT],
}

struct Diagonals<'a> {
    field: &'a [Option<Player>; WIDTH * HEIGHT],
    current_diagonal : usize,
    total_diagonals: usize,
}

impl<'a> Diagonals<'a> {
    fn new(field: &'a [Option<Player>; WIDTH * HEIGHT]) -> Diagonals<'a> {
        Diagonals {
		    field: field,
		    current_diagonal: 0,
		    total_diagonals: WIDTH + HEIGHT - 3,
		}
    }
}

impl<'a> Iterator for Diagonals<'a> {
    type Item = Diagonal;

    fn next(&mut self) -> Option<Diagonal> {
        if WIDTH == 1 || HEIGHT == 1 { return None; }
        if self.total_diagonals >= self.current_diagonal { return None; }
        None
    }
}

struct Diagonal {
    cells: [Option<Player>; WIDTH + HEIGHT],
    length: usize,
}

#[test]
fn test_diagonal_win() {
    let mut game = Game::new();
    game.make_turn(0).unwrap();
    println!("");
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    assert_eq!(game.winner(), Some(Player::Red) );
    assert_eq!(game.make_turn(0), Err(GameError::AlreadyEnded) );
}

#[test]
fn test_row_win() {
    let mut game = Game::new();
    game.make_turn(0).unwrap();
    println!("");
    println!("{:?}", &game.field.cells);
    game.make_turn(0).unwrap();
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    assert_eq!(game.winner(), Some(Player::Red) );
    assert_eq!(game.make_turn(0), Err(GameError::AlreadyEnded) );
}

#[test]
fn test_column_win() {
    let mut game = Game::new();
    game.make_turn(0).unwrap();
    println!("");
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    game.make_turn(0).unwrap();
    println!("{:?}", &game.field.cells);
    assert_eq!(game.winner(), Some(Player::Red) );
    assert_eq!(game.make_turn(0), Err(GameError::AlreadyEnded) );
}

#[test]
fn test_max_series() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    assert_eq!(Field::max_series(&[]), (None, 0));
    assert_eq!(Field::max_series(&[None, None]), (None, 0));
    assert_eq!(Field::max_series(&[red]), (red, 1));
    assert_eq!(Field::max_series(&[blue]), (blue, 1));
    assert_eq!(Field::max_series(&[red, blue]), (None, 1));
    assert_eq!(Field::max_series(&[red, red, blue]), (red, 2));
    assert_eq!(Field::max_series(&[red, red, None, red, red, red]), (red, 3));
    assert_eq!(Field::max_series(&[blue, blue, None, red, red, red]), (red, 3));
    assert_eq!(Field::max_series(&[blue, blue, None, red, red, red, blue, blue, blue]), (None, 3));
}

#[test]
fn test_rows_iterator() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    let cells = &[red,  None, blue, None,
    			  None, red,  blue, red,
    			  None, None, None, None,];
    let mut rows = Rows::new(cells);
    let row1 = rows.next().unwrap();
    let row2 = rows.next().unwrap();
    let row3 = rows.next().unwrap();
    assert!(rows.next().is_none());

    assert_eq!(row1.cells, [red,  None, blue, None] );
    assert_eq!(row2.cells, [None, red,  blue, red] );
    assert_eq!(row3.cells, [None, None, None, None] );
}

#[test]
fn test_columns_iterator() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    let cells = &[red,  None, blue, None,
    			  None, red,  blue, red,
    			  None, None, None, None,];

    let mut columns = Columns::new(&cells);
    let column1 = columns.next().unwrap();
    let column2 = columns.next().unwrap();
    let column3 = columns.next().unwrap();
    let column4 = columns.next().unwrap();
    assert!(columns.next().is_none());

    assert_eq!(column1.cells, [red,  None, None] );
    assert_eq!(column2.cells, [None, red,  None] );
    assert_eq!(column3.cells, [blue, blue, None] );
    assert_eq!(column4.cells, [None, red,  None] );
}

#[test]
fn test_diagonal_iterator() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    let cells = &[red,  None, blue, None,
    			  None, red,  blue, red,
    			  None, None, None, None,];

	let mut diagonals = Diagonals::new(&cells);
	let d1 = diagonals.next().unwrap();
	let d2 = diagonals.next().unwrap();
	let d3 = diagonals.next().unwrap();
	let d4 = diagonals.next().unwrap();

	let d5 = diagonals.next().unwrap();
	let d6 = diagonals.next().unwrap();
	let d7 = diagonals.next().unwrap();
	let d8 = diagonals.next().unwrap();

	assert!( diagonals.next().is_none() );

	fn check(d: Diagonal, cells: [Option<Player>; WIDTH + HEIGHT], length: usize) {
	    assert_eq!((d.cells, d.length), (cells, length) );
	}

	check(d1, [None, None, None, None, None, None, None], 2);
	check(d2, [blue, red, None, None, None, None, None], 3);
	check(d3, [None, blue, None, None, None, None, None], 3);
	check(d4, [red, None, None, None, None, None, None], 2);

	check(d5, [None, None, None, None, None, None, None], 2);
	check(d6, [red, red, None, None, None, None, None], 3);
	check(d7, [None, blue, None, None, None, None, None], 3);
	check(d8, [blue, red, None, None, None, None, None], 2);

}
<commit_msg>Added 'possible_moves' fn to game, removed pub visibility for Field<commit_after>#[cfg(not(test))] pub const WIDTH: usize = 5;
#[cfg(not(test))] pub const HEIGHT: usize = 5;
#[cfg(not(test))] pub const X_ROW: usize = 4;

#[cfg(test)] pub const WIDTH: usize = 4;
#[cfg(test)] pub const HEIGHT: usize = 3;
#[cfg(test)] pub const X_ROW: usize = 2;

pub struct Game {
    turns: u32,
    current_turn: Player,
    winner: Option<Player>,
    field: Field,
}

impl Game {
    pub fn new() -> Game {
        Game {
            turns: 0,
            current_turn: Player::Red,
            winner : None,
		    field: Field::new(),
		}
    }

    pub fn current_turn(&self) -> Player {
        self.current_turn
    }

    pub fn winner(&self) -> Option<Player> {
        self.winner
    }

    pub fn is_full(&self) -> bool {
        self.turns as usize == WIDTH * HEIGHT
    }

    pub fn make_turn(&mut self, column: usize) -> Result<(), GameError> {
        if self.winner.is_some() { return Err(GameError::AlreadyEnded); }
        try!(self.field.throw_token(column, self.current_turn));
        self.winner = self.field.win_check();
        self.turns += 1;
        self.current_turn = self.current_turn.next();
        Ok(())
    }

    pub fn current_state(&self) -> &[Option<Player>; WIDTH * HEIGHT] {
        &self.field.cells
    }

    pub fn possible_moves(&self) -> Vec<usize> {
        if !self.is_full() {
            self.field.possible_moves()
        } else {
            Vec::new()
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GameError {
    NoSuchColumn,
    ColumnIsFull,
    AlreadyEnded,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Player {
    Red,
    Blue,
}

impl Player {
    fn next(self) -> Player {
        match self {
            Player::Red => Player::Blue,
            Player::Blue => Player::Red,
        }
    }
}

struct Field {
    cells: [Option<Player>; WIDTH * HEIGHT],
}

impl Field {

    fn possible_moves(&self) -> Vec<usize> {
        let mut res = Vec::new();

        for (index, Column { cells }) in self.columns().enumerate() {
            if cells.iter().any(|x| x.is_none()) {
                res.push(index);
            }
        }

        res
    }

    fn new() -> Field {
        Field {
		    cells: [None; (WIDTH * HEIGHT) as usize],
		}
    }

    fn throw_token(&mut self, column_index: usize, player: Player) -> Result<(), GameError> {
        if column_index > WIDTH { return Err(GameError::NoSuchColumn); }
        let Column { cells } = Columns::index(&self.cells, column_index).next().unwrap();
        let row_index = try!( cells.iter().position(|x| x.is_none() ).ok_or(GameError::ColumnIsFull) );
        let position = row_index * WIDTH + column_index;
        self.cells[position] = Some(player);
        Ok(())
    }

    fn win_check(&self) -> Option<Player> {
        for Row { cells } in self.rows() {
            match Field::max_series(&cells[..]) {
                (Some(player), length) => {
                	if length >= X_ROW {
                	    return Some(player);
                	}
                },
                _ => {}
            }
        }

        for Column { cells } in self.columns() {
            match Field::max_series(&cells[..]) {
                (Some(player), length) => {
                	if length >= X_ROW {
                	    return Some(player);
                	}
                },
                _ => {}
            }
        }

        for Diagonal { cells, length } in self.diagonals() {
            match Field::max_series(&cells[0..length]) {
                (Some(player), length) => {
                	if length >= X_ROW {
                	    return Some(player);
                	}
                },
                _ => {}
            }
        }

        None
    }

    fn rows<'a>(&'a self) -> Rows<'a>{
        Rows::new(&self.cells)
    }

    fn columns<'a, 'b>(&'a self) -> Columns<'a> {
        Columns::new(&self.cells)
    }

    fn diagonals<'a>(&'a self) -> Diagonals<'a> {
        Diagonals::new(&self.cells)
    }

    fn max_series(cells: &[Option<Player>]) -> (Option<Player>, usize) {
        const RED: Option<Player> = Some(Player::Red);
        const BLUE: Option<Player> = Some(Player::Blue);
        let mut red_max = 0;
        let mut blue_max = 0;
        let mut prev_player = None;
        let mut series = 0;

        for curr_player in cells.iter() {
            match (*curr_player, prev_player) {
                (Some(_), None) => { series = 1; },
                (RED, RED) | (BLUE, BLUE) => { series += 1; },
                (None, RED) | (BLUE, RED) => {
					if series > red_max { red_max = series; }
					series = 1;
				},
                (None, BLUE) | (RED, BLUE) => {
					if series > blue_max { blue_max = series; }
					series = 1;
				},
                _ => {}
            }
            prev_player = *curr_player;
        }

        match prev_player {
            BLUE => if series > blue_max { blue_max = series; },
            RED  => if series > red_max { red_max = series; },
            _ => {},
        }

        if red_max == blue_max { return (None, red_max); }
        if red_max > blue_max { return (RED, red_max); } else { return (BLUE, blue_max); }
    }
}

struct Rows<'a> {
    field: &'a [Option<Player>; WIDTH * HEIGHT],
    current_row: usize,
}

impl<'a> Rows<'a> {
    fn new(field: &'a [Option<Player>; WIDTH * HEIGHT]) -> Rows<'a> {
        Rows {
		    field: field,
		    current_row: 0,
		}
    }
}

impl<'a> Iterator for Rows<'a> {
    type Item = Row;

    fn next(&mut self) -> Option<Row> {
        if self.current_row < HEIGHT {
            let from = self.current_row * WIDTH;
            let to = from + WIDTH;
            let mut cells = [None; WIDTH];
            for (val, index) in (&self.field[from .. to]).iter().zip(0..WIDTH) {
                cells[index] = *val;
            }
            self.current_row += 1;
            Some( Row { cells: cells} )
        } else {
            None
        }
    }
}

struct Row {
    cells: [Option<Player>; WIDTH],
}

struct Columns<'a> {
    field: &'a [Option<Player>; WIDTH * HEIGHT],
    current_column: usize,
}

impl<'a> Columns<'a> {
    fn new(field: &'a [Option<Player>; WIDTH * HEIGHT]) -> Columns<'a> {
        Columns {
		    field: field,
			current_column: 0,
		}
    }

    fn index(field: &'a [Option<Player>; WIDTH * HEIGHT], index: usize) -> Columns<'a> {
        Columns {
            field: field,
            current_column: index,
		}
    }
}

impl<'a> Iterator for Columns<'a> {
    type Item = Column;

    fn next(&mut self) -> Option<Column> {
        if self.current_column < WIDTH {
            let mut cells = [None; HEIGHT];
            for i in 0..HEIGHT {
                let index: usize = (i * WIDTH as usize) + self.current_column as usize;
                cells[i] = self.field[index];
            }
            self.current_column += 1;
            Some( Column { cells: cells} )
        } else {
            None
        }
    }
}

struct Column {
    cells: [Option<Player>; HEIGHT],
}

struct Diagonals<'a> {
    field: &'a [Option<Player>; WIDTH * HEIGHT],
    current_diagonal : usize,
    total_diagonals: usize,
}

impl<'a> Diagonals<'a> {
    fn new(field: &'a [Option<Player>; WIDTH * HEIGHT]) -> Diagonals<'a> {
        Diagonals {
		    field: field,
		    current_diagonal: 0,
		    total_diagonals: WIDTH + HEIGHT - 3,
		}
    }
}

impl<'a> Iterator for Diagonals<'a> {
    type Item = Diagonal;

    fn next(&mut self) -> Option<Diagonal> {
        if WIDTH == 1 || HEIGHT == 1 { return None; }
        if self.total_diagonals >= self.current_diagonal { return None; }
        None
    }
}

struct Diagonal {
    cells: [Option<Player>; WIDTH + HEIGHT],
    length: usize,
}

#[test]
fn test_possible_moves() {
    let mut game = Game::new();
    assert_eq!(game.possible_moves(), vec![0, 1, 2, 3]);
    game.make_turn(0).unwrap();
    game.make_turn(0).unwrap();
    game.make_turn(0).unwrap();
    assert_eq!(game.possible_moves(), vec![1, 2, 3]);
    game.make_turn(2).unwrap();
    game.make_turn(2).unwrap();
    game.make_turn(2).unwrap();
    assert_eq!(game.possible_moves(), vec![1, 3]);
    game.make_turn(3).unwrap();
    game.make_turn(1).unwrap();
    assert_eq!(game.possible_moves(), vec![1, 3]);
}

#[test]
fn test_diagonal_win() {
    let mut game = Game::new();
    game.make_turn(0).unwrap();
    println!("");
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    assert_eq!(game.winner(), Some(Player::Red) );
    assert_eq!(game.make_turn(0), Err(GameError::AlreadyEnded) );
}

#[test]
fn test_row_win() {
    let mut game = Game::new();
    game.make_turn(0).unwrap();
    println!("");
    println!("{:?}", &game.field.cells);
    game.make_turn(0).unwrap();
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    assert_eq!(game.winner(), Some(Player::Red) );
    assert_eq!(game.make_turn(0), Err(GameError::AlreadyEnded) );
}

#[test]
fn test_column_win() {
    let mut game = Game::new();
    game.make_turn(0).unwrap();
    println!("");
    println!("{:?}", &game.field.cells);
    game.make_turn(1).unwrap();
    println!("{:?}", &game.field.cells);
    game.make_turn(0).unwrap();
    println!("{:?}", &game.field.cells);
    assert_eq!(game.winner(), Some(Player::Red) );
    assert_eq!(game.make_turn(0), Err(GameError::AlreadyEnded) );
}

#[test]
fn test_max_series() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    assert_eq!(Field::max_series(&[]), (None, 0));
    assert_eq!(Field::max_series(&[None, None]), (None, 0));
    assert_eq!(Field::max_series(&[red]), (red, 1));
    assert_eq!(Field::max_series(&[blue]), (blue, 1));
    assert_eq!(Field::max_series(&[red, blue]), (None, 1));
    assert_eq!(Field::max_series(&[red, red, blue]), (red, 2));
    assert_eq!(Field::max_series(&[red, red, None, red, red, red]), (red, 3));
    assert_eq!(Field::max_series(&[blue, blue, None, red, red, red]), (red, 3));
    assert_eq!(Field::max_series(&[blue, blue, None, red, red, red, blue, blue, blue]), (None, 3));
}

#[test]
fn test_rows_iterator() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    let cells = &[red,  None, blue, None,
    			  None, red,  blue, red,
    			  None, None, None, None,];
    let mut rows = Rows::new(cells);
    let row1 = rows.next().unwrap();
    let row2 = rows.next().unwrap();
    let row3 = rows.next().unwrap();
    assert!(rows.next().is_none());

    assert_eq!(row1.cells, [red,  None, blue, None] );
    assert_eq!(row2.cells, [None, red,  blue, red] );
    assert_eq!(row3.cells, [None, None, None, None] );
}

#[test]
fn test_columns_iterator() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    let cells = &[red,  None, blue, None,
    			  None, red,  blue, red,
    			  None, None, None, None,];

    let mut columns = Columns::new(&cells);
    let column1 = columns.next().unwrap();
    let column2 = columns.next().unwrap();
    let column3 = columns.next().unwrap();
    let column4 = columns.next().unwrap();
    assert!(columns.next().is_none());

    assert_eq!(column1.cells, [red,  None, None] );
    assert_eq!(column2.cells, [None, red,  None] );
    assert_eq!(column3.cells, [blue, blue, None] );
    assert_eq!(column4.cells, [None, red,  None] );
}

#[test]
fn test_diagonal_iterator() {
    let red = Some(Player::Red);
    let blue = Some(Player::Blue);
    let cells = &[red,  None, blue, None,
    			  None, red,  blue, red,
    			  None, None, None, None,];

	let mut diagonals = Diagonals::new(&cells);
	let d1 = diagonals.next().unwrap();
	let d2 = diagonals.next().unwrap();
	let d3 = diagonals.next().unwrap();
	let d4 = diagonals.next().unwrap();

	let d5 = diagonals.next().unwrap();
	let d6 = diagonals.next().unwrap();
	let d7 = diagonals.next().unwrap();
	let d8 = diagonals.next().unwrap();

	assert!( diagonals.next().is_none() );

	fn check(d: Diagonal, cells: [Option<Player>; WIDTH + HEIGHT], length: usize) {
	    assert_eq!((d.cells, d.length), (cells, length) );
	}

	check(d1, [None, None, None, None, None, None, None], 2);
	check(d2, [blue, red, None, None, None, None, None], 3);
	check(d3, [None, blue, None, None, None, None, None], 3);
	check(d4, [red, None, None, None, None, None, None], 2);

	check(d5, [None, None, None, None, None, None, None], 2);
	check(d6, [red, red, None, None, None, None, None], 3);
	check(d7, [None, blue, None, None, None, None, None], 3);
	check(d8, [blue, red, None, None, None, None, None], 2);

}
<|endoftext|>


<commit_before>//! Core I/O traits and combinators when working with Tokio.
//!
//! A description of the high-level I/O combinators can be [found online] in
//! addition to a description of the [low level details].
//!
//! [found online]: https://tokio.rs/docs/getting-started/core/
//! [low level details]: https://tokio.rs/docs/going-deeper-tokio/core-low-level/

#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-io/0.1")]

#[macro_use]
extern crate log;

#[macro_use]
extern crate futures;
extern crate bytes;

use std::io as std_io;
use std::io::Write;

use futures::{Async, Poll};
use futures::future::BoxFuture;
use futures::stream::BoxStream;

use bytes::{Buf, BufMut};

/// A convenience typedef around a `Future` whose error component is `io::Error`
pub type IoFuture<T> = BoxFuture<T, std_io::Error>;

/// A convenience typedef around a `Stream` whose error component is `io::Error`
pub type IoStream<T> = BoxStream<T, std_io::Error>;

/// A convenience macro for working with `io::Result<T>` from the `Read` and
/// `Write` traits.
///
/// This macro takes `io::Result<T>` as input, and returns `T` as the output. If
/// the input type is of the `Err` variant, then `Poll::NotReady` is returned if
/// it indicates `WouldBlock` or otherwise `Err` is returned.
#[macro_export]
macro_rules! try_nb {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => {
            return Ok(::futures::Async::NotReady)
        }
        Err(e) => return Err(e.into()),
    })
}

pub mod io;
pub mod codec;

mod copy;
mod flush;
mod framed;
mod framed_read;
mod framed_write;
mod length_delimited;
mod lines;
mod read;
mod read_exact;
mod read_to_end;
mod read_until;
mod shutdown;
mod split;
mod window;
mod write_all;

use codec::{Decoder, Encoder, Framed};
use split::{ReadHalf, WriteHalf};

/// A trait for readable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Read` and indicates as a marker that an I/O
/// object is **nonblocking**, meaning that it will return an error instead of
/// blocking when bytes are unavailable, but the stream hasn't reached EOF.
/// Specifically this means that the `read` function for traits that implement
/// this type can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately read and placed into
///   the output buffer, where `n` == 0 implies that EOF has been reached.
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was read
///   into the buffer provided. The I/O object is not currently readable but may
///   become readable in the future. Most importantly, **the current future's
///   task is scheduled to get unparked when the object is readable**. This
///   means that like `Future::poll` you'll receive a notification when the I/O
///   object is readable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncRead: std_io::Read {
    /// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
    /// `true` if the supplied buffer was zeroed out.
    ///
    /// While it would be highly unusual, implementations of [`io::Read`] are
    /// able to read data from the buffer passed as an argument. Because of
    /// this, the buffer passed to [`io::Read`] must be initialized memory. In
    /// situations where large numbers of buffers are used, constantly having to
    /// zero out buffers can be expensive.
    ///
    /// This function does any necessary work to prepare an uninitialized buffer
    /// to be safe to pass to `read`. If `read` guarantees to never attempt read
    /// data out of the supplied buffer, then `prepare_uninitialized_buffer`
    /// doesn't need to do any work.
    ///
    /// If this function returns `true`, then the memory has been zeroed out.
    /// This allows implementations of `AsyncRead` which are composed of
    /// multiple sub implementations to efficiently implement
    /// `prepare_uninitialized_buffer`.
    ///
    /// This function isn't actually `unsafe` to call but `unsafe` to implement.
    /// The implementor must ensure that either the whole `buf` has been zeroed
    /// or `read_buf()` overwrites the buffer without reading it and returns
    /// correct value.
    ///
    /// This function is called from [`read_buf`].
    ///
    /// [`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
    /// [`read_buf`]: #method.read_buf
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        for i in 0..buf.len() {
            buf[i] = 0;
        }

        true
    }

    /// Pull some bytes from this source into the specified `Buf`, returning
    /// how many bytes were read.
    ///
    /// The `buf` provided will have bytes read into it and the internal cursor
    /// will be advanced if any bytes were read. Note that this method typically
    /// will not reallocate the buffer provided.
    fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining_mut() {
            return Ok(Async::Ready(0));
        }

        unsafe {
            let n = {
                let b = buf.bytes_mut();

                self.prepare_uninitialized_buffer(b);

                try_nb!(self.read(b))
            };

            buf.advance_mut(n);
            Ok(Async::Ready(n))
        }
    }

    /// Provides a `Stream` and `Sink` interface for reading and writing to this
    /// `Io` object, using `Decode` and `Encode` to read and write the raw data.
    ///
    /// Raw I/O objects work with byte sequences, but higher-level code usually
    /// wants to batch these into meaningful chunks, called "frames". This
    /// method layers framing on top of an I/O object, by using the `Codec`
    /// traits to handle encoding and decoding of messages frames. Note that
    /// the incoming and outgoing frame types may be distinct.
    ///
    /// This function returns a *single* object that is both `Stream` and
    /// `Sink`; grouping this into a single object is often useful for layering
    /// things like gzip or TLS, which require both read and write access to the
    /// underlying object.
    ///
    /// If you want to work more directly with the streams and sink, consider
    /// calling `split` on the `Framed` returned by this method, which will
    /// break them into separate objects, allowing them to interact more easily.
    fn framed<T: Encoder + Decoder>(self, codec: T) -> Framed<Self, T>
        where Self: AsyncWrite + Sized,
    {
        framed::framed(self, codec)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `Read` and `Write` traits,
    /// respectively.
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }
}

impl<T: ?Sized + AsyncRead> AsyncRead for Box<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a, T: ?Sized + AsyncRead> AsyncRead for &'a mut T {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a> AsyncRead for &'a [u8] {
    unsafe fn prepare_uninitialized_buffer(&self, _buf: &mut [u8]) -> bool {
        false
    }
}

/// A trait for writable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Write` and indicates that an I/O object is
/// **nonblocking**, meaning that it will return an error instead of blocking
/// when bytes cannot currently be written, but hasn't closed. Specifically
/// this means that the `write` function for traits that implement this type
/// can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately written .
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was
///   written from the buffer provided. The I/O object is not currently
///   writable but may become writable in the future. Most importantly, **the
///   current future's task is scheduled to get unparked when the object is
///   readable**. This means that like `Future::poll` you'll receive a
///   notification when the I/O object is writable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `write` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncWrite: std_io::Write {
    /// Initiates or attempts to shut down this writer, returning success when
    /// the I/O connection has completely shut down.
    ///
    /// This method is intended to be used for asynchronous shutdown of I/O
    /// connections. For example this is suitable for implementing shutdown of a
    /// TLS connection or calling `TcpStream::shutdown` on a proxied connection.
    /// Protocols sometimes need to flush out final pieces of data or otherwise
    /// perform a graceful shutdown handshake, reading/writing more data as
    /// appropriate. This method is the hook for such protocols to implement the
    /// graceful shutdown logic.
    ///
    /// This `shutdown` method is required by implementors of the
    /// `AsyncWrite` trait. Wrappers typically just want to proxy this call
    /// through to the wrapped type, and base types will typically implement
    /// shutdown logic here or just return `Ok(().into())`. Note that if you're
    /// wrapping an underlying `AsyncWrite` a call to `shutdown` implies that
    /// transitively the entire stream has been shut down. After your wrapper's
    /// shutdown logic has been executed you should shut down the underlying
    /// stream.
    ///
    /// Invocation of a `shutdown` implies an invocation of `flush`. Once this
    /// method returns `Ready` it implies that a flush successfully happened
    /// before the shutdown happened. That is, callers don't need to call
    /// `flush` before calling `shutdown`. They can rely that by calling
    /// `shutdown` any pending buffered data will be written out.
    ///
    /// # Return value
    ///
    /// This function returns a `Poll<(), io::Error>` classified as such:
    ///
    /// * `Ok(Async::Ready(()))` - indicates that the connection was
    ///   successfully shut down and is now safe to deallocate/drop/close
    ///   resources associated with it. This method means that the current task
    ///   will no longer receive any notifications due to this method and the
    ///   I/O object itself is likely no longer usable.
    ///
    /// * `Ok(Async::NotReady)` - indicates that shutdown is initiated but could
    ///   not complete just yet. This may mean that more I/O needs to happen to
    ///   continue this shutdown operation. The current task is scheduled to
    ///   receive a notification when it's otherwise ready to continue the
    ///   shutdown operation. When woken up this method should be called again.
    ///
    /// * `Err(e)` - indicates a fatal error has happened with shutdown,
    ///   indicating that the shutdown operation did not complete successfully.
    ///   This typically means that the I/O object is no longer usable.
    ///
    /// # Errors
    ///
    /// This function can return normal I/O errors through `Err`, described
    /// above. Additionally this method may also render the underlying
    /// `Write::write` method no longer usable (e.g. will return errors in the
    /// future). It's recommended that once `shutdown` is called the
    /// `write` method is no longer called.
    ///
    /// # Panics
    ///
    /// This function will panic if not called within the context of a future's
    /// task.
    fn shutdown(&mut self) -> Poll<(), std_io::Error>;

    /// Write a `Buf` into this value, returning how many bytes were written.
    ///
    /// Note that this method will advance the `buf` provided automatically by
    /// the number of bytes written.
    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining() {
            return Ok(Async::Ready(0));
        }

        let n = try_nb!(self.write(buf.bytes()));
        buf.advance(n);
        Ok(Async::Ready(n))
    }
}

impl<T: ?Sized + AsyncWrite> AsyncWrite for Box<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}
impl<'a, T: ?Sized + AsyncWrite> AsyncWrite for &'a mut T {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}

impl AsyncRead for std_io::Repeat {
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        false
    }
}

impl AsyncWrite for std_io::Sink {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

// TODO: Implement `prepare_uninitialized_buffer` for `io::Take`.
// This is blocked on rust-lang/rust#27269
impl<T: AsyncRead> AsyncRead for std_io::Take<T> {
}

// TODO: Implement `prepare_uninitialized_buffer` when upstream exposes inner
// parts
impl<T, U> AsyncRead for std_io::Chain<T, U>
    where T: AsyncRead,
          U: AsyncRead,
{
}

impl<T: AsyncWrite> AsyncWrite for std_io::BufWriter<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        try_nb!(self.flush());
        self.get_mut().shutdown()
    }
}

impl<T: AsyncRead> AsyncRead for std_io::BufReader<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        self.get_ref().prepare_uninitialized_buffer(buf)
    }
}

impl<T: AsRef<[u8]>> AsyncRead for std_io::Cursor<T> {
}

impl<'a> AsyncWrite for std_io::Cursor<&'a mut [u8]> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Vec<u8>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Box<[u8]>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

fn _assert_objects() {
    fn _assert<T>() {}
    _assert::<Box<AsyncRead>>();
    _assert::<Box<AsyncWrite>>();
}
<commit_msg>Fix doc for AsyncRead and AsyncWrite<commit_after>//! Core I/O traits and combinators when working with Tokio.
//!
//! A description of the high-level I/O combinators can be [found online] in
//! addition to a description of the [low level details].
//!
//! [found online]: https://tokio.rs/docs/getting-started/core/
//! [low level details]: https://tokio.rs/docs/going-deeper-tokio/core-low-level/

#![deny(missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/tokio-io/0.1")]

#[macro_use]
extern crate log;

#[macro_use]
extern crate futures;
extern crate bytes;

use std::io as std_io;
use std::io::Write;

use futures::{Async, Poll};
use futures::future::BoxFuture;
use futures::stream::BoxStream;

use bytes::{Buf, BufMut};

/// A convenience typedef around a `Future` whose error component is `io::Error`
pub type IoFuture<T> = BoxFuture<T, std_io::Error>;

/// A convenience typedef around a `Stream` whose error component is `io::Error`
pub type IoStream<T> = BoxStream<T, std_io::Error>;

/// A convenience macro for working with `io::Result<T>` from the `Read` and
/// `Write` traits.
///
/// This macro takes `io::Result<T>` as input, and returns `T` as the output. If
/// the input type is of the `Err` variant, then `Poll::NotReady` is returned if
/// it indicates `WouldBlock` or otherwise `Err` is returned.
#[macro_export]
macro_rules! try_nb {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(ref e) if e.kind() == ::std::io::ErrorKind::WouldBlock => {
            return Ok(::futures::Async::NotReady)
        }
        Err(e) => return Err(e.into()),
    })
}

pub mod io;
pub mod codec;

mod copy;
mod flush;
mod framed;
mod framed_read;
mod framed_write;
mod length_delimited;
mod lines;
mod read;
mod read_exact;
mod read_to_end;
mod read_until;
mod shutdown;
mod split;
mod window;
mod write_all;

use codec::{Decoder, Encoder, Framed};
use split::{ReadHalf, WriteHalf};

/// A trait for readable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Read` and indicates as a marker that an I/O
/// object is **nonblocking**, meaning that it will return an error instead of
/// blocking when bytes are unavailable, but the stream hasn't reached EOF.
/// Specifically this means that the `read` function for types that implement
/// this trait can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately read and placed into
///   the output buffer, where `n` == 0 implies that EOF has been reached.
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was read
///   into the buffer provided. The I/O object is not currently readable but may
///   become readable in the future. Most importantly, **the current future's
///   task is scheduled to get unparked when the object is readable**. This
///   means that like `Future::poll` you'll receive a notification when the I/O
///   object is readable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncRead: std_io::Read {
    /// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
    /// `true` if the supplied buffer was zeroed out.
    ///
    /// While it would be highly unusual, implementations of [`io::Read`] are
    /// able to read data from the buffer passed as an argument. Because of
    /// this, the buffer passed to [`io::Read`] must be initialized memory. In
    /// situations where large numbers of buffers are used, constantly having to
    /// zero out buffers can be expensive.
    ///
    /// This function does any necessary work to prepare an uninitialized buffer
    /// to be safe to pass to `read`. If `read` guarantees to never attempt read
    /// data out of the supplied buffer, then `prepare_uninitialized_buffer`
    /// doesn't need to do any work.
    ///
    /// If this function returns `true`, then the memory has been zeroed out.
    /// This allows implementations of `AsyncRead` which are composed of
    /// multiple sub implementations to efficiently implement
    /// `prepare_uninitialized_buffer`.
    ///
    /// This function isn't actually `unsafe` to call but `unsafe` to implement.
    /// The implementor must ensure that either the whole `buf` has been zeroed
    /// or `read_buf()` overwrites the buffer without reading it and returns
    /// correct value.
    ///
    /// This function is called from [`read_buf`].
    ///
    /// [`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
    /// [`read_buf`]: #method.read_buf
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        for i in 0..buf.len() {
            buf[i] = 0;
        }

        true
    }

    /// Pull some bytes from this source into the specified `Buf`, returning
    /// how many bytes were read.
    ///
    /// The `buf` provided will have bytes read into it and the internal cursor
    /// will be advanced if any bytes were read. Note that this method typically
    /// will not reallocate the buffer provided.
    fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining_mut() {
            return Ok(Async::Ready(0));
        }

        unsafe {
            let n = {
                let b = buf.bytes_mut();

                self.prepare_uninitialized_buffer(b);

                try_nb!(self.read(b))
            };

            buf.advance_mut(n);
            Ok(Async::Ready(n))
        }
    }

    /// Provides a `Stream` and `Sink` interface for reading and writing to this
    /// `Io` object, using `Decode` and `Encode` to read and write the raw data.
    ///
    /// Raw I/O objects work with byte sequences, but higher-level code usually
    /// wants to batch these into meaningful chunks, called "frames". This
    /// method layers framing on top of an I/O object, by using the `Codec`
    /// traits to handle encoding and decoding of messages frames. Note that
    /// the incoming and outgoing frame types may be distinct.
    ///
    /// This function returns a *single* object that is both `Stream` and
    /// `Sink`; grouping this into a single object is often useful for layering
    /// things like gzip or TLS, which require both read and write access to the
    /// underlying object.
    ///
    /// If you want to work more directly with the streams and sink, consider
    /// calling `split` on the `Framed` returned by this method, which will
    /// break them into separate objects, allowing them to interact more easily.
    fn framed<T: Encoder + Decoder>(self, codec: T) -> Framed<Self, T>
        where Self: AsyncWrite + Sized,
    {
        framed::framed(self, codec)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `Read` and `Write` traits,
    /// respectively.
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }
}

impl<T: ?Sized + AsyncRead> AsyncRead for Box<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a, T: ?Sized + AsyncRead> AsyncRead for &'a mut T {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        (**self).prepare_uninitialized_buffer(buf)
    }
}

impl<'a> AsyncRead for &'a [u8] {
    unsafe fn prepare_uninitialized_buffer(&self, _buf: &mut [u8]) -> bool {
        false
    }
}

/// A trait for writable objects which operated in an asynchronous and
/// futures-aware fashion.
///
/// This trait inherits from `io::Write` and indicates that an I/O object is
/// **nonblocking**, meaning that it will return an error instead of blocking
/// when bytes cannot currently be written, but hasn't closed. Specifically
/// this means that the `write` function for types that implement this trait
/// can have a few return values:
///
/// * `Ok(n)` means that `n` bytes of data was immediately written .
/// * `Err(e) if e.kind() == ErrorKind::WouldBlock` means that no data was
///   written from the buffer provided. The I/O object is not currently
///   writable but may become writable in the future. Most importantly, **the
///   current future's task is scheduled to get unparked when the object is
///   readable**. This means that like `Future::poll` you'll receive a
///   notification when the I/O object is writable again.
/// * `Err(e)` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `write` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncWrite: std_io::Write {
    /// Initiates or attempts to shut down this writer, returning success when
    /// the I/O connection has completely shut down.
    ///
    /// This method is intended to be used for asynchronous shutdown of I/O
    /// connections. For example this is suitable for implementing shutdown of a
    /// TLS connection or calling `TcpStream::shutdown` on a proxied connection.
    /// Protocols sometimes need to flush out final pieces of data or otherwise
    /// perform a graceful shutdown handshake, reading/writing more data as
    /// appropriate. This method is the hook for such protocols to implement the
    /// graceful shutdown logic.
    ///
    /// This `shutdown` method is required by implementors of the
    /// `AsyncWrite` trait. Wrappers typically just want to proxy this call
    /// through to the wrapped type, and base types will typically implement
    /// shutdown logic here or just return `Ok(().into())`. Note that if you're
    /// wrapping an underlying `AsyncWrite` a call to `shutdown` implies that
    /// transitively the entire stream has been shut down. After your wrapper's
    /// shutdown logic has been executed you should shut down the underlying
    /// stream.
    ///
    /// Invocation of a `shutdown` implies an invocation of `flush`. Once this
    /// method returns `Ready` it implies that a flush successfully happened
    /// before the shutdown happened. That is, callers don't need to call
    /// `flush` before calling `shutdown`. They can rely that by calling
    /// `shutdown` any pending buffered data will be written out.
    ///
    /// # Return value
    ///
    /// This function returns a `Poll<(), io::Error>` classified as such:
    ///
    /// * `Ok(Async::Ready(()))` - indicates that the connection was
    ///   successfully shut down and is now safe to deallocate/drop/close
    ///   resources associated with it. This method means that the current task
    ///   will no longer receive any notifications due to this method and the
    ///   I/O object itself is likely no longer usable.
    ///
    /// * `Ok(Async::NotReady)` - indicates that shutdown is initiated but could
    ///   not complete just yet. This may mean that more I/O needs to happen to
    ///   continue this shutdown operation. The current task is scheduled to
    ///   receive a notification when it's otherwise ready to continue the
    ///   shutdown operation. When woken up this method should be called again.
    ///
    /// * `Err(e)` - indicates a fatal error has happened with shutdown,
    ///   indicating that the shutdown operation did not complete successfully.
    ///   This typically means that the I/O object is no longer usable.
    ///
    /// # Errors
    ///
    /// This function can return normal I/O errors through `Err`, described
    /// above. Additionally this method may also render the underlying
    /// `Write::write` method no longer usable (e.g. will return errors in the
    /// future). It's recommended that once `shutdown` is called the
    /// `write` method is no longer called.
    ///
    /// # Panics
    ///
    /// This function will panic if not called within the context of a future's
    /// task.
    fn shutdown(&mut self) -> Poll<(), std_io::Error>;

    /// Write a `Buf` into this value, returning how many bytes were written.
    ///
    /// Note that this method will advance the `buf` provided automatically by
    /// the number of bytes written.
    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, std_io::Error>
        where Self: Sized,
    {
        if !buf.has_remaining() {
            return Ok(Async::Ready(0));
        }

        let n = try_nb!(self.write(buf.bytes()));
        buf.advance(n);
        Ok(Async::Ready(n))
    }
}

impl<T: ?Sized + AsyncWrite> AsyncWrite for Box<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}
impl<'a, T: ?Sized + AsyncWrite> AsyncWrite for &'a mut T {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        (**self).shutdown()
    }
}

impl AsyncRead for std_io::Repeat {
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        false
    }
}

impl AsyncWrite for std_io::Sink {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

// TODO: Implement `prepare_uninitialized_buffer` for `io::Take`.
// This is blocked on rust-lang/rust#27269
impl<T: AsyncRead> AsyncRead for std_io::Take<T> {
}

// TODO: Implement `prepare_uninitialized_buffer` when upstream exposes inner
// parts
impl<T, U> AsyncRead for std_io::Chain<T, U>
    where T: AsyncRead,
          U: AsyncRead,
{
}

impl<T: AsyncWrite> AsyncWrite for std_io::BufWriter<T> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        try_nb!(self.flush());
        self.get_mut().shutdown()
    }
}

impl<T: AsyncRead> AsyncRead for std_io::BufReader<T> {
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
        self.get_ref().prepare_uninitialized_buffer(buf)
    }
}

impl<T: AsRef<[u8]>> AsyncRead for std_io::Cursor<T> {
}

impl<'a> AsyncWrite for std_io::Cursor<&'a mut [u8]> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Vec<u8>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

impl AsyncWrite for std_io::Cursor<Box<[u8]>> {
    fn shutdown(&mut self) -> Poll<(), std_io::Error> {
        Ok(().into())
    }
}

fn _assert_objects() {
    fn _assert<T>() {}
    _assert::<Box<AsyncRead>>();
    _assert::<Box<AsyncWrite>>();
}
<|endoftext|>


<commit_before>//! Implementation of OAuth 1.0 in accordance with [RFC 5849](http://tools.ietf.org/html/rfc5849)

#[unstable]
pub mod crypto;

#[unstable]
pub mod oauth1;
<commit_msg>added feature blocks to remove compiler warnings<commit_after>//! Implementation of OAuth 1.0 in accordance with [RFC 5849](http://tools.ietf.org/html/rfc5849)
#![feature(core, collections, rand)]

#[unstable]
pub mod crypto;

#[unstable]
pub mod oauth1;
<|endoftext|>


<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionalty to the linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.get_path().unwrap().display());
//!
//! ld.attach("test.img", 0).unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};
use std::default::Default;

static LOOP_SET_FD: u64 = 0x4C00;
static LOOP_CLR_FD: u64 = 0x4C01;
static LOOP_SET_STATUS64: u64 = 0x4C04;
static LOOP_CTL_GET_FREE: u64 = 0x4C82;

const LOOP_CONTROL: &'static str = "/dev/loop-control";
const LOOP_PREFIX: &'static str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<LoopControl> {
        Ok(LoopControl {
            dev_file: try!(OpenOptions::new().read(true).write(true).open(LOOP_CONTROL)),
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.get_path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(try!(LoopDevice::open(&format!("{}{}", LOOP_PREFIX, result))))
        }
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<LoopDevice> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(LoopDevice { device: f })
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach the file
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_FD,
                     bf.as_raw_fd() as c_int) < 0 {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_STATUS64,
                     &mut info) < 0 {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the path of the loop device.
    pub fn get_path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// # ld.attach("test.img", 0).unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD, 0) < 0 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}
<commit_msg>use u16 for ioctl() request and convert it to required type<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionalty to the linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.get_path().unwrap().display());
//!
//! ld.attach("test.img", 0).unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};
use std::default::Default;

static LOOP_SET_FD: u16 = 0x4C00;
static LOOP_CLR_FD: u16 = 0x4C01;
static LOOP_SET_STATUS64: u16 = 0x4C04;
static LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &'static str = "/dev/loop-control";
const LOOP_PREFIX: &'static str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<LoopControl> {
        Ok(LoopControl {
            dev_file: try!(OpenOptions::new().read(true).write(true).open(LOOP_CONTROL)),
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.get_path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into());
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(try!(LoopDevice::open(&format!("{}{}", LOOP_PREFIX, result))))
        }
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<LoopDevice> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(LoopDevice { device: f })
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach the file
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_FD.into(),
                     bf.as_raw_fd() as c_int) < 0 {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_STATUS64.into(),
                     &mut info) < 0 {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the path of the loop device.
    pub fn get_path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// # ld.attach("test.img", 0).unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) < 0 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}
<|endoftext|>