<commit_before>use byteorder::{BigEndian, ByteOrder};
use bytes::Bytes;
use futures::{Async, Future, Poll};
use futures::sync::{mpsc, oneshot};
use protobuf;
use protocol;
use std::collections::HashMap;
use std::mem;

use util::SeqGenerator;

mod types;
pub use self::types::*;

mod sender;
pub use self::sender::MercurySender;

component! {
    MercuryManager : MercuryManagerInner {
        sequence: SeqGenerator<u64> = SeqGenerator::new(0),
        pending: HashMap<Vec<u8>, MercuryPending> = HashMap::new(),
        subscriptions: Vec<(String, mpsc::UnboundedSender<MercuryResponse>)> = Vec::new(),
    }
}

pub struct MercuryPending {
    parts: Vec<Vec<u8>>,
    partial: Option<Vec<u8>>,
    callback: Option<oneshot::Sender<Result<MercuryResponse, MercuryError>>>,
}

pub struct MercuryFuture<T>(oneshot::Receiver<Result<T, MercuryError>>);
impl<T> Future for MercuryFuture<T> {
    type Item = T;
    type Error = MercuryError;

    fn poll(&mut self) -> Poll<T, MercuryError> {
        match self.0.poll() {
            Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)),
            Ok(Async::Ready(Err(err))) => Err(err),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(oneshot::Canceled) => Err(MercuryError),
        }
    }
}

impl MercuryManager {
    fn next_seq(&self) -> Vec<u8> {
        let mut seq = vec![0u8; 8];
        BigEndian::write_u64(&mut seq, self.lock(|inner| inner.sequence.get()));
        seq
    }

    pub fn request(&self, req: MercuryRequest) -> MercuryFuture<MercuryResponse> {
        let (tx, rx) = oneshot::channel();

        let pending = MercuryPending {
            parts: Vec::new(),
            partial: None,
            callback: Some(tx),
        };

        let seq = self.next_seq();
        self.lock(|inner| inner.pending.insert(seq.clone(), pending));

        let cmd = req.method.command();
        let data = req.encode(&seq);

        self.session().send_packet(cmd, data);
        MercuryFuture(rx)
    }

    pub fn get<T: Into<String>>(&self, uri: T) -> MercuryFuture<MercuryResponse> {
        self.request(MercuryRequest {
            method: MercuryMethod::GET,
            uri: uri.into(),
            content_type: None,
            payload: Vec::new(),
        })
    }

    pub fn send<T: Into<String>>(&self, uri: T, data: Vec<u8>) -> MercuryFuture<MercuryResponse> {
        self.request(MercuryRequest {
            method: MercuryMethod::SEND,
            uri: uri.into(),
            content_type: None,
            payload: vec![data],
        })
    }

    pub fn sender<T: Into<String>>(&self, uri: T) -> MercurySender {
        MercurySender::new(self.clone(), uri.into())
    }

    pub fn subscribe<T: Into<String>>(
        &self,
        uri: T,
    ) -> Box<Future<Item = mpsc::UnboundedReceiver<MercuryResponse>, Error = MercuryError>> {
        let uri = uri.into();
        let request = self.request(MercuryRequest {
            method: MercuryMethod::SUB,
            uri: uri.clone(),
            content_type: None,
            payload: Vec::new(),
        });

        let manager = self.clone();
        Box::new(request.map(move |response| {
            let (tx, rx) = mpsc::unbounded();

            manager.lock(move |inner| {
                debug!("subscribed uri={} count={}", uri, response.payload.len());
                if response.payload.len() > 0 {
                    // Old subscription protocol, watch the provided list of URIs
                    for sub in response.payload {
                        let mut sub: protocol::pubsub::Subscription =
                            protobuf::parse_from_bytes(&sub).unwrap();
                        let sub_uri = sub.take_uri();

                        debug!("subscribed sub_uri={}", sub_uri);

                        inner.subscriptions.push((sub_uri, tx.clone()));
                    }
                } else {
                    // New subscription protocol, watch the requested URI
                    inner.subscriptions.push((uri, tx));
                }
            });

            rx
        }))
    }

    pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) {
        let seq_len = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;
        let seq = data.split_to(seq_len).as_ref().to_owned();

        let flags = data.split_to(1).as_ref()[0];
        let count = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;

        let pending = self.lock(|inner| inner.pending.remove(&seq));

        let mut pending = match pending {
            Some(pending) => pending,
            None if cmd == 0xb5 => MercuryPending {
                parts: Vec::new(),
                partial: None,
                callback: None,
            },
            None => {
                warn!("Ignore seq {:?} cmd {:x}", seq, cmd);
                return;
            }
        };

        for i in 0..count {
            let mut part = Self::parse_part(&mut data);
            if let Some(mut partial) = mem::replace(&mut pending.partial, None) {
                partial.extend_from_slice(&part);
                part = partial;
            }

            if i == count - 1 && (flags == 2) {
                pending.partial = Some(part)
            } else {
                pending.parts.push(part);
            }
        }

        if flags == 0x1 {
            self.complete_request(cmd, pending);
        } else {
            self.lock(move |inner| inner.pending.insert(seq, pending));
        }
    }

    fn parse_part(data: &mut Bytes) -> Vec<u8> {
        let size = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;
        data.split_to(size).as_ref().to_owned()
    }

    fn complete_request(&self, cmd: u8, mut pending: MercuryPending) {
        let header_data = pending.parts.remove(0);
        let header: protocol::mercury::Header = protobuf::parse_from_bytes(&header_data).unwrap();

        let response = MercuryResponse {
            uri: header.get_uri().to_owned(),
            status_code: header.get_status_code(),
            payload: pending.parts,
        };

        if response.status_code >= 400 {
            warn!("error {} for uri {}", response.status_code, &response.uri);
            if let Some(cb) = pending.callback {
                let _ = cb.send(Err(MercuryError));
            }
        } else {
            if cmd == 0xb5 {
                self.lock(|inner| {
                    let mut found = false;
                    inner.subscriptions.retain(|&(ref prefix, ref sub)| {
                        if response.uri.starts_with(prefix) {
                            found = true;

                            // if send fails, remove from list of subs
                            // TODO: send unsub message
                            sub.unbounded_send(response.clone()).is_ok()
                        } else {
                            // URI doesn't match
                            true
                        }
                    });

                    if !found {
                        debug!("unknown subscription uri={}", response.uri);
                    }
                })
            } else if let Some(cb) = pending.callback {
                let _ = cb.send(Ok(response));
            }
        }
    }
}
<commit_msg>core API: MercuryManager.request()<commit_after>use byteorder::{BigEndian, ByteOrder};
use bytes::Bytes;
use futures::{Async, Future, Poll};
use futures::sync::{mpsc, oneshot};
use protobuf;
use protocol;
use std::collections::HashMap;
use std::mem;

use util::SeqGenerator;

mod types;
pub use self::types::*;

mod sender;
pub use self::sender::MercurySender;

component! {
    MercuryManager : MercuryManagerInner {
        sequence: SeqGenerator<u64> = SeqGenerator::new(0),
        pending: HashMap<Vec<u8>, MercuryPending> = HashMap::new(),
        subscriptions: Vec<(String, mpsc::UnboundedSender<MercuryResponse>)> = Vec::new(),
    }
}

pub struct MercuryPending {
    parts: Vec<Vec<u8>>,
    partial: Option<Vec<u8>>,
    callback: Option<oneshot::Sender<Result<MercuryResponse, MercuryError>>>,
}

pub struct MercuryFuture<T>(oneshot::Receiver<Result<T, MercuryError>>);
impl<T> Future for MercuryFuture<T> {
    type Item = T;
    type Error = MercuryError;

    fn poll(&mut self) -> Poll<T, MercuryError> {
        match self.0.poll() {
            Ok(Async::Ready(Ok(value))) => Ok(Async::Ready(value)),
            Ok(Async::Ready(Err(err))) => Err(err),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(oneshot::Canceled) => Err(MercuryError),
        }
    }
}

impl MercuryManager {
    fn next_seq(&self) -> Vec<u8> {
        let mut seq = vec![0u8; 8];
        BigEndian::write_u64(&mut seq, self.lock(|inner| inner.sequence.get()));
        seq
    }

    fn request(&self, req: MercuryRequest) -> MercuryFuture<MercuryResponse> {
        let (tx, rx) = oneshot::channel();

        let pending = MercuryPending {
            parts: Vec::new(),
            partial: None,
            callback: Some(tx),
        };

        let seq = self.next_seq();
        self.lock(|inner| inner.pending.insert(seq.clone(), pending));

        let cmd = req.method.command();
        let data = req.encode(&seq);

        self.session().send_packet(cmd, data);
        MercuryFuture(rx)
    }

    pub fn get<T: Into<String>>(&self, uri: T) -> MercuryFuture<MercuryResponse> {
        self.request(MercuryRequest {
            method: MercuryMethod::GET,
            uri: uri.into(),
            content_type: None,
            payload: Vec::new(),
        })
    }

    pub fn send<T: Into<String>>(&self, uri: T, data: Vec<u8>) -> MercuryFuture<MercuryResponse> {
        self.request(MercuryRequest {
            method: MercuryMethod::SEND,
            uri: uri.into(),
            content_type: None,
            payload: vec![data],
        })
    }

    pub fn sender<T: Into<String>>(&self, uri: T) -> MercurySender {
        MercurySender::new(self.clone(), uri.into())
    }

    pub fn subscribe<T: Into<String>>(
        &self,
        uri: T,
    ) -> Box<Future<Item = mpsc::UnboundedReceiver<MercuryResponse>, Error = MercuryError>> {
        let uri = uri.into();
        let request = self.request(MercuryRequest {
            method: MercuryMethod::SUB,
            uri: uri.clone(),
            content_type: None,
            payload: Vec::new(),
        });

        let manager = self.clone();
        Box::new(request.map(move |response| {
            let (tx, rx) = mpsc::unbounded();

            manager.lock(move |inner| {
                debug!("subscribed uri={} count={}", uri, response.payload.len());
                if response.payload.len() > 0 {
                    // Old subscription protocol, watch the provided list of URIs
                    for sub in response.payload {
                        let mut sub: protocol::pubsub::Subscription =
                            protobuf::parse_from_bytes(&sub).unwrap();
                        let sub_uri = sub.take_uri();

                        debug!("subscribed sub_uri={}", sub_uri);

                        inner.subscriptions.push((sub_uri, tx.clone()));
                    }
                } else {
                    // New subscription protocol, watch the requested URI
                    inner.subscriptions.push((uri, tx));
                }
            });

            rx
        }))
    }

    pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) {
        let seq_len = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;
        let seq = data.split_to(seq_len).as_ref().to_owned();

        let flags = data.split_to(1).as_ref()[0];
        let count = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;

        let pending = self.lock(|inner| inner.pending.remove(&seq));

        let mut pending = match pending {
            Some(pending) => pending,
            None if cmd == 0xb5 => MercuryPending {
                parts: Vec::new(),
                partial: None,
                callback: None,
            },
            None => {
                warn!("Ignore seq {:?} cmd {:x}", seq, cmd);
                return;
            }
        };

        for i in 0..count {
            let mut part = Self::parse_part(&mut data);
            if let Some(mut partial) = mem::replace(&mut pending.partial, None) {
                partial.extend_from_slice(&part);
                part = partial;
            }

            if i == count - 1 && (flags == 2) {
                pending.partial = Some(part)
            } else {
                pending.parts.push(part);
            }
        }

        if flags == 0x1 {
            self.complete_request(cmd, pending);
        } else {
            self.lock(move |inner| inner.pending.insert(seq, pending));
        }
    }

    fn parse_part(data: &mut Bytes) -> Vec<u8> {
        let size = BigEndian::read_u16(data.split_to(2).as_ref()) as usize;
        data.split_to(size).as_ref().to_owned()
    }

    fn complete_request(&self, cmd: u8, mut pending: MercuryPending) {
        let header_data = pending.parts.remove(0);
        let header: protocol::mercury::Header = protobuf::parse_from_bytes(&header_data).unwrap();

        let response = MercuryResponse {
            uri: header.get_uri().to_owned(),
            status_code: header.get_status_code(),
            payload: pending.parts,
        };

        if response.status_code >= 400 {
            warn!("error {} for uri {}", response.status_code, &response.uri);
            if let Some(cb) = pending.callback {
                let _ = cb.send(Err(MercuryError));
            }
        } else {
            if cmd == 0xb5 {
                self.lock(|inner| {
                    let mut found = false;
                    inner.subscriptions.retain(|&(ref prefix, ref sub)| {
                        if response.uri.starts_with(prefix) {
                            found = true;

                            // if send fails, remove from list of subs
                            // TODO: send unsub message
                            sub.unbounded_send(response.clone()).is_ok()
                        } else {
                            // URI doesn't match
                            true
                        }
                    });

                    if !found {
                        debug!("unknown subscription uri={}", response.uri);
                    }
                })
            } else if let Some(cb) = pending.callback {
                let _ = cb.send(Ok(response));
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Prepared statements cache for faster execution.
extern crate lru_cache;

use {SqliteResult, SqliteConnection, SqliteStatement};
use lru_cache::LruCache;

/// Prepared statements cache.
///
/// FIXME limitation: the same SQL can be cached only once...
#[derive(Debug)]
pub struct StatementCache<'conn> {
    pub conn: &'conn SqliteConnection,
    cache: LruCache<String, SqliteStatement<'conn>>,
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn SqliteConnection, capacity: usize) -> StatementCache<'conn> {
        StatementCache{ conn: conn,  cache: LruCache::new(capacity) }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    pub fn get(&mut self, sql: &str) -> SqliteResult<SqliteStatement<'conn>> {
        let stmt = self.cache.remove(sql);
        match stmt {
            Some(stmt) => Ok(stmt),
            _ => self.conn.prepare(sql)
        }
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    pub fn release(&mut self, stmt: SqliteStatement<'conn>, discard: bool) -> SqliteResult<()> {
        if discard {
            return stmt.finalize();
        }
        // FIXME stmt.reset_if_needed();
        // clear bindings ???
        self.cache.insert(stmt.sql(), stmt).map_or(Ok(()), |stmt| stmt.finalize())
    }

    /// Flush the prepared statement cache
    pub fn flush(&mut self) {
        self.cache.clear();
    }

    /// Return (current, max) sizes.
    pub fn size(&self) -> (usize, usize) {
        (self.cache.len(), self.cache.capacity())
    }

    /// Set the maximum number of cached statements.
    pub fn set_size(&mut self, capacity: usize) {
        self.cache.set_capacity(capacity);
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;
    use super::StatementCache;

   #[test]
    fn test_cache() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let mut cache = StatementCache::new(&db, 10);
        let sql = "PRAGMA schema_version";
        let mut stmt = cache.get(sql).unwrap();
        //println!("NEW {:?}", stmt);
        cache.release(stmt, false).unwrap();
        stmt = cache.get(sql).unwrap();
        //println!("CACHED {:?}", stmt);
        cache.release(stmt, true).unwrap();
        cache.flush();
    }
}
<commit_msg>Fix use declaration.<commit_after>//! Prepared statements cache for faster execution.
extern crate lru_cache;

use {SqliteResult, SqliteConnection, SqliteStatement};
use self::lru_cache::LruCache;

/// Prepared statements cache.
///
/// FIXME limitation: the same SQL can be cached only once...
#[derive(Debug)]
pub struct StatementCache<'conn> {
    pub conn: &'conn SqliteConnection,
    cache: LruCache<String, SqliteStatement<'conn>>,
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn SqliteConnection, capacity: usize) -> StatementCache<'conn> {
        StatementCache{ conn: conn,  cache: LruCache::new(capacity) }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    pub fn get(&mut self, sql: &str) -> SqliteResult<SqliteStatement<'conn>> {
        let stmt = self.cache.remove(sql);
        match stmt {
            Some(stmt) => Ok(stmt),
            _ => self.conn.prepare(sql)
        }
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    pub fn release(&mut self, stmt: SqliteStatement<'conn>, discard: bool) -> SqliteResult<()> {
        if discard {
            return stmt.finalize();
        }
        // FIXME stmt.reset_if_needed();
        // clear bindings ???
        self.cache.insert(stmt.sql(), stmt).map_or(Ok(()), |stmt| stmt.finalize())
    }

    /// Flush the prepared statement cache
    pub fn flush(&mut self) {
        self.cache.clear();
    }

    /// Return (current, max) sizes.
    pub fn size(&self) -> (usize, usize) {
        (self.cache.len(), self.cache.capacity())
    }

    /// Set the maximum number of cached statements.
    pub fn set_size(&mut self, capacity: usize) {
        self.cache.set_capacity(capacity);
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;
    use super::StatementCache;

   #[test]
    fn test_cache() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let mut cache = StatementCache::new(&db, 10);
        let sql = "PRAGMA schema_version";
        let mut stmt = cache.get(sql).unwrap();
        //println!("NEW {:?}", stmt);
        cache.release(stmt, false).unwrap();
        stmt = cache.get(sql).unwrap();
        //println!("CACHED {:?}", stmt);
        cache.release(stmt, true).unwrap();
        cache.flush();
    }
}
<|endoftext|>


<commit_before>use std::process::Command;

pub fn update_lockfile(repository_path: &str) -> bool {
    let manifest_path = format!("{}/Cargo.toml", repository_path);
    Command::new("cargo")
        .arg("fetch")
        .arg("--manifest-path")
        .arg(manifest_path)
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

pub fn package(repository_path: &str) -> bool {
    let manifest_path = format!("{}/Cargo.toml", repository_path);
    Command::new("cargo")
        .arg("package")
        .arg("--manifest-path")
        .arg(manifest_path)
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}
<commit_msg>feat: Method to publish to crates.io<commit_after>use std::process::Command;

pub fn update_lockfile(repository_path: &str) -> bool {
    let manifest_path = format!("{}/Cargo.toml", repository_path);
    Command::new("cargo")
        .arg("fetch")
        .arg("--manifest-path")
        .arg(manifest_path)
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

pub fn package(repository_path: &str) -> bool {
    let manifest_path = format!("{}/Cargo.toml", repository_path);
    Command::new("cargo")
        .arg("package")
        .arg("--manifest-path")
        .arg(manifest_path)
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

pub fn publish(repository_path: &str) -> bool {
    let manifest_path = format!("{}/Cargo.toml", repository_path);
    let token = "TO BE DETERMINED";
    Command::new("cargo")
        .arg("publish")
        .arg("--manifest-path")
        .arg(manifest_path)
        .arg("--token")
        .arg(token)
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}
<|endoftext|>


<commit_before>use std::rc::{self, Rc};
use std::sync::{self, Arc};

/// Trait for generalizing downgrading a strong reference to a weak reference.
pub trait Downgrade
where
    Self: Sized,
{
    /// Weak reference type.
    type Weak;

    /// Downgrade to a weak reference.
    fn downgrade(&self) -> Self::Weak;
}

/// Trait for generalizing upgrading a weak reference to a strong reference.
pub trait Upgrade
where
    Self: Sized,
{
    /// Strong reference type.
    type Strong;

    /// Try upgrading a weak reference to a strong reference.
    fn upgrade(&self) -> Option<Self::Strong>;
}

impl<T: Downgrade + crate::ObjectType> Upgrade for crate::WeakRef<T> {
    type Strong = T;

    fn upgrade(&self) -> Option<Self::Strong> {
        self.upgrade()
    }
}

impl<T> Downgrade for Arc<T> {
    type Weak = sync::Weak<T>;

    fn downgrade(&self) -> Self::Weak {
        Arc::downgrade(self)
    }
}

impl<T> Upgrade for sync::Weak<T> {
    type Strong = Arc<T>;

    fn upgrade(&self) -> Option<Self::Strong> {
        self.upgrade()
    }
}

impl<T> Downgrade for Rc<T> {
    type Weak = rc::Weak<T>;

    fn downgrade(&self) -> Self::Weak {
        Rc::downgrade(self)
    }
}

impl<T> Upgrade for rc::Weak<T> {
    type Strong = Rc<T>;

    fn upgrade(&self) -> Option<Self::Strong> {
        self.upgrade()
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! to_type_before {
    (_) => ();
    (self) => (
        compile_error!("Can't use `self` as variable name for the `clone!` macro. Try storing it in a temporary variable.");
    );
    (@weak self) => (
        compile_error!("Can't use `self` as variable name for the `clone!` macro. Try storing it in a temporary variable.");
    );
    ($variable:ident) => (
        let $variable = $variable.clone();
    );
    (@weak $variable:ident) => (
        let $variable = $crate::clone::Downgrade::downgrade(&$variable);
    );
}

#[doc(hidden)]
#[macro_export]
macro_rules! to_type_after {
    (_ , $return_value:expr) => {};
    (self, $return_value:expr) => {};
    (@weak self, $return_value:expr) => {};
    ($variable:ident , $return_value:expr) => {};
    (@weak $variable:ident , $return_value:expr) => {
        let $variable = match $crate::clone::Upgrade::upgrade(&$variable) {
            Some(val) => val,
            None => return ($return_value)(),
        };
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! to_return_value {
    () => {
        ()
    };
    ($value:expr) => {
        $value
    };
}

/// Macro for passing variables  as strong or weak references into a closure.
///
/// This macro can be useful in combination with closures, e.g. signal handlers, to reduce the
/// boilerplate required for passing strong or weak references into the closure. It will
/// automatically create the new reference and pass it with the same name into the closure.
///
/// If upgrading the weak reference to a strong reference inside the closure is failing, the
/// closure is immediately returning an optional default return value. If none is provided, `()` is
/// returned.
///
///  ### Passing a strong reference
/// ```rust
/// use glib::clone;
/// use std::rc::Rc;
///
/// let v = Rc::new(1);
/// let closure = clone!(v => move |x| {
///     println!("v: {}, x: {}", v, x);
/// });
///
/// closure(2);
/// ```
///
///  ### Passing a strong and weak reference
/// ```rust
/// use glib::clone;
/// use std::rc::Rc;
///
/// let v = Rc::new(1);
/// let u = Rc::new(2);
/// let closure = clone!(v, @weak u => move |x| {
///     println!("v: {}, u: {}, x: {}", v, u, x);
/// });
///
/// closure(3);
/// ```
///
///  ### Providing a default return value if upgrading a weak reference fails
/// ```rust
/// use glib::clone;
/// use std::rc::Rc;
///
/// let v = Rc::new(1);
/// let closure = clone!(@weak v => @default-return false, move |x| {
///     println!("v: {}, x: {}", v, x);
///     true
/// });
///
/// // Drop value so that the weak reference can't be upgraded.
/// drop(v);
///
/// assert_eq!(closure(2), false);
/// ```
#[macro_export]
macro_rules! clone {
    ($($(@ $weak:ident)? $variables:ident),+ => $(@default-return $return_value:expr,)? move || $body:block ) => (
        {
            $( $crate::to_type_before!($(@ $weak)? $variables); )*
            move || {
                let return_value = || $crate::to_return_value!($($return_value)?);
                $( $crate::to_type_after!($(@ $weak)? $variables, return_value );)*
                $body
            }
        }
    );
    ($($(@ $weak:ident)? $variables:ident),+ => $(@default-return $return_value:expr ,)? move | $($pattern:pat),* | $body:block ) => (
        {
            $( $crate::to_type_before!($(@ $weak)? $variables); )*
            move |$($pattern),*| {
                let return_value = || $crate::to_return_value!($($return_value)?);
                $( $crate::to_type_after!($(@ $weak)? $variables, return_value );)*
                $body
            }
        }
    );
}
<commit_msg>Improve doc styling<commit_after>use std::rc::{self, Rc};
use std::sync::{self, Arc};

/// Trait for generalizing downgrading a strong reference to a weak reference.
pub trait Downgrade
where
    Self: Sized,
{
    /// Weak reference type.
    type Weak;

    /// Downgrade to a weak reference.
    fn downgrade(&self) -> Self::Weak;
}

/// Trait for generalizing upgrading a weak reference to a strong reference.
pub trait Upgrade
where
    Self: Sized,
{
    /// Strong reference type.
    type Strong;

    /// Try upgrading a weak reference to a strong reference.
    fn upgrade(&self) -> Option<Self::Strong>;
}

impl<T: Downgrade + crate::ObjectType> Upgrade for crate::WeakRef<T> {
    type Strong = T;

    fn upgrade(&self) -> Option<Self::Strong> {
        self.upgrade()
    }
}

impl<T> Downgrade for Arc<T> {
    type Weak = sync::Weak<T>;

    fn downgrade(&self) -> Self::Weak {
        Arc::downgrade(self)
    }
}

impl<T> Upgrade for sync::Weak<T> {
    type Strong = Arc<T>;

    fn upgrade(&self) -> Option<Self::Strong> {
        self.upgrade()
    }
}

impl<T> Downgrade for Rc<T> {
    type Weak = rc::Weak<T>;

    fn downgrade(&self) -> Self::Weak {
        Rc::downgrade(self)
    }
}

impl<T> Upgrade for rc::Weak<T> {
    type Strong = Rc<T>;

    fn upgrade(&self) -> Option<Self::Strong> {
        self.upgrade()
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! to_type_before {
    (_) => ();
    (self) => (
        compile_error!("Can't use `self` as variable name for the `clone!` macro. Try storing it in a temporary variable.");
    );
    (@weak self) => (
        compile_error!("Can't use `self` as variable name for the `clone!` macro. Try storing it in a temporary variable.");
    );
    ($variable:ident) => (
        let $variable = $variable.clone();
    );
    (@weak $variable:ident) => (
        let $variable = $crate::clone::Downgrade::downgrade(&$variable);
    );
}

#[doc(hidden)]
#[macro_export]
macro_rules! to_type_after {
    (_ , $return_value:expr) => {};
    (self, $return_value:expr) => {};
    (@weak self, $return_value:expr) => {};
    ($variable:ident , $return_value:expr) => {};
    (@weak $variable:ident , $return_value:expr) => {
        let $variable = match $crate::clone::Upgrade::upgrade(&$variable) {
            Some(val) => val,
            None => return ($return_value)(),
        };
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! to_return_value {
    () => {
        ()
    };
    ($value:expr) => {
        $value
    };
}

/// Macro for passing variables as strong or weak references into a closure.
///
/// This macro can be useful in combination with closures, e.g. signal handlers, to reduce the
/// boilerplate required for passing strong or weak references into the closure. It will
/// automatically create the new reference and pass it with the same name into the closure.
///
/// If upgrading the weak reference to a strong reference inside the closure is failing, the
/// closure is immediately returning an optional default return value. If none is provided, `()` is
/// returned.
///
/// ### Passing a strong reference
///
/// ```
/// use glib::clone;
/// use std::rc::Rc;
///
/// let v = Rc::new(1);
/// let closure = clone!(v => move |x| {
///     println!("v: {}, x: {}", v, x);
/// });
///
/// closure(2);
/// ```
///
/// ### Passing a strong and weak reference
///
/// ```
/// use glib::clone;
/// use std::rc::Rc;
///
/// let v = Rc::new(1);
/// let u = Rc::new(2);
/// let closure = clone!(v, @weak u => move |x| {
///     println!("v: {}, u: {}, x: {}", v, u, x);
/// });
///
/// closure(3);
/// ```
///
/// ### Providing a default return value if upgrading a weak reference fails
///
/// ```
/// use glib::clone;
/// use std::rc::Rc;
///
/// let v = Rc::new(1);
/// let closure = clone!(@weak v => @default-return false, move |x| {
///     println!("v: {}, x: {}", v, x);
///     true
/// });
///
/// // Drop value so that the weak reference can't be upgraded.
/// drop(v);
///
/// assert_eq!(closure(2), false);
/// ```
#[macro_export]
macro_rules! clone {
    ($($(@ $weak:ident)? $variables:ident),+ => $(@default-return $return_value:expr,)? move || $body:block ) => (
        {
            $( $crate::to_type_before!($(@ $weak)? $variables); )*
            move || {
                let return_value = || $crate::to_return_value!($($return_value)?);
                $( $crate::to_type_after!($(@ $weak)? $variables, return_value );)*
                $body
            }
        }
    );
    ($($(@ $weak:ident)? $variables:ident),+ => $(@default-return $return_value:expr ,)? move | $($pattern:pat),* | $body:block ) => (
        {
            $( $crate::to_type_before!($(@ $weak)? $variables); )*
            move |$($pattern),*| {
                let return_value = || $crate::to_return_value!($($return_value)?);
                $( $crate::to_type_after!($(@ $weak)? $variables, return_value );)*
                $body
            }
        }
    );
}
<|endoftext|>


<commit_before>use ::cssparser;
use ::libc;

use ::glib::translate::*;

use parsers::Parse;
use parsers::ParseError;
use error::*;

// There are two quirks here:
//
// First, we need to expose the Color algebraic type *and* a parse
// error to C, but we can't repr(C) them plainly.  So, we define a
// ColorKind enum and a ColorSpec struct that can both be represented
// in C.
//
// Second, the C code in librsvg expects ARGB colors passed around as
// guint32.  However, in Rust we'd prefer to use cssparser's RGBA
// structure, which has explicit fields for red/green/blue/alpha.
// We'll do those conversions here, for the benefit of the C code, and
// then just wait until the C code gradually disappears.

// Keep this in sync with rsvg-css.h:RsvgCssColorKind
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ColorKind {
    Inherit,
    CurrentColor,
    ARGB,
    ParseError
}

// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ColorSpec {
    kind: ColorKind,
    argb: u32
}

// Keep in sync with rsvg-css.h:AllowInherit
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowInherit {
    No,
    Yes
}

// Keep in sync with rsvg-css.h:AllowCurrentColor
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowCurrentColor {
    No,
    Yes
}

// This is the Rust version of the above
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
    Inherit,
    CurrentColor,
    RGBA (cssparser::RGBA)
}

impl Parse for Color {
    type Data = (AllowInherit, AllowCurrentColor);
    type Err = AttributeError;

    fn parse (s: &str, (allow_inherit, allow_current_color): (AllowInherit, AllowCurrentColor)) -> Result<Color, AttributeError> {
        if s == "inherit" {
            if allow_inherit == AllowInherit::Yes {
                Ok (Color::Inherit)
            } else {
                Err (AttributeError::Value ("inherit is not allowed here".to_string ()))
            }
        } else {
            let mut input = cssparser::ParserInput::new (s);
            match cssparser::Color::parse (&mut cssparser::Parser::new (&mut input)) {
                Ok (cssparser::Color::CurrentColor) => {
                    if allow_current_color == AllowCurrentColor::Yes {
                        Ok (Color::CurrentColor)
                    } else {
                        Err (AttributeError::Value ("currentColor is not allowed here".to_string ()))
                    }
                },

                Ok (csscolor) => Ok (Color::from (csscolor)),

                _ => Err (AttributeError::Parse (ParseError::new ("invalid syntax for color")))
            }
        }
    }

}

impl Color {
    pub fn from_color_spec (spec: &ColorSpec) -> Result <Color, AttributeError> {
        match *spec {
            ColorSpec { kind: ColorKind::Inherit, .. }      => Ok (Color::Inherit),

            ColorSpec { kind: ColorKind::CurrentColor, .. } => Ok (Color::CurrentColor),

            ColorSpec { kind: ColorKind::ARGB, argb } => Ok (Color::RGBA (rgba_from_argb (argb))),

            ColorSpec { kind: ColorKind::ParseError, .. } => Err (AttributeError::Parse (ParseError::new ("parse error")))
        }
    }
}

fn rgba_from_argb (argb: u32) -> cssparser::RGBA {
    cssparser::RGBA::new (((argb & 0x00ff_0000) >> 16) as u8,
                          ((argb & 0x0000_ff00) >> 8) as u8,
                          ((argb & 0x0000_00ff) as u8),
                          ((argb & 0xff00_0000) >> 24) as u8)
}

impl From<cssparser::Color> for Color {
    fn from (c: cssparser::Color) -> Color {
        match c {
            cssparser::Color::CurrentColor => Color::CurrentColor,
            cssparser::Color::RGBA (rgba) => Color::RGBA (rgba)
        }
    }
}

impl From<u32> for Color {
    fn from (argb: u32) -> Color {
        Color::RGBA (rgba_from_argb (argb))
    }
}

impl From<Result<Color, AttributeError>> for ColorSpec {
    fn from (result: Result<Color, AttributeError>) -> ColorSpec {
        match result {
            Ok (Color::Inherit) =>
                ColorSpec {
                    kind: ColorKind::Inherit,
                    argb: 0
                },

            Ok (Color::CurrentColor) =>
                ColorSpec {
                    kind: ColorKind::CurrentColor,
                    argb: 0
                },

            Ok (Color::RGBA (rgba)) =>
                ColorSpec {
                    kind: ColorKind::ARGB,
                    argb: (u32::from(rgba.alpha) << 24 |
                           u32::from(rgba.red)   << 16 |
                           u32::from(rgba.green) << 8  |
                           u32::from(rgba.blue))
                },

            _ =>
                ColorSpec {
                    kind: ColorKind::ParseError,
                    argb: 0
                }
        }
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_color (string: *const libc::c_char,
                                    allow_inherit: AllowInherit,
                                    allow_current_color: AllowCurrentColor) -> ColorSpec {
    let s = unsafe { String::from_glib_none (string) };

    ColorSpec::from (Color::parse (&s, (allow_inherit, allow_current_color)))
}

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

    fn parse (s: &str) -> ColorSpec {
        // ColorSpec::from (Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes)))
        rsvg_css_parse_color (s.to_glib_none ().0, AllowInherit::Yes, AllowCurrentColor::Yes)
    }

    #[test]
    fn parses_hash_hex_colors () {
        assert_eq! (parse ("#AB10fa20"), ColorSpec { kind: ColorKind::ARGB, argb: 0x20ab10fa });
        assert_eq! (parse ("#10fa20"),   ColorSpec { kind: ColorKind::ARGB, argb: 0xff10fa20 });
        assert_eq! (parse ("#abcd"),     ColorSpec { kind: ColorKind::ARGB, argb: 0xddaabbcc });
        assert_eq! (parse ("#123"),      ColorSpec { kind: ColorKind::ARGB, argb: 0xff112233 });
    }

    #[test]
    fn parses_color_keywords () {
        assert_eq! (parse ("red"),  ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("lime"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("blue"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_color_functions () {
        assert_eq! (parse ("rgb(255, 0, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("rgb(0, 255, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("rgb(0, 0, 255)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_current_color () {
        assert_eq! (parse ("currentColor"), ColorSpec { kind: ColorKind::CurrentColor, argb: 0 });
    }

    fn make_error () -> ColorSpec {
        ColorSpec {
            kind: ColorKind::ParseError,
            argb: 0
        }
    }

    #[test]
    fn invalid_hash_hex_colors_yield_error () {
        assert_eq! (parse ("#"), make_error ());
        assert_eq! (parse ("#xyz"), make_error ());
        assert_eq! (parse ("#112233gg"), make_error ());
    }

    #[test]
    fn invalid_colors_yield_error () {
        assert_eq! (parse (""), make_error ());
        assert_eq! (parse ("foo"), make_error ());
        assert_eq! (parse ("rgb(chilaquil)"), make_error ());
        assert_eq! (parse ("rgb(1, 2, 3, 4, 5)"), make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_current_color () {
        assert_eq! (ColorSpec::from (Color::parse ("currentColor", (AllowInherit::Yes, AllowCurrentColor::No))),
                    make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_inherit () {
        assert_eq! (ColorSpec::from (Color::parse ("inherit", (AllowInherit::No, AllowCurrentColor::Yes))),
                    make_error ());
    }

    fn test_roundtrip (s: &str) {
        let result = Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes));
        let result2 = result.clone ();
        let spec = ColorSpec::from (result2);

        if result.is_ok () {
            assert_eq! (Color::from_color_spec (&spec), result);
        } else {
            assert! (Color::from_color_spec (&spec).is_err ());
        }
    }

    #[test]
    fn roundtrips () {
        test_roundtrip ("inherit");
        test_roundtrip ("currentColor");
        test_roundtrip ("#aabbccdd");
        test_roundtrip ("papadzul");
    }

    #[test]
    fn from_argb () {
        assert_eq! (Color::from (0xaabbccdd),
                    Color::RGBA (cssparser::RGBA::new (0xbb, 0xcc, 0xdd, 0xaa)));
    }
}
<commit_msg>rsvg_css_parse_color(): Don't copy the incoming string<commit_after>use ::cssparser;
use ::libc;

use ::glib::translate::*;

use parsers::Parse;
use parsers::ParseError;
use error::*;
use util::utf8_cstr;

// There are two quirks here:
//
// First, we need to expose the Color algebraic type *and* a parse
// error to C, but we can't repr(C) them plainly.  So, we define a
// ColorKind enum and a ColorSpec struct that can both be represented
// in C.
//
// Second, the C code in librsvg expects ARGB colors passed around as
// guint32.  However, in Rust we'd prefer to use cssparser's RGBA
// structure, which has explicit fields for red/green/blue/alpha.
// We'll do those conversions here, for the benefit of the C code, and
// then just wait until the C code gradually disappears.

// Keep this in sync with rsvg-css.h:RsvgCssColorKind
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ColorKind {
    Inherit,
    CurrentColor,
    ARGB,
    ParseError
}

// Keep this in sync with rsvg-css.h:RsvgCssColorSpec
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ColorSpec {
    kind: ColorKind,
    argb: u32
}

// Keep in sync with rsvg-css.h:AllowInherit
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowInherit {
    No,
    Yes
}

// Keep in sync with rsvg-css.h:AllowCurrentColor
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum AllowCurrentColor {
    No,
    Yes
}

// This is the Rust version of the above
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
    Inherit,
    CurrentColor,
    RGBA (cssparser::RGBA)
}

impl Parse for Color {
    type Data = (AllowInherit, AllowCurrentColor);
    type Err = AttributeError;

    fn parse (s: &str, (allow_inherit, allow_current_color): (AllowInherit, AllowCurrentColor)) -> Result<Color, AttributeError> {
        if s == "inherit" {
            if allow_inherit == AllowInherit::Yes {
                Ok (Color::Inherit)
            } else {
                Err (AttributeError::Value ("inherit is not allowed here".to_string ()))
            }
        } else {
            let mut input = cssparser::ParserInput::new (s);
            match cssparser::Color::parse (&mut cssparser::Parser::new (&mut input)) {
                Ok (cssparser::Color::CurrentColor) => {
                    if allow_current_color == AllowCurrentColor::Yes {
                        Ok (Color::CurrentColor)
                    } else {
                        Err (AttributeError::Value ("currentColor is not allowed here".to_string ()))
                    }
                },

                Ok (csscolor) => Ok (Color::from (csscolor)),

                _ => Err (AttributeError::Parse (ParseError::new ("invalid syntax for color")))
            }
        }
    }

}

impl Color {
    pub fn from_color_spec (spec: &ColorSpec) -> Result <Color, AttributeError> {
        match *spec {
            ColorSpec { kind: ColorKind::Inherit, .. }      => Ok (Color::Inherit),

            ColorSpec { kind: ColorKind::CurrentColor, .. } => Ok (Color::CurrentColor),

            ColorSpec { kind: ColorKind::ARGB, argb } => Ok (Color::RGBA (rgba_from_argb (argb))),

            ColorSpec { kind: ColorKind::ParseError, .. } => Err (AttributeError::Parse (ParseError::new ("parse error")))
        }
    }
}

fn rgba_from_argb (argb: u32) -> cssparser::RGBA {
    cssparser::RGBA::new (((argb & 0x00ff_0000) >> 16) as u8,
                          ((argb & 0x0000_ff00) >> 8) as u8,
                          ((argb & 0x0000_00ff) as u8),
                          ((argb & 0xff00_0000) >> 24) as u8)
}

impl From<cssparser::Color> for Color {
    fn from (c: cssparser::Color) -> Color {
        match c {
            cssparser::Color::CurrentColor => Color::CurrentColor,
            cssparser::Color::RGBA (rgba) => Color::RGBA (rgba)
        }
    }
}

impl From<u32> for Color {
    fn from (argb: u32) -> Color {
        Color::RGBA (rgba_from_argb (argb))
    }
}

impl From<Result<Color, AttributeError>> for ColorSpec {
    fn from (result: Result<Color, AttributeError>) -> ColorSpec {
        match result {
            Ok (Color::Inherit) =>
                ColorSpec {
                    kind: ColorKind::Inherit,
                    argb: 0
                },

            Ok (Color::CurrentColor) =>
                ColorSpec {
                    kind: ColorKind::CurrentColor,
                    argb: 0
                },

            Ok (Color::RGBA (rgba)) =>
                ColorSpec {
                    kind: ColorKind::ARGB,
                    argb: (u32::from(rgba.alpha) << 24 |
                           u32::from(rgba.red)   << 16 |
                           u32::from(rgba.green) << 8  |
                           u32::from(rgba.blue))
                },

            _ =>
                ColorSpec {
                    kind: ColorKind::ParseError,
                    argb: 0
                }
        }
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_color (string: *const libc::c_char,
                                    allow_inherit: AllowInherit,
                                    allow_current_color: AllowCurrentColor) -> ColorSpec {
    let s = unsafe { utf8_cstr(string) };

    ColorSpec::from (Color::parse (s, (allow_inherit, allow_current_color)))
}

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

    fn parse (s: &str) -> ColorSpec {
        // ColorSpec::from (Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes)))
        rsvg_css_parse_color (s.to_glib_none ().0, AllowInherit::Yes, AllowCurrentColor::Yes)
    }

    #[test]
    fn parses_hash_hex_colors () {
        assert_eq! (parse ("#AB10fa20"), ColorSpec { kind: ColorKind::ARGB, argb: 0x20ab10fa });
        assert_eq! (parse ("#10fa20"),   ColorSpec { kind: ColorKind::ARGB, argb: 0xff10fa20 });
        assert_eq! (parse ("#abcd"),     ColorSpec { kind: ColorKind::ARGB, argb: 0xddaabbcc });
        assert_eq! (parse ("#123"),      ColorSpec { kind: ColorKind::ARGB, argb: 0xff112233 });
    }

    #[test]
    fn parses_color_keywords () {
        assert_eq! (parse ("red"),  ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("lime"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("blue"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_color_functions () {
        assert_eq! (parse ("rgb(255, 0, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xffff0000 });
        assert_eq! (parse ("rgb(0, 255, 0)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff00ff00 });
        assert_eq! (parse ("rgb(0, 0, 255)"), ColorSpec { kind: ColorKind::ARGB, argb: 0xff0000ff });
    }

    #[test]
    fn parses_current_color () {
        assert_eq! (parse ("currentColor"), ColorSpec { kind: ColorKind::CurrentColor, argb: 0 });
    }

    fn make_error () -> ColorSpec {
        ColorSpec {
            kind: ColorKind::ParseError,
            argb: 0
        }
    }

    #[test]
    fn invalid_hash_hex_colors_yield_error () {
        assert_eq! (parse ("#"), make_error ());
        assert_eq! (parse ("#xyz"), make_error ());
        assert_eq! (parse ("#112233gg"), make_error ());
    }

    #[test]
    fn invalid_colors_yield_error () {
        assert_eq! (parse (""), make_error ());
        assert_eq! (parse ("foo"), make_error ());
        assert_eq! (parse ("rgb(chilaquil)"), make_error ());
        assert_eq! (parse ("rgb(1, 2, 3, 4, 5)"), make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_current_color () {
        assert_eq! (ColorSpec::from (Color::parse ("currentColor", (AllowInherit::Yes, AllowCurrentColor::No))),
                    make_error ());
    }

    #[test]
    fn yields_error_on_disallowed_inherit () {
        assert_eq! (ColorSpec::from (Color::parse ("inherit", (AllowInherit::No, AllowCurrentColor::Yes))),
                    make_error ());
    }

    fn test_roundtrip (s: &str) {
        let result = Color::parse (s, (AllowInherit::Yes, AllowCurrentColor::Yes));
        let result2 = result.clone ();
        let spec = ColorSpec::from (result2);

        if result.is_ok () {
            assert_eq! (Color::from_color_spec (&spec), result);
        } else {
            assert! (Color::from_color_spec (&spec).is_err ());
        }
    }

    #[test]
    fn roundtrips () {
        test_roundtrip ("inherit");
        test_roundtrip ("currentColor");
        test_roundtrip ("#aabbccdd");
        test_roundtrip ("papadzul");
    }

    #[test]
    fn from_argb () {
        assert_eq! (Color::from (0xaabbccdd),
                    Color::RGBA (cssparser::RGBA::new (0xbb, 0xcc, 0xdd, 0xaa)));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::collections::VecDeque;
use std::rc::Rc;
use std::cell::RefCell;
use futures::{self, task, Async, Future, Poll};
use futures::sync::oneshot;

use capnp::{Error};

use serialize::{self, AsOutputSegments};

enum State<W, M> where W: io::Write, M: AsOutputSegments {
    Writing(serialize::Write<W, M>, oneshot::Sender<M>),
    BetweenWrites(W),
    Empty,
}

/// A queue of messages being written.
pub struct WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    inner: Rc<RefCell<Inner<M>>>,
    state: State<W, M>,
}

struct Inner<M> {
    queue: VecDeque<(M, oneshot::Sender<M>)>,
    sender_count: usize,
    task: Option<task::Task>,

    // If set, then the queue has been requested to end, and we should complete the oneshot once
    // the queue has been emptied.
    end_notifier: Option<oneshot::Sender<()>>
}

/// A handle that allows message to be sent to a `WriteQueue`.
pub struct Sender<M> where M: AsOutputSegments {
    inner: Rc<RefCell<Inner<M>>>,
}

impl <M> Clone for Sender<M> where M: AsOutputSegments {
    fn clone(&self) -> Sender<M> {
        self.inner.borrow_mut().sender_count += 1;
        Sender { inner: self.inner.clone() }
    }
}

impl <M> Drop for Sender<M> where M: AsOutputSegments {
    fn drop(&mut self) {
        self.inner.borrow_mut().sender_count -= 1;
    }
}

pub fn write_queue<W, M>(writer: W) -> (Sender<M>, WriteQueue<W, M>)
    where W: io::Write, M: AsOutputSegments
{
    let inner = Rc::new(RefCell::new(Inner {
        queue: VecDeque::new(),
        task: None,
        sender_count: 1,
        end_notifier: None,
    }));

    let queue = WriteQueue {
        inner: inner.clone(),
        state: State::BetweenWrites(writer),
    };

    let sender = Sender { inner: inner };

    (sender, queue)
}

impl <M> Sender<M> where M: AsOutputSegments {
    /// Enqueues a message to be written.
    pub fn send(&mut self, message: M) -> oneshot::Receiver<M> {
        let (complete, oneshot) = futures::oneshot();

        if self.inner.borrow().end_notifier.is_some() {
            drop(complete)
        } else {
            self.inner.borrow_mut().queue.push_back((message, complete));
        }

        match self.inner.borrow_mut().task.take() {
            Some(t) => t.unpark(),
            None => (),
        }

        oneshot
    }

    /// Returns the number of messages queued to be written, not including any in-progress write.
    pub fn len(&mut self) -> usize {
        self.inner.borrow().queue.len()
    }

    /// Commands the queue to stop writing messages once it is empty. After this method has been called,
    /// any new calls to `send()` will return a future that immediately resolves to an error.
    pub fn end(&mut self) -> oneshot::Receiver<()> {
        let (complete, receiver) = futures::oneshot();

        // TODO: what if end_notifier is already full? Maybe it should be a vector?
        self.inner.borrow_mut().end_notifier = Some(complete);

        match self.inner.borrow_mut().task.take() {
            Some(t) => t.unpark(),
            None => (),
        }

        receiver
    }
}

enum IntermediateState<W, M> where W: io::Write, M: AsOutputSegments {
    WriteDone(M, W),
    StartWrite(M, oneshot::Sender<M>),
    Resolve,
}

impl <W, M> Future for WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    type Item = W; // Resolves when all senders have been dropped and all messages written.
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let next = match self.state {
                State::Writing(ref mut write, ref mut _complete) => {
                    let (w, m) = try_ready!(Future::poll(write));
                    IntermediateState::WriteDone(m, w)
                }
                State::BetweenWrites(ref mut _writer) => {
                    let front = self.inner.borrow_mut().queue.pop_front();
                    match front {
                        Some((m, complete)) => {
                            IntermediateState::StartWrite(m, complete)
                        }
                        None => {
                            let count = self.inner.borrow().sender_count;
                            let ended = self.inner.borrow().end_notifier.is_some();
                            if count == 0 || ended {
                                IntermediateState::Resolve
                            } else {
                                self.inner.borrow_mut().task = Some(task::park());
                                return Ok(Async::NotReady)
                            }
                        }
                    }
                }
                State::Empty => unreachable!(),
            };

            match next {
                IntermediateState::WriteDone(m, w) => {
                    match ::std::mem::replace(&mut self.state, State::BetweenWrites(w)) {
                        State::Writing(_, complete) => {
                            complete.complete(m)
                        }
                        _ => unreachable!(),
                    }
                }
                IntermediateState::StartWrite(m, c) => {
                    let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            State::Writing(::serialize::write_message(w, m), c)
                        }
                        _ => unreachable!(),
                    };
                    self.state = new_state;
                }
                IntermediateState::Resolve => {
                    let ender = self.inner.borrow_mut().end_notifier.take();
                    match ender {
                        None => (),
                        Some(complete) => complete.complete(()),
                    }
                    match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            return Ok(Async::Ready(w))
                        }
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}
<commit_msg>WriteQueue senders should only hold a weak reference to the WriteQueue<commit_after>// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use futures::{self, task, Async, Future, Poll};
use futures::sync::oneshot;

use capnp::{Error};

use serialize::{self, AsOutputSegments};

enum State<W, M> where W: io::Write, M: AsOutputSegments {
    Writing(serialize::Write<W, M>, oneshot::Sender<M>),
    BetweenWrites(W),
    Empty,
}

/// A queue of messages being written.
pub struct WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    inner: Rc<RefCell<Inner<M>>>,
    state: State<W, M>,
}

struct Inner<M> {
    queue: VecDeque<(M, oneshot::Sender<M>)>,
    sender_count: usize,
    task: Option<task::Task>,

    // If set, then the queue has been requested to end, and we should complete the oneshot once
    // the queue has been emptied.
    end_notifier: Option<oneshot::Sender<()>>
}

/// A handle that allows message to be sent to a `WriteQueue`.
pub struct Sender<M> where M: AsOutputSegments {
    inner: Weak<RefCell<Inner<M>>>,
}

impl <M> Clone for Sender<M> where M: AsOutputSegments {
    fn clone(&self) -> Sender<M> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().sender_count += 1;
            }
        }
        Sender { inner: self.inner.clone() }
    }
}

impl <M> Drop for Sender<M> where M: AsOutputSegments {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.borrow_mut().sender_count -= 1;
            }
        }
    }
}

pub fn write_queue<W, M>(writer: W) -> (Sender<M>, WriteQueue<W, M>)
    where W: io::Write, M: AsOutputSegments
{
    let inner = Rc::new(RefCell::new(Inner {
        queue: VecDeque::new(),
        task: None,
        sender_count: 1,
        end_notifier: None,
    }));

    let sender = Sender { inner: Rc::downgrade(&inner) };

    let queue = WriteQueue {
        inner: inner,
        state: State::BetweenWrites(writer),
    };

    (sender, queue)
}

impl <M> Sender<M> where M: AsOutputSegments {
    /// Enqueues a message to be written.
    pub fn send(&mut self, message: M) -> oneshot::Receiver<M> {
        let (complete, oneshot) = futures::oneshot();

        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                if rc_inner.borrow().end_notifier.is_some() {
                    drop(complete)
                } else {
                    rc_inner.borrow_mut().queue.push_back((message, complete));
                }

                match rc_inner.borrow_mut().task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }

        oneshot
    }

    /// Returns the number of messages queued to be written, not including any in-progress write.
    pub fn len(&mut self) -> usize {
        match self.inner.upgrade() {
            None => 0,
            Some(rc_inner) => rc_inner.borrow().queue.len(),
        }

    }

    /// Commands the queue to stop writing messages once it is empty. After this method has been called,
    /// any new calls to `send()` will return a future that immediately resolves to an error.
    pub fn end(&mut self) -> oneshot::Receiver<()> {
        let (complete, receiver) = futures::oneshot();

        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                // TODO: what if end_notifier is already full? Maybe it should be a vector?
                rc_inner.borrow_mut().end_notifier = Some(complete);

                match rc_inner.borrow_mut().task.take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }

        receiver
    }
}

enum IntermediateState<W, M> where W: io::Write, M: AsOutputSegments {
    WriteDone(M, W),
    StartWrite(M, oneshot::Sender<M>),
    Resolve,
}

impl <W, M> Future for WriteQueue<W, M> where W: io::Write, M: AsOutputSegments {
    type Item = W; // Resolves when all senders have been dropped and all messages written.
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let next = match self.state {
                State::Writing(ref mut write, ref mut _complete) => {
                    let (w, m) = try_ready!(Future::poll(write));
                    IntermediateState::WriteDone(m, w)
                }
                State::BetweenWrites(ref mut _writer) => {
                    let front = self.inner.borrow_mut().queue.pop_front();
                    match front {
                        Some((m, complete)) => {
                            IntermediateState::StartWrite(m, complete)
                        }
                        None => {
                            let count = self.inner.borrow().sender_count;
                            let ended = self.inner.borrow().end_notifier.is_some();
                            if count == 0 || ended {
                                IntermediateState::Resolve
                            } else {
                                self.inner.borrow_mut().task = Some(task::park());
                                return Ok(Async::NotReady)
                            }
                        }
                    }
                }
                State::Empty => unreachable!(),
            };

            match next {
                IntermediateState::WriteDone(m, w) => {
                    match ::std::mem::replace(&mut self.state, State::BetweenWrites(w)) {
                        State::Writing(_, complete) => {
                            complete.complete(m)
                        }
                        _ => unreachable!(),
                    }
                }
                IntermediateState::StartWrite(m, c) => {
                    let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            State::Writing(::serialize::write_message(w, m), c)
                        }
                        _ => unreachable!(),
                    };
                    self.state = new_state;
                }
                IntermediateState::Resolve => {
                    let ender = self.inner.borrow_mut().end_notifier.take();
                    match ender {
                        None => (),
                        Some(complete) => complete.complete(()),
                    }
                    match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            return Ok(Async::Ready(w))
                        }
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Bindings to various errno.h definitions.

///Error numbers defined in errno-base.h, with some exceptions which are marked accordingly
pub mod errno_base {

    ///Operation not permitted
    pub const EPERM: ::c_int = 1;

    ///No such file or directory
    pub const ENOENT: ::c_int = 2;

    ///No such process
    pub const ESRCH: ::c_int = 3;

    ///Interrupted system call. Oops
    pub const EINTR: ::c_int = 4;

    ///I/O error.
    pub const EIO: ::c_int = 5;

    ///No such device or address
    pub const ENXIO: ::c_int = 6;

    ///Argument list too long.
    ///
    ///You thought it was error too big, didn't you?
    pub const E2BIG: ::c_int = 7;

    ///Exec format error
    pub const ENOEXEC: ::c_int = 8;

    ///Bad file number
    pub const EBADF: ::c_int = 9;

    ///No child processes
    ///
    ///Alternatively, your name is Anthony Dinozzo Jr or Richard Castle
    pub const ECHILD: ::c_int = 10;

    ///Try again, I'm not really an error, just an annoyance
    pub const EAGAIN: ::c_int = 11;

    ///Out of memory
    pub const ENOMEM: ::c_int = 12;

    ///Permission denied!
    pub const EACCES: ::c_int = 13;

    ///Bad address
    pub const EFAULT: ::c_int = 14;

    ///Block device required but not found
    pub const ENOTBLK: ::c_int = 15;

    ///Device or resource is too busy to listen to you right now
    pub const EBUSY: ::c_int = 16;

    ///File already exists
    pub const EEXIST: ::c_int = 17;

    ///Cross-device link. Sorry, but quantum entanglement is not working in storage drives yet
    pub const EXDEV: ::c_int = 18;

    ///No such device.
    ///
    ///Alternatively, you have been robbed by a Jedi knight. "This is not the device you were searching for"
    pub const ENODEV: ::c_int = 19;

    ///That's... not a directory
    pub const ENOTDIR: ::c_int = 20;

    ///That's... not a file. That's a directory
    pub const EISDIR: ::c_int = 21;

    ///Your argument is invalid!
    pub const EINVAL: ::c_int = 22;

    ///File table overflowed
    pub const ENFILE: ::c_int = 23;

    ///Too many files are already open
    pub const EMFILE: ::c_int = 24;

    ///You are not a typewriter
    ///
    ///Does this expand to you are not a terminal? What a about a smart kettle? Or a WIFI-enabled microwave? Hey, somebody should go patent that
    pub const ENOTTTY: ::c_int = 25;

    ///Text file is too busy to listen to you right now
    pub const ETXTBSY: ::c_int = 26; //Ooooh, what are you writing?

    ///File is too large. What are you doing, downloading a car?
    pub const EFBIG: ::c_int = 27; //Okay, really, how?

    ///You don't have any (or at least enough) space left on the specified device. You might need a new hard drive.
    ///
    ///Might I suggest a SSD? They cost more but the performance gain is worth it
    pub const ENOSPC: ::c_int = 28; //I'm so sorry

    ///Illegal seek
    ///
    ///What the hell are you doing?
    pub const ESPIPE: ::c_int = 29;

    ///You're trying to write to a read-only file system.
    pub const EROFS: ::c_int = 30; //Haha, nice try

    ///Too many links exist
    pub const EMLINK: ::c_int = 31;

    ///Broken pipe
    pub const EPIPE: ::c_int = 32;

    ///Math argument is out of the function's domain
    ///
    ///??? I need more coffee to get this. Is it like trying to check if an int is NaN?
    pub const EDOM: ::c_int = 33;

    ///Math result could not be represented
    ///
    ///Stop trying to divide by ze--- ```EACCES```
    pub const ERANGE: ::c_int = 34;

}

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub mod errno_common {

    ///Resource deadlock would occur
    pub const EDEADLK: ::c_int = 35;

    ///File name is too long. (Hah!)
    pub const ENAMETOOLONG: ::c_int = 36;

    ///No record locks available
    pub const ENOLCK: ::c_int = 37;

    ///Invalid system call number
    ///
    ///This is special. Arch syscall entry code returns -ENOSYS if
    ///users try to call a syscall that doesn't exist.
    pub const ENOSYS: ::c_int = 38;

    ///Directory is not empty.
    pub const ENOTEMPTY: ::c_int = 39;

    ///Too many symbolic links encountered. This is probably an infinite loop
    ///
    ///Alternatively, you broke your computer.
    pub const ELOOP: ::c_int = 40;

    ///Operation would block. You should try again?
    pub const EWOULDBLOCK: ::c_int = ::EAGAIN;

    ///No message of the desired type
    pub const ENOMSG: ::c_int = 42;

    ///Identifier was removed
    pub const EIDRM: ::c_int = 43;

    ///Channel number is out of acceptable range
    pub const ECHRNG: ::c_int = 44;

    ///Level 2 is not synchronized
    pub const EL2NSYNC: ::c_int = 45;

    ///Level 3 was halted
    pub const EL3HLT: ::c_int = 46;

    ///Level 3 was reset
    pub const EL3RST: ::c_int = 47;

    ///Link number is out of range
    ///
    ///How do you do this?
    pub const ELNRNG: ::c_int = 48;

    ///Protocol driver not attached
    pub const EUNATCH: ::c_int = 49;

    ///No CSI structure is available
    pub const ENOCSI: ::c_int = 50;

    ///Level 2 was halted
    pub const EL2HLT: ::c_int = 51;

    ///Invalid exchange
    pub const EBADE: ::c_int = 52;

    ///Invalid request descriptor
    pub const EBADR: ::c_int = 53;

    ///Exchange is full.
    ///
    ///I am so sorry
    pub const EXFULL: ::c_int = 54;

    ///No anode is available
    pub const ENOANO: ::c_int = 55;

    ///Invalid request code
    pub const EBADRQC: ::c_int = 56;

    ///Invalid slot
    pub const EBADSLT: ::c_int = 57;

    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = EDEADLK;

    ///Bad font file format
    pub const EBFONT: ::c_int = 59;

    ///Device is not a stream
    pub const ENOSTR: ::c_int = 60;

    ///No data is available
    pub const ENODATA: ::c_int = 61;

    ///Timer expired
    pub const ETIME: ::c_int = 62;

    ///Out of streams resources
    ///
    ///Should this be stream's? I'm not sure about the context. Is it the resources of the stream, or resources of the system's supply of streams?
    pub const ENOSR: ::c_int = 63;

    ///Requested machine was not on the network
    pub const ENONET: ::c_int = 64;

    ///Package is not installed
    pub const ENOPKG: ::c_int = 65;

    ///Object is remote when it is required to be local
    pub const EREMOTE: ::c_int = 66;

    ///Link has been severed
    pub const ENOLINK: ::c_int = 67;

    ///Error in advertising
    pub const EADV: ::c_int = 68;

    ///Srmount error
    pub const ESRMNT: ::c_int = 69;

    ///Communications error on send
    pub const ECOMM: ::c_int = 70;

    ///Protocol error
    pub const EPROTO: ::c_int = 71;

    ///A multihop was attempted
    pub const EMULTIHOP: ::c_int = 72;

    ///A RFS-specific error occurred
    pub const EDOTDOT: ::c_int = 73;

    ///Message is not a data message
    pub const EBADMASG: ::c_int = 74;

    ///Value is too large for the defined data type
    pub const EOVERFLOW: ::c_int = 75;

    ///Name is not unique on the network
    ///
    ///No, BILLY_TABLES, you can't have ten computers called '; DROP TABLE users' for "backup purposes"
    pub const ENOTUNIQ: ::c_int = 76;

    ///File descriptor is in a bad state
    ///
    ///Huh. I haven't seen this before
    pub const EBADFD: ::c_int = 77;

    ///The remote address changed.
    ///
    ///How does this happen? A change from wifi to 4g, etc?
    pub const EREMCHG: ::c_int = 78;

    ///Can not access a needed shared library
    ///
    ///Thankfully, with Cargo, this shouldn't happen :)
    pub const ELIBACC: ::c_int = 79;

    ///Attempted to access a shared library, only to find out it was corrupted
    ///
    ///WELL, FUCK.
    pub const ELIBBAD: ::c_int = 80;

    ///.lib section in a.out is corrupted
    pub const ELIBSCN: ::c_int = 81;

    ///Attempting to link in too many shared libraries
    ///
    ///Are... are you okay?
    pub const ELIBMAX: ::c_int = 82;

    ///Cannot exec a shared library directly
    pub const ELIBEXEC: ::c_int = 83;

    ///Illegal byte sequence
    ///
    ///I don't know what the hell you are doing, but you're probably doing it wrong
    pub const EILSEQ: ::c_int = 84;

    ///Interrupted system call, you should restart it
    ///
    ///Well, that's easy
    pub const ERESTART: ::c_int = 85;

    ///Streams pipe error
    pub const ESTRPIPE: ::c_int = 86;

    ///Too many users
    ///
    ///*Points finger and laughs*
    pub const EUSERS: ::c_int = 87;

    ///Socket operation attempted on an object that is not a socket
    pub const ENOTSOCK: ::c_int = 88;

    ///Destination address required
    pub const EDESTADDRREQ: ::c_int = 89;

    ///Message is too long
    pub const EMSGSIZE: ::c_int = 90;

    ///Protocol type is wrong for this socket
    pub const EPROTOTYPE: ::c_int = 91;

    ///Protocol is not available
    pub const ENOPROTOOPT: ::c_int = 92;

    ///Protocol is not supported
    pub const EPROTONOSUPPORT: ::c_int = 93;

    ///Socket type is not supported
    ///
    ///What?
    pub const ESOCKTNOSUPPORT: ::c_int = 94;

    ///Operation not supported on transport endpoint
    pub const EOPNOTSUPP: ::c_int = 95;

    ///Protocol family is not supported
    pub const EPFNOSUPPORT: ::c_int = 96;

    ///Address family is not supported by this protocol
    pub const EAFNOSUPPORT: ::c_int = 97;

    ///Address is already in use
    pub const EADDRINUSE: ::c_int = 98;

    ///Cannot assign the requested address
    pub const EADDRNOTAVAIL: ::c_int = 99;

    ///Network is down
    pub const ENETDOWN: ::c_int = 100;

    ///Network is unreachable :(
    pub const ENETUNREACH: ::c_int = 101;

    ///Network dropped connection because of a reset
    pub const ENETRESET: ::c_int = 102;

    ///Software caused the connection to abort
    pub const ECONNABORTED: ::c_int = 103;

    ///Connection was reset by a peer
    pub const ECONNRESET: ::c_int = 104;

    ///No buffer space is available
    pub const ENOBUFS: ::c_int = 105;

    ///Transport endpoint is already connected
    pub const EISCONN: ::c_int = 106;

    ///Transport endpoint is not connected
    pub const ENOTCONN: ::c_int = 107;

    ///Cannot send after the transport endpoint is shut down
    pub const ESHUTDOWN: ::c_int = 108;

    ///Too many references; Cannot splice
    pub const ETOOMANYREFS: ::c_int = 109;

    ///Connection timed out
    pub const ETIMEDOUT: ::c_int = 110;

    ///Connection was refused
    pub const ECONNREFUSED: ::c_int = 111;

    ///The host is down! D:
    pub const EHOSTDOWN: ::c_int = 112;

    ///There is no usable route to the host
    pub const EHOSTUNREACH: ::c_int = 113;

    ///Operation is already in progress. Be patient!
    pub const EALREADY: ::c_int = 114;

    ///Operation is in progress
    pub const EINPROGRESS: ::c_int = 115;

    ///The file handle is stale. Ew!
    pub const ESTALE: ::c_int = 116;

    ///The structure needs cleaning
    pub const EUCLEAN: ::c_int = 117;

    ///This is not a XENIX named type file
    pub const ENOTNAM: ::c_int = 118;

    ///No XENIX semaphores are available
    pub const ENAVAIL: ::c_int = 119;

    ///This is a named type file
    pub const EISNAM: ::c_int = 120;

    ///A remote I/O error occurred
    pub const EREMOTEIO: ::c_int = 121;

    ///You exceeded your quote
    pub const EDQUOT: ::c_int = 122;

    ///No medium was found
    pub const ENOMEDIUM: ::c_int = 123;

    ///You're using the wrong medium type
    pub const EMEDIUMTYPE: ::c_int = 124;

    ///The operation was cancelled
    pub const ECANCELED: ::c_int = 125;

    ///The required key is not available
    pub const ENOKEY: ::c_int = 126;

    ///The key you're using has expired
    pub const EKEYEXPIRED: ::c_int = 127;

    ///The key you're using has been revoked
    pub const EKEYREVOKED: ::c_int = 128;

    ///The key you're using was rejected by the service you're trying to access
    pub const EKEYREJECTED: ::c_int = 129;

    ///Your owner died.
    ///
    ///Dobby is a free computer!
    ///
    ///Just kidding. Your mutex's owner died. Dobby is still a slave
    pub const EOWNERDEAD: ::c_int = 130;

    ///The state of your mutex is not recoverable
    pub const ENOTRECOVERABLE: ::c_int = 131;

    ///Operation is not possible due to RF-kill
    pub const ERFKILL: ::c_int = 132;

    ///The memory page has a hardware error
    pub const EHWPOISON: ::c_int = 133;

}

pub use self::errno_base::*;

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub use self::errno_common::*;<commit_msg>Re-order usage in errno.rs a bit<commit_after>//! Bindings to various errno.h definitions.

///Error numbers defined in errno-base.h, with some exceptions which are marked accordingly
pub mod errno_base {

    ///Operation not permitted
    pub const EPERM: ::c_int = 1;

    ///No such file or directory
    pub const ENOENT: ::c_int = 2;

    ///No such process
    pub const ESRCH: ::c_int = 3;

    ///Interrupted system call. Oops
    pub const EINTR: ::c_int = 4;

    ///I/O error.
    pub const EIO: ::c_int = 5;

    ///No such device or address
    pub const ENXIO: ::c_int = 6;

    ///Argument list too long.
    ///
    ///You thought it was error too big, didn't you?
    pub const E2BIG: ::c_int = 7;

    ///Exec format error
    pub const ENOEXEC: ::c_int = 8;

    ///Bad file number
    pub const EBADF: ::c_int = 9;

    ///No child processes
    ///
    ///Alternatively, your name is Anthony Dinozzo Jr or Richard Castle
    pub const ECHILD: ::c_int = 10;

    ///Try again, I'm not really an error, just an annoyance
    pub const EAGAIN: ::c_int = 11;

    ///Out of memory
    pub const ENOMEM: ::c_int = 12;

    ///Permission denied!
    pub const EACCES: ::c_int = 13;

    ///Bad address
    pub const EFAULT: ::c_int = 14;

    ///Block device required but not found
    pub const ENOTBLK: ::c_int = 15;

    ///Device or resource is too busy to listen to you right now
    pub const EBUSY: ::c_int = 16;

    ///File already exists
    pub const EEXIST: ::c_int = 17;

    ///Cross-device link. Sorry, but quantum entanglement is not working in storage drives yet
    pub const EXDEV: ::c_int = 18;

    ///No such device.
    ///
    ///Alternatively, you have been robbed by a Jedi knight. "This is not the device you were searching for"
    pub const ENODEV: ::c_int = 19;

    ///That's... not a directory
    pub const ENOTDIR: ::c_int = 20;

    ///That's... not a file. That's a directory
    pub const EISDIR: ::c_int = 21;

    ///Your argument is invalid!
    pub const EINVAL: ::c_int = 22;

    ///File table overflowed
    pub const ENFILE: ::c_int = 23;

    ///Too many files are already open
    pub const EMFILE: ::c_int = 24;

    ///You are not a typewriter
    ///
    ///Does this expand to you are not a terminal? What a about a smart kettle? Or a WIFI-enabled microwave? Hey, somebody should go patent that
    pub const ENOTTTY: ::c_int = 25;

    ///Text file is too busy to listen to you right now
    pub const ETXTBSY: ::c_int = 26; //Ooooh, what are you writing?

    ///File is too large. What are you doing, downloading a car?
    pub const EFBIG: ::c_int = 27; //Okay, really, how?

    ///You don't have any (or at least enough) space left on the specified device. You might need a new hard drive.
    ///
    ///Might I suggest a SSD? They cost more but the performance gain is worth it
    pub const ENOSPC: ::c_int = 28; //I'm so sorry

    ///Illegal seek
    ///
    ///What the hell are you doing?
    pub const ESPIPE: ::c_int = 29;

    ///You're trying to write to a read-only file system.
    pub const EROFS: ::c_int = 30; //Haha, nice try

    ///Too many links exist
    pub const EMLINK: ::c_int = 31;

    ///Broken pipe
    pub const EPIPE: ::c_int = 32;

    ///Math argument is out of the function's domain
    ///
    ///??? I need more coffee to get this. Is it like trying to check if an int is NaN?
    pub const EDOM: ::c_int = 33;

    ///Math result could not be represented
    ///
    ///Stop trying to divide by ze--- ```EACCES```
    pub const ERANGE: ::c_int = 34;

}

pub use self::errno_base::*;

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub mod errno_common {

    ///Resource deadlock would occur
    pub const EDEADLK: ::c_int = 35;

    ///File name is too long. (Hah!)
    pub const ENAMETOOLONG: ::c_int = 36;

    ///No record locks available
    pub const ENOLCK: ::c_int = 37;

    ///Invalid system call number
    ///
    ///This is special. Arch syscall entry code returns -ENOSYS if
    ///users try to call a syscall that doesn't exist.
    pub const ENOSYS: ::c_int = 38;

    ///Directory is not empty.
    pub const ENOTEMPTY: ::c_int = 39;

    ///Too many symbolic links encountered. This is probably an infinite loop
    ///
    ///Alternatively, you broke your computer.
    pub const ELOOP: ::c_int = 40;

    ///Operation would block. You should try again?
    pub const EWOULDBLOCK: ::c_int = ::EAGAIN;

    ///No message of the desired type
    pub const ENOMSG: ::c_int = 42;

    ///Identifier was removed
    pub const EIDRM: ::c_int = 43;

    ///Channel number is out of acceptable range
    pub const ECHRNG: ::c_int = 44;

    ///Level 2 is not synchronized
    pub const EL2NSYNC: ::c_int = 45;

    ///Level 3 was halted
    pub const EL3HLT: ::c_int = 46;

    ///Level 3 was reset
    pub const EL3RST: ::c_int = 47;

    ///Link number is out of range
    ///
    ///How do you do this?
    pub const ELNRNG: ::c_int = 48;

    ///Protocol driver not attached
    pub const EUNATCH: ::c_int = 49;

    ///No CSI structure is available
    pub const ENOCSI: ::c_int = 50;

    ///Level 2 was halted
    pub const EL2HLT: ::c_int = 51;

    ///Invalid exchange
    pub const EBADE: ::c_int = 52;

    ///Invalid request descriptor
    pub const EBADR: ::c_int = 53;

    ///Exchange is full.
    ///
    ///I am so sorry
    pub const EXFULL: ::c_int = 54;

    ///No anode is available
    pub const ENOANO: ::c_int = 55;

    ///Invalid request code
    pub const EBADRQC: ::c_int = 56;

    ///Invalid slot
    pub const EBADSLT: ::c_int = 57;

    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = EDEADLK;

    ///Bad font file format
    pub const EBFONT: ::c_int = 59;

    ///Device is not a stream
    pub const ENOSTR: ::c_int = 60;

    ///No data is available
    pub const ENODATA: ::c_int = 61;

    ///Timer expired
    pub const ETIME: ::c_int = 62;

    ///Out of streams resources
    ///
    ///Should this be stream's? I'm not sure about the context. Is it the resources of the stream, or resources of the system's supply of streams?
    pub const ENOSR: ::c_int = 63;

    ///Requested machine was not on the network
    pub const ENONET: ::c_int = 64;

    ///Package is not installed
    pub const ENOPKG: ::c_int = 65;

    ///Object is remote when it is required to be local
    pub const EREMOTE: ::c_int = 66;

    ///Link has been severed
    pub const ENOLINK: ::c_int = 67;

    ///Error in advertising
    pub const EADV: ::c_int = 68;

    ///Srmount error
    pub const ESRMNT: ::c_int = 69;

    ///Communications error on send
    pub const ECOMM: ::c_int = 70;

    ///Protocol error
    pub const EPROTO: ::c_int = 71;

    ///A multihop was attempted
    pub const EMULTIHOP: ::c_int = 72;

    ///A RFS-specific error occurred
    pub const EDOTDOT: ::c_int = 73;

    ///Message is not a data message
    pub const EBADMASG: ::c_int = 74;

    ///Value is too large for the defined data type
    pub const EOVERFLOW: ::c_int = 75;

    ///Name is not unique on the network
    ///
    ///No, BILLY_TABLES, you can't have ten computers called '; DROP TABLE users' for "backup purposes"
    pub const ENOTUNIQ: ::c_int = 76;

    ///File descriptor is in a bad state
    ///
    ///Huh. I haven't seen this before
    pub const EBADFD: ::c_int = 77;

    ///The remote address changed.
    ///
    ///How does this happen? A change from wifi to 4g, etc?
    pub const EREMCHG: ::c_int = 78;

    ///Can not access a needed shared library
    ///
    ///Thankfully, with Cargo, this shouldn't happen :)
    pub const ELIBACC: ::c_int = 79;

    ///Attempted to access a shared library, only to find out it was corrupted
    ///
    ///WELL, FUCK.
    pub const ELIBBAD: ::c_int = 80;

    ///.lib section in a.out is corrupted
    pub const ELIBSCN: ::c_int = 81;

    ///Attempting to link in too many shared libraries
    ///
    ///Are... are you okay?
    pub const ELIBMAX: ::c_int = 82;

    ///Cannot exec a shared library directly
    pub const ELIBEXEC: ::c_int = 83;

    ///Illegal byte sequence
    ///
    ///I don't know what the hell you are doing, but you're probably doing it wrong
    pub const EILSEQ: ::c_int = 84;

    ///Interrupted system call, you should restart it
    ///
    ///Well, that's easy
    pub const ERESTART: ::c_int = 85;

    ///Streams pipe error
    pub const ESTRPIPE: ::c_int = 86;

    ///Too many users
    ///
    ///*Points finger and laughs*
    pub const EUSERS: ::c_int = 87;

    ///Socket operation attempted on an object that is not a socket
    pub const ENOTSOCK: ::c_int = 88;

    ///Destination address required
    pub const EDESTADDRREQ: ::c_int = 89;

    ///Message is too long
    pub const EMSGSIZE: ::c_int = 90;

    ///Protocol type is wrong for this socket
    pub const EPROTOTYPE: ::c_int = 91;

    ///Protocol is not available
    pub const ENOPROTOOPT: ::c_int = 92;

    ///Protocol is not supported
    pub const EPROTONOSUPPORT: ::c_int = 93;

    ///Socket type is not supported
    ///
    ///What?
    pub const ESOCKTNOSUPPORT: ::c_int = 94;

    ///Operation not supported on transport endpoint
    pub const EOPNOTSUPP: ::c_int = 95;

    ///Protocol family is not supported
    pub const EPFNOSUPPORT: ::c_int = 96;

    ///Address family is not supported by this protocol
    pub const EAFNOSUPPORT: ::c_int = 97;

    ///Address is already in use
    pub const EADDRINUSE: ::c_int = 98;

    ///Cannot assign the requested address
    pub const EADDRNOTAVAIL: ::c_int = 99;

    ///Network is down
    pub const ENETDOWN: ::c_int = 100;

    ///Network is unreachable :(
    pub const ENETUNREACH: ::c_int = 101;

    ///Network dropped connection because of a reset
    pub const ENETRESET: ::c_int = 102;

    ///Software caused the connection to abort
    pub const ECONNABORTED: ::c_int = 103;

    ///Connection was reset by a peer
    pub const ECONNRESET: ::c_int = 104;

    ///No buffer space is available
    pub const ENOBUFS: ::c_int = 105;

    ///Transport endpoint is already connected
    pub const EISCONN: ::c_int = 106;

    ///Transport endpoint is not connected
    pub const ENOTCONN: ::c_int = 107;

    ///Cannot send after the transport endpoint is shut down
    pub const ESHUTDOWN: ::c_int = 108;

    ///Too many references; Cannot splice
    pub const ETOOMANYREFS: ::c_int = 109;

    ///Connection timed out
    pub const ETIMEDOUT: ::c_int = 110;

    ///Connection was refused
    pub const ECONNREFUSED: ::c_int = 111;

    ///The host is down! D:
    pub const EHOSTDOWN: ::c_int = 112;

    ///There is no usable route to the host
    pub const EHOSTUNREACH: ::c_int = 113;

    ///Operation is already in progress. Be patient!
    pub const EALREADY: ::c_int = 114;

    ///Operation is in progress
    pub const EINPROGRESS: ::c_int = 115;

    ///The file handle is stale. Ew!
    pub const ESTALE: ::c_int = 116;

    ///The structure needs cleaning
    pub const EUCLEAN: ::c_int = 117;

    ///This is not a XENIX named type file
    pub const ENOTNAM: ::c_int = 118;

    ///No XENIX semaphores are available
    pub const ENAVAIL: ::c_int = 119;

    ///This is a named type file
    pub const EISNAM: ::c_int = 120;

    ///A remote I/O error occurred
    pub const EREMOTEIO: ::c_int = 121;

    ///You exceeded your quote
    pub const EDQUOT: ::c_int = 122;

    ///No medium was found
    pub const ENOMEDIUM: ::c_int = 123;

    ///You're using the wrong medium type
    pub const EMEDIUMTYPE: ::c_int = 124;

    ///The operation was cancelled
    pub const ECANCELED: ::c_int = 125;

    ///The required key is not available
    pub const ENOKEY: ::c_int = 126;

    ///The key you're using has expired
    pub const EKEYEXPIRED: ::c_int = 127;

    ///The key you're using has been revoked
    pub const EKEYREVOKED: ::c_int = 128;

    ///The key you're using was rejected by the service you're trying to access
    pub const EKEYREJECTED: ::c_int = 129;

    ///Your owner died.
    ///
    ///Dobby is a free computer!
    ///
    ///Just kidding. Your mutex's owner died. Dobby is still a slave
    pub const EOWNERDEAD: ::c_int = 130;

    ///The state of your mutex is not recoverable
    pub const ENOTRECOVERABLE: ::c_int = 131;

    ///Operation is not possible due to RF-kill
    pub const ERFKILL: ::c_int = 132;

    ///The memory page has a hardware error
    pub const EHWPOISON: ::c_int = 133;

}

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub use self::errno_common::*;<|endoftext|>


<commit_before>use failure::Fail;

#[derive(Debug, Fail)]
pub enum Error {
    #[fail(display = "Invalid FEN string: {}", fen)]
    InvalidFen { fen: String },
    #[fail(
        display = "The board specified did not pass sanity checks.  Are you sure the kings exist and the side to move cannot capture the opposing king?"
    )]
    InvalidBoard,
}
<commit_msg>Adds documentation to .<commit_after>use failure::Fail;

/// Sometimes, bad stuff happens.
#[derive(Debug, Fail)]
pub enum Error {
    /// The FEN string is invalid
    #[fail(display = "Invalid FEN string: {}", fen)]
    InvalidFen { fen: String },

    /// The board created from BoardBuilder was found to be invalid
    #[fail(
        display = "The board specified did not pass sanity checks.  Are you sure the kings exist and the side to move cannot capture the opposing king?"
    )]
    InvalidBoard,
}
<|endoftext|>