<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![cfg(feature = "debugmozjs")]

#[macro_use]
extern crate mozjs;
extern crate libc;

use mozjs::jsapi::GetRealmObjectPrototype;
use mozjs::jsapi::JSAutoRealm;
use mozjs::jsapi::JSClass;
use mozjs::jsapi::JSContext;
use mozjs::jsapi::JSFunctionSpec;
use mozjs::jsapi::JSNativeWrapper;
use mozjs::jsapi::JSPropertySpec_Name;
use mozjs::jsapi::JS_NewGlobalObject;
use mozjs::jsapi::JS_NewObjectWithUniqueType;
use mozjs::jsapi::JSPROP_ENUMERATE;
use mozjs::jsapi::JS_SetGCZeal;
use mozjs::jsapi::OnNewGlobalHookOption;
use mozjs::jsapi::Value;
use mozjs::jsapi::{JSObject, JSString, JSFunction};
use mozjs::jsval::JSVal;
use mozjs::rust::{JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS, define_methods};
use std::ptr;

#[test]
fn rooting() {
    unsafe {
        let engine = JSEngine::init().unwrap();
        let runtime = Runtime::new(engine.handle());
        let cx = runtime.cx();
        JS_SetGCZeal(cx, 2, 1);

        let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
        let c_option = RealmOptions::default();

        rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                       &SIMPLE_GLOBAL_CLASS,
                                                       ptr::null_mut(),
                                                       h_option,
                                                       &*c_option));
        let _ac = JSAutoRealm::new(cx, global.get());
        rooted!(in(cx) let prototype_proto = GetRealmObjectPrototype(cx));
        rooted!(in(cx) let proto = JS_NewObjectWithUniqueType(cx,
                                                              &CLASS as *const _,
                                                              prototype_proto.handle().into()));
        define_methods(cx, proto.handle(), METHODS).unwrap();

        rooted!(in(cx) let root : JSVal);
        assert_eq!(root.get().is_undefined(), true);

        rooted!(in(cx) let root : *mut JSObject);
        assert_eq!(root.get().is_null(), true);

        rooted!(in(cx) let root : *mut JSString);
        assert_eq!(root.get().is_null(), true);

        rooted!(in(cx) let root : *mut JSFunction);
        assert_eq!(root.get().is_null(), true);
    }
}

unsafe extern "C" fn generic_method(_: *mut JSContext, _: u32, _: *mut Value) -> bool {
    true
}

const METHODS: &'static [JSFunctionSpec] = &[
    JSFunctionSpec {
        name: JSPropertySpec_Name { string_: b"addEventListener\0" as *const u8 as *const libc::c_char },
        call: JSNativeWrapper { op: Some(generic_method), info: 0 as *const _ },
        nargs: 2,
        flags: JSPROP_ENUMERATE as u16,
        selfHostedName: 0 as *const libc::c_char
    },
    JSFunctionSpec {
        name: JSPropertySpec_Name { string_: b"removeEventListener\0" as *const u8 as *const libc::c_char },
        call: JSNativeWrapper { op: Some(generic_method), info: 0 as *const _  },
        nargs: 2,
        flags: JSPROP_ENUMERATE as u16,
        selfHostedName: 0 as *const libc::c_char
    },
    JSFunctionSpec {
        name: JSPropertySpec_Name { string_: b"dispatchEvent\0" as *const u8 as *const libc::c_char },
        call: JSNativeWrapper { op: Some(generic_method), info: 0 as *const _  },
        nargs: 1,
        flags: JSPROP_ENUMERATE as u16,
        selfHostedName: 0 as *const libc::c_char
    },
    JSFunctionSpec::ZERO,
];

static CLASS: JSClass = JSClass {
    name: b"EventTargetPrototype\0" as *const u8 as *const libc::c_char,
    flags: 0,
    cOps: 0 as *const _,
    spec: ptr::null(),
    ext: ptr::null(),
    oOps: ptr::null(),
};
<commit_msg>Update rooting test<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![cfg(feature = "debugmozjs")]

#[macro_use]
extern crate mozjs;
extern crate libc;

use mozjs::jsapi::GetRealmObjectPrototype;
use mozjs::jsapi::JSAutoRealm;
use mozjs::jsapi::JSClass;
use mozjs::jsapi::JSContext;
use mozjs::jsapi::JSFunctionSpec;
use mozjs::jsapi::JSNativeWrapper;
use mozjs::jsapi::JSPropertySpec_Name;
use mozjs::jsapi::JS_NewGlobalObject;
use mozjs::jsapi::JS_NewObjectWithGivenProto;
use mozjs::jsapi::JSPROP_ENUMERATE;
use mozjs::jsapi::JS_SetGCZeal;
use mozjs::jsapi::OnNewGlobalHookOption;
use mozjs::jsapi::Value;
use mozjs::jsapi::{JSObject, JSString, JSFunction};
use mozjs::jsval::JSVal;
use mozjs::rust::{JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS, define_methods};
use std::ptr;

#[test]
fn rooting() {
    unsafe {
        let engine = JSEngine::init().unwrap();
        let runtime = Runtime::new(engine.handle());
        let cx = runtime.cx();
        JS_SetGCZeal(cx, 2, 1);

        let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
        let c_option = RealmOptions::default();

        rooted!(in(cx) let global = JS_NewGlobalObject(cx,
                                                       &SIMPLE_GLOBAL_CLASS,
                                                       ptr::null_mut(),
                                                       h_option,
                                                       &*c_option));
        let _ac = JSAutoRealm::new(cx, global.get());
        rooted!(in(cx) let prototype_proto = GetRealmObjectPrototype(cx));
        rooted!(in(cx) let proto = JS_NewObjectWithGivenProto(cx,
                                                              &CLASS as *const _,
                                                              prototype_proto.handle().into()));
        define_methods(cx, proto.handle(), METHODS).unwrap();

        rooted!(in(cx) let root : JSVal);
        assert_eq!(root.get().is_undefined(), true);

        rooted!(in(cx) let root : *mut JSObject);
        assert_eq!(root.get().is_null(), true);

        rooted!(in(cx) let root : *mut JSString);
        assert_eq!(root.get().is_null(), true);

        rooted!(in(cx) let root : *mut JSFunction);
        assert_eq!(root.get().is_null(), true);
    }
}

unsafe extern "C" fn generic_method(_: *mut JSContext, _: u32, _: *mut Value) -> bool {
    true
}

const METHODS: &'static [JSFunctionSpec] = &[
    JSFunctionSpec {
        name: JSPropertySpec_Name { string_: b"addEventListener\0" as *const u8 as *const libc::c_char },
        call: JSNativeWrapper { op: Some(generic_method), info: 0 as *const _ },
        nargs: 2,
        flags: JSPROP_ENUMERATE as u16,
        selfHostedName: 0 as *const libc::c_char
    },
    JSFunctionSpec {
        name: JSPropertySpec_Name { string_: b"removeEventListener\0" as *const u8 as *const libc::c_char },
        call: JSNativeWrapper { op: Some(generic_method), info: 0 as *const _  },
        nargs: 2,
        flags: JSPROP_ENUMERATE as u16,
        selfHostedName: 0 as *const libc::c_char
    },
    JSFunctionSpec {
        name: JSPropertySpec_Name { string_: b"dispatchEvent\0" as *const u8 as *const libc::c_char },
        call: JSNativeWrapper { op: Some(generic_method), info: 0 as *const _  },
        nargs: 1,
        flags: JSPROP_ENUMERATE as u16,
        selfHostedName: 0 as *const libc::c_char
    },
    JSFunctionSpec::ZERO,
];

static CLASS: JSClass = JSClass {
    name: b"EventTargetPrototype\0" as *const u8 as *const libc::c_char,
    flags: 0,
    cOps: 0 as *const _,
    spec: ptr::null(),
    ext: ptr::null(),
    oOps: ptr::null(),
};
<|endoftext|>


<commit_before>//! Sinks
//!
//! This module contains a number of functions for working with `Sink`s,
//! including the `SinkExt` trait which adds methods to `Sink` types.
//!
//! This module is only available when the `sink` feature of this
//! library is activated, and it is activated by default.

use futures_core::future::Future;
use futures_core::stream::{Stream, TryStream};
use crate::future::Either;

#[cfg(feature = "compat")]
use crate::compat::CompatSink;

pub use futures_sink::Sink;

mod close;
pub use self::close::Close;

mod drain;
pub use self::drain::{drain, Drain};

mod fanout;
pub use self::fanout::Fanout;

mod flush;
pub use self::flush::Flush;

mod err_into;
pub use self::err_into::SinkErrInto;

mod map_err;
pub use self::map_err::SinkMapErr;

mod send;
pub use self::send::Send;

mod send_all;
pub use self::send_all::SendAll;

mod with;
pub use self::with::With;

mod with_flat_map;
pub use self::with_flat_map::WithFlatMap;

#[cfg(feature = "alloc")]
mod buffer;
#[cfg(feature = "alloc")]
pub use self::buffer::Buffer;

impl<T: ?Sized, Item> SinkExt<Item> for T where T: Sink<Item> {}

/// An extension trait for `Sink`s that provides a variety of convenient
/// combinator functions.
pub trait SinkExt<Item>: Sink<Item> {
    /// Composes a function *in front of* the sink.
    ///
    /// This adapter produces a new sink that passes each value through the
    /// given function `f` before sending it to `self`.
    ///
    /// To process each value, `f` produces a *future*, which is then polled to
    /// completion before passing its result down to the underlying sink. If the
    /// future produces an error, that error is returned by the new sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F>
        where F: FnMut(U) -> Fut,
              Fut: Future<Output = Result<Item, E>>,
              E: From<Self::Error>,
              Self: Sized
    {
        With::new(self, f)
    }

    /// Composes a function *in front of* the sink.
    ///
    /// This adapter produces a new sink that passes each value through the
    /// given function `f` before sending it to `self`.
    ///
    /// To process each value, `f` produces a *stream*, of which each value
    /// is passed to the underlying sink. A new value will not be accepted until
    /// the stream has been drained
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::flat_map`.
    ///
    /// # Examples
    ///
    /// ```
    /// # futures::executor::block_on(async {
    /// use futures::channel::mpsc;
    /// use futures::sink::SinkExt;
    /// use futures::stream::{self, StreamExt};
    ///
    /// let (tx, rx) = mpsc::channel(5);
    ///
    /// let mut tx = tx.with_flat_map(|x| {
    ///     stream::iter(vec![Ok(42); x])
    /// });
    ///
    /// tx.send(5).await.unwrap();
    /// drop(tx);
    /// let received: Vec<i32> = rx.collect().await;
    /// assert_eq!(received, vec![42, 42, 42, 42, 42]);
    /// # });
    /// ```
    fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F>
        where F: FnMut(U) -> St,
              St: Stream<Item = Result<Item, Self::Error>>,
              Self: Sized
    {
        WithFlatMap::new(self, f)
    }

    /*
    fn with_map<U, F>(self, f: F) -> WithMap<Self, U, F>
        where F: FnMut(U) -> Self::SinkItem,
              Self: Sized;

    fn with_filter<F>(self, f: F) -> WithFilter<Self, F>
        where F: FnMut(Self::SinkItem) -> bool,
              Self: Sized;

    fn with_filter_map<U, F>(self, f: F) -> WithFilterMap<Self, U, F>
        where F: FnMut(U) -> Option<Self::SinkItem>,
              Self: Sized;
     */

    /// Transforms the error returned by the sink.
    fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F>
        where F: FnOnce(Self::Error) -> E,
              Self: Sized,
    {
        SinkMapErr::new(self, f)
    }

    /// Map this sink's error to a different error type using the `Into` trait.
    ///
    /// If wanting to map errors of a `Sink + Stream`, use `.sink_err_into().err_into()`.
    fn sink_err_into<E>(self) -> err_into::SinkErrInto<Self, Item, E>
        where Self: Sized,
              Self::Error: Into<E>,
    {
        SinkErrInto::new(self)
    }

    /// Adds a fixed-size buffer to the current sink.
    ///
    /// The resulting sink will buffer up to `capacity` items when the
    /// underlying sink is unwilling to accept additional items. Calling `flush`
    /// on the buffered sink will attempt to both empty the buffer and complete
    /// processing on the underlying sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    ///
    /// This method is only available when the `std` or `alloc` feature of this
    /// library is activated, and it is activated by default.
    #[cfg(feature = "alloc")]
    fn buffer(self, capacity: usize) -> Buffer<Self, Item>
        where Self: Sized,
    {
        Buffer::new(self, capacity)
    }

    /// Close the sink.
    fn close(&mut self) -> Close<'_, Self, Item>
        where Self: Unpin,
    {
        Close::new(self)
    }

    /// Fanout items to multiple sinks.
    ///
    /// This adapter clones each incoming item and forwards it to both this as well as
    /// the other sink at the same time.
    fn fanout<Si>(self, other: Si) -> Fanout<Self, Si>
        where Self: Sized,
              Item: Clone,
              Si: Sink<Item, Error=Self::Error>
    {
        Fanout::new(self, other)
    }

    /// Flush the sink, processing all pending items.
    ///
    /// This adapter is intended to be used when you want to stop sending to the sink
    /// until all current requests are processed.
    fn flush(&mut self) -> Flush<'_, Self, Item>
        where Self: Unpin,
    {
        Flush::new(self)
    }

    /// A future that completes after the given item has been fully processed
    /// into the sink, including flushing.
    ///
    /// Note that, **because of the flushing requirement, it is usually better
    /// to batch together items to send via `send_all`, rather than flushing
    /// between each item.**
    fn send(&mut self, item: Item) -> Send<'_, Self, Item>
        where Self: Unpin,
    {
        Send::new(self, item)
    }

    /// A future that completes after the given stream has been fully processed
    /// into the sink, including flushing.
    ///
    /// This future will drive the stream to keep producing items until it is
    /// exhausted, sending each item to the sink. It will complete once both the
    /// stream is exhausted, the sink has received all items, and the sink has
    /// been flushed. Note that the sink is **not** closed.
    ///
    /// Doing `sink.send_all(stream)` is roughly equivalent to
    /// `stream.forward(sink)`. The returned future will exhaust all items from
    /// `stream` and send them to `self`.
    fn send_all<'a, St>(
        &'a mut self,
        stream: &'a mut St
    ) -> SendAll<'a, Self, St>
        where St: TryStream<Ok = Item, Error = Self::Error> + Stream + Unpin + ?Sized,
              Self: Unpin,
    {
        SendAll::new(self, stream)
    }

    /// Wrap this sink in an `Either` sink, making it the left-hand variant
    /// of that `Either`.
    ///
    /// This can be used in combination with the `right_sink` method to write `if`
    /// statements that evaluate to different streams in different branches.
    fn left_sink<Si2>(self) -> Either<Self, Si2>
        where Si2: Sink<Item, Error = Self::Error>,
              Self: Sized
    {
        Either::Left(self)
    }

    /// Wrap this stream in an `Either` stream, making it the right-hand variant
    /// of that `Either`.
    ///
    /// This can be used in combination with the `left_sink` method to write `if`
    /// statements that evaluate to different streams in different branches.
    fn right_sink<Si1>(self) -> Either<Si1, Self>
        where Si1: Sink<Item, Error = Self::Error>,
              Self: Sized
    {
        Either::Right(self)
    }

    /// Wraps a [`Sink`] into a sink compatible with libraries using
    /// futures 0.1 `Sink`. Requires the `compat` feature to be enabled.
    #[cfg(feature = "compat")]
    fn compat(self) -> CompatSink<Self, Item>
        where Self: Sized + Unpin,
    {
        CompatSink::new(self)
    }
}
<commit_msg>Add `*_unpin` methods to `SinkExt`<commit_after>//! Sinks
//!
//! This module contains a number of functions for working with `Sink`s,
//! including the `SinkExt` trait which adds methods to `Sink` types.
//!
//! This module is only available when the `sink` feature of this
//! library is activated, and it is activated by default.

use core::pin::Pin;
use futures_core::future::Future;
use futures_core::stream::{Stream, TryStream};
use futures_core::task::{Context, Poll};
use crate::future::Either;

#[cfg(feature = "compat")]
use crate::compat::CompatSink;

pub use futures_sink::Sink;

mod close;
pub use self::close::Close;

mod drain;
pub use self::drain::{drain, Drain};

mod fanout;
pub use self::fanout::Fanout;

mod flush;
pub use self::flush::Flush;

mod err_into;
pub use self::err_into::SinkErrInto;

mod map_err;
pub use self::map_err::SinkMapErr;

mod send;
pub use self::send::Send;

mod send_all;
pub use self::send_all::SendAll;

mod with;
pub use self::with::With;

mod with_flat_map;
pub use self::with_flat_map::WithFlatMap;

#[cfg(feature = "alloc")]
mod buffer;
#[cfg(feature = "alloc")]
pub use self::buffer::Buffer;

impl<T: ?Sized, Item> SinkExt<Item> for T where T: Sink<Item> {}

/// An extension trait for `Sink`s that provides a variety of convenient
/// combinator functions.
pub trait SinkExt<Item>: Sink<Item> {
    /// Composes a function *in front of* the sink.
    ///
    /// This adapter produces a new sink that passes each value through the
    /// given function `f` before sending it to `self`.
    ///
    /// To process each value, `f` produces a *future*, which is then polled to
    /// completion before passing its result down to the underlying sink. If the
    /// future produces an error, that error is returned by the new sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F>
        where F: FnMut(U) -> Fut,
              Fut: Future<Output = Result<Item, E>>,
              E: From<Self::Error>,
              Self: Sized
    {
        With::new(self, f)
    }

    /// Composes a function *in front of* the sink.
    ///
    /// This adapter produces a new sink that passes each value through the
    /// given function `f` before sending it to `self`.
    ///
    /// To process each value, `f` produces a *stream*, of which each value
    /// is passed to the underlying sink. A new value will not be accepted until
    /// the stream has been drained
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::flat_map`.
    ///
    /// # Examples
    ///
    /// ```
    /// # futures::executor::block_on(async {
    /// use futures::channel::mpsc;
    /// use futures::sink::SinkExt;
    /// use futures::stream::{self, StreamExt};
    ///
    /// let (tx, rx) = mpsc::channel(5);
    ///
    /// let mut tx = tx.with_flat_map(|x| {
    ///     stream::iter(vec![Ok(42); x])
    /// });
    ///
    /// tx.send(5).await.unwrap();
    /// drop(tx);
    /// let received: Vec<i32> = rx.collect().await;
    /// assert_eq!(received, vec![42, 42, 42, 42, 42]);
    /// # });
    /// ```
    fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F>
        where F: FnMut(U) -> St,
              St: Stream<Item = Result<Item, Self::Error>>,
              Self: Sized
    {
        WithFlatMap::new(self, f)
    }

    /*
    fn with_map<U, F>(self, f: F) -> WithMap<Self, U, F>
        where F: FnMut(U) -> Self::SinkItem,
              Self: Sized;

    fn with_filter<F>(self, f: F) -> WithFilter<Self, F>
        where F: FnMut(Self::SinkItem) -> bool,
              Self: Sized;

    fn with_filter_map<U, F>(self, f: F) -> WithFilterMap<Self, U, F>
        where F: FnMut(U) -> Option<Self::SinkItem>,
              Self: Sized;
     */

    /// Transforms the error returned by the sink.
    fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F>
        where F: FnOnce(Self::Error) -> E,
              Self: Sized,
    {
        SinkMapErr::new(self, f)
    }

    /// Map this sink's error to a different error type using the `Into` trait.
    ///
    /// If wanting to map errors of a `Sink + Stream`, use `.sink_err_into().err_into()`.
    fn sink_err_into<E>(self) -> err_into::SinkErrInto<Self, Item, E>
        where Self: Sized,
              Self::Error: Into<E>,
    {
        SinkErrInto::new(self)
    }

    /// Adds a fixed-size buffer to the current sink.
    ///
    /// The resulting sink will buffer up to `capacity` items when the
    /// underlying sink is unwilling to accept additional items. Calling `flush`
    /// on the buffered sink will attempt to both empty the buffer and complete
    /// processing on the underlying sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    ///
    /// This method is only available when the `std` or `alloc` feature of this
    /// library is activated, and it is activated by default.
    #[cfg(feature = "alloc")]
    fn buffer(self, capacity: usize) -> Buffer<Self, Item>
        where Self: Sized,
    {
        Buffer::new(self, capacity)
    }

    /// Close the sink.
    fn close(&mut self) -> Close<'_, Self, Item>
        where Self: Unpin,
    {
        Close::new(self)
    }

    /// Fanout items to multiple sinks.
    ///
    /// This adapter clones each incoming item and forwards it to both this as well as
    /// the other sink at the same time.
    fn fanout<Si>(self, other: Si) -> Fanout<Self, Si>
        where Self: Sized,
              Item: Clone,
              Si: Sink<Item, Error=Self::Error>
    {
        Fanout::new(self, other)
    }

    /// Flush the sink, processing all pending items.
    ///
    /// This adapter is intended to be used when you want to stop sending to the sink
    /// until all current requests are processed.
    fn flush(&mut self) -> Flush<'_, Self, Item>
        where Self: Unpin,
    {
        Flush::new(self)
    }

    /// A future that completes after the given item has been fully processed
    /// into the sink, including flushing.
    ///
    /// Note that, **because of the flushing requirement, it is usually better
    /// to batch together items to send via `send_all`, rather than flushing
    /// between each item.**
    fn send(&mut self, item: Item) -> Send<'_, Self, Item>
        where Self: Unpin,
    {
        Send::new(self, item)
    }

    /// A future that completes after the given stream has been fully processed
    /// into the sink, including flushing.
    ///
    /// This future will drive the stream to keep producing items until it is
    /// exhausted, sending each item to the sink. It will complete once both the
    /// stream is exhausted, the sink has received all items, and the sink has
    /// been flushed. Note that the sink is **not** closed.
    ///
    /// Doing `sink.send_all(stream)` is roughly equivalent to
    /// `stream.forward(sink)`. The returned future will exhaust all items from
    /// `stream` and send them to `self`.
    fn send_all<'a, St>(
        &'a mut self,
        stream: &'a mut St
    ) -> SendAll<'a, Self, St>
        where St: TryStream<Ok = Item, Error = Self::Error> + Stream + Unpin + ?Sized,
              Self: Unpin,
    {
        SendAll::new(self, stream)
    }

    /// Wrap this sink in an `Either` sink, making it the left-hand variant
    /// of that `Either`.
    ///
    /// This can be used in combination with the `right_sink` method to write `if`
    /// statements that evaluate to different streams in different branches.
    fn left_sink<Si2>(self) -> Either<Self, Si2>
        where Si2: Sink<Item, Error = Self::Error>,
              Self: Sized
    {
        Either::Left(self)
    }

    /// Wrap this stream in an `Either` stream, making it the right-hand variant
    /// of that `Either`.
    ///
    /// This can be used in combination with the `left_sink` method to write `if`
    /// statements that evaluate to different streams in different branches.
    fn right_sink<Si1>(self) -> Either<Si1, Self>
        where Si1: Sink<Item, Error = Self::Error>,
              Self: Sized
    {
        Either::Right(self)
    }

    /// Wraps a [`Sink`] into a sink compatible with libraries using
    /// futures 0.1 `Sink`. Requires the `compat` feature to be enabled.
    #[cfg(feature = "compat")]
    fn compat(self) -> CompatSink<Self, Item>
        where Self: Sized + Unpin,
    {
        CompatSink::new(self)
    }

    /// A convenience method for calling [`Sink::poll_ready`] on [`Unpin`]
    /// sink types.
    fn poll_ready_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>
        where Self: Unpin
    {
        Pin::new(self).poll_ready(cx)
    }

    /// A convenience method for calling [`Sink::start_send`] on [`Unpin`]
    /// sink types.
    fn start_send_unpin(&mut self, item: Item) -> Result<(), Self::Error>
        where Self: Unpin
    {
        Pin::new(self).start_send(item)
    }

    /// A convenience method for calling [`Sink::poll_flush`] on [`Unpin`]
    /// sink types.
    fn poll_flush_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>
        where Self: Unpin
    {
        Pin::new(self).poll_flush(cx)
    }

    /// A convenience method for calling [`Sink::poll_close`] on [`Unpin`]
    /// sink types.
    fn poll_close_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>
        where Self: Unpin
    {
        Pin::new(self).poll_close(cx)
    }
}
<|endoftext|>


<commit_before>#![cfg(feature="inline-systemd")]
extern crate specinfra;

use specinfra::backend;

#[test]
fn service_resource() {
    let b = backend::direct::Direct::new();
    let s = specinfra::new(&b).unwrap();

    let dbus = s.service("dbus.service");
    assert!(dbus.is_running().unwrap());

    let dbus = s.service("dbus");
    assert!(dbus.is_running().unwrap());

    let sshd = s.service("sshd");
    assert!(sshd.is_enabled().unwrap());

    let nginx = s.service("nginx");
    assert!(nginx.enable().unwrap());
    assert!(nginx.is_enabled().unwrap());
    assert!(nginx.disable().unwrap());
    assert_eq!(nginx.is_enabled().unwrap(), false);

    assert!(nginx.start().unwrap());
    assert!(nginx.is_running().unwrap());

    assert!(nginx.reload().unwrap());
    assert!(nginx.is_running().unwrap());

    assert!(nginx.restart().unwrap());
    assert!(nginx.is_running().unwrap());

    assert!(nginx.stop().unwrap());
    assert_eq!(nginx.is_running().unwrap(), false);
}
<commit_msg>Separate function into two functions to test inline and shell providers<commit_after>#![cfg(feature="inline-systemd")]
extern crate specinfra;

use specinfra::backend;

#[test]
fn service_resource_with_inline_provider() {
    let b = backend::direct::Direct::new();
    let s = specinfra::new(&b).unwrap();
    test_service_resource(s);
}

fn test_service_resource(s: specinfra::Specinfra) {
    let dbus = s.service("dbus.service");
    assert!(dbus.is_running().unwrap());

    let dbus = s.service("dbus");
    assert!(dbus.is_running().unwrap());

    let sshd = s.service("sshd");
    assert!(sshd.is_enabled().unwrap());

    let nginx = s.service("nginx");
    assert!(nginx.enable().unwrap());
    assert!(nginx.is_enabled().unwrap());
    assert!(nginx.disable().unwrap());
    assert_eq!(nginx.is_enabled().unwrap(), false);

    assert!(nginx.start().unwrap());
    assert!(nginx.is_running().unwrap());

    assert!(nginx.reload().unwrap());
    assert!(nginx.is_running().unwrap());

    assert!(nginx.restart().unwrap());
    assert!(nginx.is_running().unwrap());

    assert!(nginx.stop().unwrap());
    assert_eq!(nginx.is_running().unwrap(), false);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use byteorder::WriteBytesExt;
use byteorder::LittleEndian as LE;
use conn::Conn;
use conn::futures::write_packet::WritePacket;
use conn::stmt::InnerStmt;
use consts::Command;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Done;
use lib_futures::done;
use lib_futures::Future;
use lib_futures::Poll;
use std::io::Write;
use std::mem;
use value::Value;
use value::Value::*;

steps! {
    SendLongData {
        Init(Done<Conn, Error>),
        WritePacket(WritePacket),
    }
}

/// Future that sends part of statement parametes via MySql's `COM_STMT_SEND_LONG_DATA`.
///
/// It resolves to `Conn`, `InnerStmt` and statement parameters.
pub struct SendLongData {
    step: Step,
    inner_stmt: Option<InnerStmt>,
    params: Vec<Value>,
    ids: Vec<u16>,
    next_chunk: usize,
}

pub fn new(conn: Conn, inner_stmt: InnerStmt, params: Vec<Value>, ids: Vec<u16>) -> SendLongData {
    SendLongData {
        step: Step::Init(done(Ok(conn))),
        inner_stmt: Some(inner_stmt),
        params: params,
        ids: ids,
        next_chunk: 0
    }
}

impl Future for SendLongData {
    type Item = (Conn, InnerStmt, Vec<Value>);
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.either_poll()) {
            Out::Init(conn) | Out::WritePacket(conn) => {
                let data = match self.ids.pop() {
                    Some(id) => match self.params[id as usize] {
                        Bytes(ref x) => {
                            let max_allowed_packet = conn.max_allowed_packet as usize;
                            let stmt_id = self.inner_stmt.as_ref().unwrap().statement_id;
                            let mut chunks = x.chunks(max_allowed_packet - 8);
                            match chunks.nth(self.next_chunk) {
                                Some(chunk) => {
                                    let mut buf = Vec::with_capacity(chunk.len() + 7);
                                    buf.write_u32::<LE>(stmt_id).unwrap();
                                    buf.write_u16::<LE>(id).unwrap();
                                    buf.write_all(chunk).unwrap();
                                    if chunk.len() < max_allowed_packet - 8 {
                                        Some((buf, 0, None))
                                    } else {
                                        Some((buf, 1, Some(id)))
                                    }
                                },
                                None => {
                                    let mut buf = Vec::with_capacity(8);
                                    buf.write_u32::<LE>(stmt_id).unwrap();
                                    buf.write_u16::<LE>(id).unwrap();
                                    Some((buf, 0, None))
                                }
                            }
                        },
                        _ => unreachable!(),
                    },
                    None => None,
                };
                match data {
                    Some((data, next_chunk, id)) => {
                        if let Some(id) = id {
                            self.ids.push(id);
                        }
                        self.next_chunk = next_chunk;
                        let future = conn.write_command_data(Command::COM_STMT_SEND_LONG_DATA, data);
                        self.step = Step::WritePacket(future);
                        self.poll()
                    },
                    None => {
                        let stmt = self.inner_stmt.take().unwrap();
                        let params = mem::replace(&mut self.params, vec![]);
                        Ok(Ready((conn, stmt, params)))
                    }
                }
            },
        }
    }
}
<commit_msg>Fix corner case in send_long_data<commit_after>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use byteorder::WriteBytesExt;
use byteorder::LittleEndian as LE;
use conn::Conn;
use conn::futures::write_packet::WritePacket;
use conn::stmt::InnerStmt;
use consts::Command;
use errors::*;
use lib_futures::Async;
use lib_futures::Async::Ready;
use lib_futures::Done;
use lib_futures::done;
use lib_futures::Future;
use lib_futures::Poll;
use std::io::Write;
use std::mem;
use value::Value;
use value::Value::*;

steps! {
    SendLongData {
        Init(Done<Conn, Error>),
        WritePacket(WritePacket),
    }
}

/// Future that sends part of statement parametes via MySql's `COM_STMT_SEND_LONG_DATA`.
///
/// It resolves to `Conn`, `InnerStmt` and statement parameters.
pub struct SendLongData {
    step: Step,
    inner_stmt: Option<InnerStmt>,
    params: Vec<Value>,
    ids: Vec<u16>,
    next_chunk: usize,
}

impl SendLongData {
    fn next_chunk(&mut self, max_allowed_packet: usize) -> Option<Vec<u8>> {
        let chunk_meta = match self.ids.pop() {
            Some(id) => match self.params[id as usize] {
                Bytes(ref x) => {
                    let stmt_id = self.inner_stmt.as_ref().unwrap().statement_id;
                    let mut chunks = x.chunks(max_allowed_packet - 8);
                    match chunks.nth(self.next_chunk) {
                        Some(chunk) => {
                            let mut buf = Vec::with_capacity(chunk.len() + 7);
                            buf.write_u32::<LE>(stmt_id).unwrap();
                            buf.write_u16::<LE>(id).unwrap();
                            buf.write_all(chunk).unwrap();
                            if chunk.len() < max_allowed_packet - 8 {
                                Some((buf, 0, None))
                            } else {
                                Some((buf, 1, Some(id)))
                            }
                        },
                        None => {
                            Some((Vec::new(), 0, None))
                        }
                    }
                },
                _ => unreachable!(),
            },
            None => None,
        };

        match chunk_meta {
            Some((data, next_chunk, maybe_id)) => {
                if let Some(id) = maybe_id {
                    self.ids.push(id);
                }
                self.next_chunk = next_chunk;
                if data.len() == 0 {
                    self.next_chunk(max_allowed_packet)
                } else {
                    Some(data)
                }
            },
            None => None,
        }
    }
}

pub fn new(conn: Conn, inner_stmt: InnerStmt, params: Vec<Value>, ids: Vec<u16>) -> SendLongData {
    SendLongData {
        step: Step::Init(done(Ok(conn))),
        inner_stmt: Some(inner_stmt),
        params: params,
        ids: ids,
        next_chunk: 0
    }
}

impl Future for SendLongData {
    type Item = (Conn, InnerStmt, Vec<Value>);
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match try_ready!(self.either_poll()) {
            Out::Init(conn) | Out::WritePacket(conn) => {
                match self.next_chunk(conn.max_allowed_packet as usize) {
                    Some(data) => {
                        let future = conn.write_command_data(Command::COM_STMT_SEND_LONG_DATA, data);
                        self.step = Step::WritePacket(future);
                        self.poll()
                    },
                    None => {
                        let stmt = self.inner_stmt.take().unwrap();
                        let params = mem::replace(&mut self.params, vec![]);
                        Ok(Ready((conn, stmt, params)))
                    }
                }
            },
        }
    }
}
<|endoftext|>


<commit_before>use super::super::{
    Request,
    SetupRequest,
};
use curl::easy::{
    Easy2,
    Handler,
    ReadError,
};
use http_types::Method;

// This trait has to be implemented by the Easy2<H>'s H generic type, as well as curl's Handler.
// This is because the body of POST requests needs to be pushed from the storage associated to
// that type, so this trait provides a method to store the body String and a method to copy data
// by providing just an offset as multiple calls to push the data happen.
pub trait SetBody: Handler {
    // Static method to copy data over starting from an offset, return the number of bytes that
    // were copied and updating the offset.
    #[inline]
    fn copy_data(offset: &mut usize, source: &[u8], dest: &mut [u8]) -> usize {
        super::copy_data(offset, source, dest)
    }

    // This method should store the body data to be pushed by this request.
    fn set_body(&mut self, body: String);
}

// A default type that works with the requirements of conversion between a Request and a set up
// Easy2 client by implementing the SetBody trait.
#[derive(Debug)]
pub struct BodyHandle {
    count: usize,
    body:  Option<String>,
}

impl BodyHandle {
    pub fn new() -> Self {
        Self { count: 0,
               body:  None, }
    }

    pub fn with_body(&mut self, body: Option<String>) {
        self.body = body;
    }
}

impl Default for BodyHandle {
    fn default() -> Self {
        Self::new()
    }
}

impl Handler for BodyHandle {
    fn read(&mut self, data: &mut [u8]) -> Result<usize, ReadError> {
        // we should never have this called on requests without a body
        debug_assert!(self.body.is_some());

        if let Some(ref body) = self.body {
            Ok(Self::copy_data(&mut self.count, &body.as_bytes(), data))
        } else {
            unreachable!()
        }
    }
}

impl SetBody for BodyHandle {
    fn set_body(&mut self, body: String) {
        self.with_body(body.into());
    }
}

impl<URI: ToString, H: SetBody> SetupRequest<'_, URI, ()> for Easy2<H> {
    fn setup_request(&mut self, r: Request, params: URI) {
        let (uri, body) = r.parameters.uri_and_body(r.path);
        let uri_base = params;
        let uri = uri_base.to_string() + uri.as_ref();

        match r.method {
            Method::GET => self.get(true),
            Method::POST => self.post(true),
            Method::PUT => self.put(true),
            // any other verb needs to use custom_request()
            m => self.custom_request(m.as_str()),
        }.expect("failed to set up the request's method");

        self.url(uri.as_str()).expect("error setting up url for curl");
        let mut headerlist = super::headermap_to_curl_list(&r.headers);
        // libcurl by default adds "Expect: 100-continue" to send bodies, which would break us
        headerlist.append("Expect:")
                  .expect("failed to allocate node for curl list of headers");
        // don't specify Content-Type for this request (similar to other clients)
        headerlist.append("Content-Type:")
                  .expect("failed to allocate node for curl list of headers");
        self.http_headers(headerlist)
            .expect("error setting up headers for curl");

        if body.is_some() {
            let body = r.parameters.into_inner();
            // this sets the Content-Length - some servers will misbehave without this
            self.post_field_size(body.len() as u64)
                .expect("failed to set post size");

            self.get_mut().set_body(body);
        }
    }
}
<commit_msg>request/easy2: mark some comments as documentation<commit_after>use super::super::{
    Request,
    SetupRequest,
};
use curl::easy::{
    Easy2,
    Handler,
    ReadError,
};
use http_types::Method;

/// This trait has to be implemented by the Easy2<H>'s H generic type, as well as curl's Handler.
/// This is because the body of POST requests needs to be pushed from the storage associated to
/// that type, so this trait provides a method to store the body String and a method to copy data
/// by providing just an offset as multiple calls to push the data happen.
pub trait SetBody: Handler {
    /// Static method to copy data over starting from an offset, return the number of bytes that
    /// were copied and updating the offset.
    #[inline]
    fn copy_data(offset: &mut usize, source: &[u8], dest: &mut [u8]) -> usize {
        super::copy_data(offset, source, dest)
    }

    /// This method should store the body data to be pushed by this request.
    fn set_body(&mut self, body: String);
}

/// A default type that works with the requirements of conversion between a Request and a set up
/// Easy2 client by implementing the SetBody trait.
#[derive(Debug, Clone)]
pub struct BodyHandle {
    count: usize,
    body:  Option<String>,
}

impl BodyHandle {
    pub fn new() -> Self {
        Self { count: 0,
               body:  None, }
    }

    /// A method to set/unset the body. To be used from a SetBody trait impl.
    pub fn with_body(&mut self, body: Option<String>) {
        self.body = body;
    }
}

impl Default for BodyHandle {
    fn default() -> Self {
        Self::new()
    }
}

impl Handler for BodyHandle {
    fn read(&mut self, data: &mut [u8]) -> Result<usize, ReadError> {
        // we should never have this called on requests without a body
        debug_assert!(self.body.is_some());

        if let Some(ref body) = self.body {
            Ok(Self::copy_data(&mut self.count, &body.as_bytes(), data))
        } else {
            unreachable!()
        }
    }
}

impl SetBody for BodyHandle {
    fn set_body(&mut self, body: String) {
        self.with_body(body.into());
    }
}

impl<URI: ToString, H: SetBody> SetupRequest<'_, URI, ()> for Easy2<H> {
    fn setup_request(&mut self, r: Request, params: URI) {
        let (uri, body) = r.parameters.uri_and_body(r.path);
        let uri_base = params;
        let uri = uri_base.to_string() + uri.as_ref();

        match r.method {
            Method::GET => self.get(true),
            Method::POST => self.post(true),
            Method::PUT => self.put(true),
            // any other verb needs to use custom_request()
            m => self.custom_request(m.as_str()),
        }.expect("failed to set up the request's method");

        self.url(uri.as_str()).expect("error setting up url for curl");
        let mut headerlist = super::headermap_to_curl_list(&r.headers);
        // libcurl by default adds "Expect: 100-continue" to send bodies, which would break us
        headerlist.append("Expect:")
                  .expect("failed to allocate node for curl list of headers");
        // don't specify Content-Type for this request (similar to other clients)
        headerlist.append("Content-Type:")
                  .expect("failed to allocate node for curl list of headers");
        self.http_headers(headerlist)
            .expect("error setting up headers for curl");

        if body.is_some() {
            let body = r.parameters.into_inner();
            // this sets the Content-Length - some servers will misbehave without this
            self.post_field_size(body.len() as u64)
                .expect("failed to set post size");

            self.get_mut().set_body(body);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(plugin, convert, path_ext, box_syntax, rustc_private)]

#![plugin(oak)]

extern crate oak_runtime;
extern crate term;

use oak_runtime::*;
use grammars::*;

use std::path::{PathBuf, Path};
use std::fs::{File, read_dir, PathExt};
use std::io;
use std::io::Read;

use term::*;
use ExpectedResult::*;

mod grammars;

#[test]
fn test_data_directory()
{
  let data_path = Path::new("data/");
  if !data_path.is_dir() {
    panic!(format!("`{}` is not a valid data directory.", data_path.display()));
  }
  let mut test_path = PathBuf::new();
  test_path.push(data_path);
  test_path.push(Path::new("test"));
  let mut test_engine = TestEngine::new(test_path);
  test_engine.register("ntcc", Box::new(|content|
    ntcc::recognize_ntcc(content.stream())));
  test_engine.register("type_name", Box::new(|content|
    type_name::recognize_type_names(content.stream())));
  test_engine.register("calc", Box::new(|content|
    calc::recognize_program(content.stream())));

  test_engine.run();
}

struct TestEngine
{
  test_path: PathBuf,
  grammars: Vec<GrammarInfo>,
  display: TestDisplay
}

impl TestEngine
{
  fn new(test_path: PathBuf) -> TestEngine
  {
    if !test_path.is_dir() {
      panic!(format!("`{}` is not a valid grammar directory.", test_path.display()));
    }
    TestEngine{
      test_path: test_path,
      grammars: Vec::new(),
      display: TestDisplay::new()
    }
  }

  fn register(&mut self, name: &str, recognizer: Box<for<'a> Fn(&'a str) -> ParseState<StrStream<'a>, ()>>)
  {
    self.grammars.push(GrammarInfo{name: String::from(name), recognizer: recognizer});
  }

  fn run(&mut self)
  {
    self.display.title("    Oak library tests suite");
    for grammar in self.grammars.iter() {
      let grammar_path = self.test_path.join(Path::new(grammar.name.as_str()));
      self.display.info(&format!("Start tests of the grammar `{}`", grammar.name));
      self.display.path(&grammar_path);
      let mut test = Test{
        info: grammar,
        display: &mut self.display
      };
      test.test_directory(&format!("Run and Pass tests of `{}`", grammar.name),
        &grammar_path.join(Path::new("run-pass")), Match);
      test.test_directory(&format!("Run and Fail tests of `{}`", grammar.name),
        &grammar_path.join(Path::new("run-fail")), Error);
    }
    self.display.stats();
    self.display.panic_if_failure();
  }
}

struct GrammarInfo
{
  name: String,
  recognizer: Box<for<'a> Fn(&'a str) -> ParseState<StrStream<'a>, ()>>
}

#[derive(Clone)]
enum ExpectedResult {
  Match,
  Error
}

struct Test<'a>
{
  info: &'a GrammarInfo,
  display: &'a mut TestDisplay,
}

impl<'a> Test<'a>
{
  fn test_directory(&mut self, start_msg: &String, directory: &Path, expectation: ExpectedResult)
  {
    self.display.info(start_msg);

    match read_dir(directory) {
      Ok(dir_entries) => {
        for entry in dir_entries.map(Result::unwrap).map(|entry| entry.path()) {
          if entry.is_file() {
            self.test_file(entry.as_path(), expectation.clone());
          } else {
            self.display.warn(&format!("Entry ignored because it's not a file."));
            self.display.path(entry.as_path());
          }
        }
      }
      Err(ref io_err) => {
        self.display.fs_error("Can't read directory.", directory, io_err);
      }
    }
  }

  fn test_file(&mut self, filepath: &Path, expectation: ExpectedResult)
  {
    let mut file = File::open(filepath);
    match file {
      Ok(ref mut file) => {
        let mut buf_contents = vec![];
        let contents = file.read_to_end(&mut buf_contents);
        match contents {
          Ok(_) => {
            let utf8_contents = std::str::from_utf8(buf_contents.as_slice());
            self.test_input(utf8_contents.unwrap(), expectation, filepath);
          },
          Err(ref io_err) => {
            self.display.fs_error("Can't read file.", filepath, io_err);
          }
        }
      },
      Err(ref io_err) => {
        self.display.fs_error("Can't open file.", filepath, io_err);
      }
    }
  }

  fn test_input(&mut self, input: &str, expectation: ExpectedResult, test_path: &Path)
  {
    let state = (self.info.recognizer)(input);
    let result = state.into_result();
    match (expectation.clone(), result) {
      (Match, Ok((ref state, _))) if state.full_read() => self.display.success(test_path),
      (Error, Ok((ref state, _))) if state.partial_read() => self.display.success(test_path),
      (Error, Err(_)) => self.display.success(test_path),
      (_, state) => {
        self.display.failure(test_path, expectation, state);
      }
    }
  }
}

struct TestDisplay
{
  terminal: Box<Terminal<WriterWrapper>+'static>,
  num_success: u32,
  num_failure: u32,
  num_system_failure: u32
}

impl TestDisplay
{
  pub fn new() -> TestDisplay
  {
    TestDisplay{
      terminal: term::stdout().unwrap(),
      num_success: 0,
      num_failure: 0,
      num_system_failure: 0
    }
  }

  pub fn title(&mut self, msg: &str)
  {
    self.write_header(term::color::CYAN, msg);
    self.write_msg("\n\n");
  }

  pub fn info(&mut self, msg: &String)
  {
    self.write_line(term::color::CYAN, "\n[ info ] ", msg);
  }

  pub fn error(&mut self, msg: &String)
  {
    self.write_line(term::color::RED, "  [ error ] ", msg);
  }

  pub fn path(&mut self, path: &Path)
  {
    self.write_line(term::color::CYAN, "  [ path ] ",
      &format!("{}", path.display()));
  }

  pub fn stats(&mut self)
  {
    let system_failure_plural = if self.num_system_failure > 1 { "s" } else { "" };
    let msg = format!("{} passed, {} failed, {} system failure{}.",
        self.num_success, self.num_failure, self.num_system_failure,
        system_failure_plural);
    self.write_line(term::color::BLUE, "\n\n[ stats ] ", &msg);
  }

  pub fn panic_if_failure(&self)
  {
    if self.num_failure > 0 || self.num_system_failure > 0 {
      panic!("");
    }
  }

  pub fn failure(&mut self, path: &Path, expectation: ExpectedResult,
    result: ParseResult<StrStream, ()>)
  {
    self.num_failure += 1;
    let test_name = self.file_stem(path);
    self.write_line(term::color::RED, "[ failed ] ", &test_name);
    self.path(path);
    self.expected(expectation);
    self.wrong_result(result);
  }

  fn expected(&mut self, expectation: ExpectedResult)
  {
    let msg = match expectation {
      Match => "Fully match",
      Error => "Error"
    };
    self.write_line(term::color::CYAN, "  [ expected ] ", &format!("{}", msg))
  }

  fn wrong_result(&mut self, result: ParseResult<StrStream, ()>)
  {
    let msg = match result {
      Ok((ref state, ref err)) if state.partial_read() => {
        format!("Partial match. `{}`", err)
      }
      Ok(_) => format!("Fully matched."),
      Err(err) => format!("{}", err)
    };
    self.error(&msg)
  }

  pub fn success(&mut self, path: &Path)
  {
    self.num_success += 1;
    let test_name = self.file_stem(path);
    self.write_line(term::color::GREEN, "[ passed ] ", &test_name);
  }

  fn file_stem(&self, path: &Path) -> String
  {
    format!("{}", path.file_stem().unwrap().to_str().unwrap())
  }

  pub fn warn(&mut self, msg: &String)
  {
    self.write_line(term::color::YELLOW, "  [ warning ] ", msg);
  }

  pub fn fs_error(&mut self, msg: &str, path: &Path, io_err: &io::Error)
  {
    self.system_failure(&format!("{}", msg));
    self.path(path);
    self.error(&format!("{}", io_err));
  }

  pub fn system_failure(&mut self, msg: &String)
  {
    self.num_system_failure += 1;
    self.write_line(term::color::RED, "[ system error ] ", msg);
  }

  fn write_line(&mut self, color: color::Color, header: &str, msg: &String)
  {
    self.write_header(color, header);
    self.write_msg(msg.as_str());
    self.write_msg("\n");
  }

  fn write_header(&mut self, color: color::Color, header: &str)
  {
    self.terminal.fg(color).unwrap();
    self.write_msg(header);
    self.terminal.reset().unwrap();
  }

  fn write_msg(&mut self, msg: &str)
  {
    (write!(self.terminal, "{}", msg)).unwrap();
  }
}
<commit_msg>[Rust update] Use inherent method of Path instead of PathExt which is deprecated now.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(plugin, convert, box_syntax, rustc_private)]

#![plugin(oak)]

extern crate oak_runtime;
extern crate term;

use oak_runtime::*;
use grammars::*;

use std::path::{PathBuf, Path};
use std::fs::{File, read_dir};
use std::io;
use std::io::Read;

use term::*;
use ExpectedResult::*;

mod grammars;

#[test]
fn test_data_directory()
{
  let data_path = Path::new("data/");
  if !data_path.is_dir() {
    panic!(format!("`{}` is not a valid data directory.", data_path.display()));
  }
  let mut test_path = PathBuf::new();
  test_path.push(data_path);
  test_path.push(Path::new("test"));
  let mut test_engine = TestEngine::new(test_path);
  test_engine.register("ntcc", Box::new(|content|
    ntcc::recognize_ntcc(content.stream())));
  test_engine.register("type_name", Box::new(|content|
    type_name::recognize_type_names(content.stream())));
  test_engine.register("calc", Box::new(|content|
    calc::recognize_program(content.stream())));

  test_engine.run();
}

struct TestEngine
{
  test_path: PathBuf,
  grammars: Vec<GrammarInfo>,
  display: TestDisplay
}

impl TestEngine
{
  fn new(test_path: PathBuf) -> TestEngine
  {
    if !test_path.is_dir() {
      panic!(format!("`{}` is not a valid grammar directory.", test_path.display()));
    }
    TestEngine{
      test_path: test_path,
      grammars: Vec::new(),
      display: TestDisplay::new()
    }
  }

  fn register(&mut self, name: &str, recognizer: Box<for<'a> Fn(&'a str) -> ParseState<StrStream<'a>, ()>>)
  {
    self.grammars.push(GrammarInfo{name: String::from(name), recognizer: recognizer});
  }

  fn run(&mut self)
  {
    self.display.title("    Oak library tests suite");
    for grammar in self.grammars.iter() {
      let grammar_path = self.test_path.join(Path::new(grammar.name.as_str()));
      self.display.info(&format!("Start tests of the grammar `{}`", grammar.name));
      self.display.path(&grammar_path);
      let mut test = Test{
        info: grammar,
        display: &mut self.display
      };
      test.test_directory(&format!("Run and Pass tests of `{}`", grammar.name),
        &grammar_path.join(Path::new("run-pass")), Match);
      test.test_directory(&format!("Run and Fail tests of `{}`", grammar.name),
        &grammar_path.join(Path::new("run-fail")), Error);
    }
    self.display.stats();
    self.display.panic_if_failure();
  }
}

struct GrammarInfo
{
  name: String,
  recognizer: Box<for<'a> Fn(&'a str) -> ParseState<StrStream<'a>, ()>>
}

#[derive(Clone)]
enum ExpectedResult {
  Match,
  Error
}

struct Test<'a>
{
  info: &'a GrammarInfo,
  display: &'a mut TestDisplay,
}

impl<'a> Test<'a>
{
  fn test_directory(&mut self, start_msg: &String, directory: &Path, expectation: ExpectedResult)
  {
    self.display.info(start_msg);

    match read_dir(directory) {
      Ok(dir_entries) => {
        for entry in dir_entries.map(Result::unwrap).map(|entry| entry.path()) {
          if entry.is_file() {
            self.test_file(entry.as_path(), expectation.clone());
          } else {
            self.display.warn(&format!("Entry ignored because it's not a file."));
            self.display.path(entry.as_path());
          }
        }
      }
      Err(ref io_err) => {
        self.display.fs_error("Can't read directory.", directory, io_err);
      }
    }
  }

  fn test_file(&mut self, filepath: &Path, expectation: ExpectedResult)
  {
    let mut file = File::open(filepath);
    match file {
      Ok(ref mut file) => {
        let mut buf_contents = vec![];
        let contents = file.read_to_end(&mut buf_contents);
        match contents {
          Ok(_) => {
            let utf8_contents = std::str::from_utf8(buf_contents.as_slice());
            self.test_input(utf8_contents.unwrap(), expectation, filepath);
          },
          Err(ref io_err) => {
            self.display.fs_error("Can't read file.", filepath, io_err);
          }
        }
      },
      Err(ref io_err) => {
        self.display.fs_error("Can't open file.", filepath, io_err);
      }
    }
  }

  fn test_input(&mut self, input: &str, expectation: ExpectedResult, test_path: &Path)
  {
    let state = (self.info.recognizer)(input);
    let result = state.into_result();
    match (expectation.clone(), result) {
      (Match, Ok((ref state, _))) if state.full_read() => self.display.success(test_path),
      (Error, Ok((ref state, _))) if state.partial_read() => self.display.success(test_path),
      (Error, Err(_)) => self.display.success(test_path),
      (_, state) => {
        self.display.failure(test_path, expectation, state);
      }
    }
  }
}

struct TestDisplay
{
  terminal: Box<Terminal<WriterWrapper>+'static>,
  num_success: u32,
  num_failure: u32,
  num_system_failure: u32
}

impl TestDisplay
{
  pub fn new() -> TestDisplay
  {
    TestDisplay{
      terminal: term::stdout().unwrap(),
      num_success: 0,
      num_failure: 0,
      num_system_failure: 0
    }
  }

  pub fn title(&mut self, msg: &str)
  {
    self.write_header(term::color::CYAN, msg);
    self.write_msg("\n\n");
  }

  pub fn info(&mut self, msg: &String)
  {
    self.write_line(term::color::CYAN, "\n[ info ] ", msg);
  }

  pub fn error(&mut self, msg: &String)
  {
    self.write_line(term::color::RED, "  [ error ] ", msg);
  }

  pub fn path(&mut self, path: &Path)
  {
    self.write_line(term::color::CYAN, "  [ path ] ",
      &format!("{}", path.display()));
  }

  pub fn stats(&mut self)
  {
    let system_failure_plural = if self.num_system_failure > 1 { "s" } else { "" };
    let msg = format!("{} passed, {} failed, {} system failure{}.",
        self.num_success, self.num_failure, self.num_system_failure,
        system_failure_plural);
    self.write_line(term::color::BLUE, "\n\n[ stats ] ", &msg);
  }

  pub fn panic_if_failure(&self)
  {
    if self.num_failure > 0 || self.num_system_failure > 0 {
      panic!("");
    }
  }

  pub fn failure(&mut self, path: &Path, expectation: ExpectedResult,
    result: ParseResult<StrStream, ()>)
  {
    self.num_failure += 1;
    let test_name = self.file_stem(path);
    self.write_line(term::color::RED, "[ failed ] ", &test_name);
    self.path(path);
    self.expected(expectation);
    self.wrong_result(result);
  }

  fn expected(&mut self, expectation: ExpectedResult)
  {
    let msg = match expectation {
      Match => "Fully match",
      Error => "Error"
    };
    self.write_line(term::color::CYAN, "  [ expected ] ", &format!("{}", msg))
  }

  fn wrong_result(&mut self, result: ParseResult<StrStream, ()>)
  {
    let msg = match result {
      Ok((ref state, ref err)) if state.partial_read() => {
        format!("Partial match. `{}`", err)
      }
      Ok(_) => format!("Fully matched."),
      Err(err) => format!("{}", err)
    };
    self.error(&msg)
  }

  pub fn success(&mut self, path: &Path)
  {
    self.num_success += 1;
    let test_name = self.file_stem(path);
    self.write_line(term::color::GREEN, "[ passed ] ", &test_name);
  }

  fn file_stem(&self, path: &Path) -> String
  {
    format!("{}", path.file_stem().unwrap().to_str().unwrap())
  }

  pub fn warn(&mut self, msg: &String)
  {
    self.write_line(term::color::YELLOW, "  [ warning ] ", msg);
  }

  pub fn fs_error(&mut self, msg: &str, path: &Path, io_err: &io::Error)
  {
    self.system_failure(&format!("{}", msg));
    self.path(path);
    self.error(&format!("{}", io_err));
  }

  pub fn system_failure(&mut self, msg: &String)
  {
    self.num_system_failure += 1;
    self.write_line(term::color::RED, "[ system error ] ", msg);
  }

  fn write_line(&mut self, color: color::Color, header: &str, msg: &String)
  {
    self.write_header(color, header);
    self.write_msg(msg.as_str());
    self.write_msg("\n");
  }

  fn write_header(&mut self, color: color::Color, header: &str)
  {
    self.terminal.fg(color).unwrap();
    self.write_msg(header);
    self.terminal.reset().unwrap();
  }

  fn write_msg(&mut self, msg: &str)
  {
    (write!(self.terminal, "{}", msg)).unwrap();
  }
}
<|endoftext|>


<commit_before>//  notty is a new kind of terminal emulator.
//  Copyright (C) 2015 without boats
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
use std::io;
use std::ffi::CString;
use std::ptr;
use std::sync::Arc;

extern crate libc;

static TIOCSWINSZ: libc::c_ulong = 0x5414;

#[link(name="util")]
extern {
    fn forkpty(amaster: *mut libc::c_int,
               name: *mut libc::c_char,
               termp: *const libc::c_void,
               winsize: *const Winsize) -> libc::pid_t;
}

#[repr(C)]
struct Winsize {
    ws_row: libc::c_ushort,
    ws_col: libc::c_ushort,
    ws_xpixel: libc::c_ushort,
    ws_ypixel: libc::c_ushort,
}

pub fn pty(name: &str, width: u16, height: u16) -> (Reader, Writer) {
    let mut amaster = 0;
    let winsize = Winsize {
        ws_row: height as libc::c_ushort,
        ws_col: width as libc::c_ushort,
        ws_xpixel: 0,
        ws_ypixel: 0
    };
    match unsafe { forkpty(&mut amaster as *mut _,
                           ptr::null_mut(),
                           ptr::null(),
                           &winsize as *const _) } {
        0           => {
            let name = CString::new(name).unwrap();
            unsafe { libc::execvp(name.as_ptr(), ptr::null()); }
            unreachable!();
        }
        n if n > 0  => {
            let handle = Arc::new(Handle(amaster));
            (Reader(handle.clone()), Writer(handle.clone()))
        }
        _           => panic!("Fork failed.")
    }
}

pub struct Reader(Arc<Handle>);

impl io::Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match unsafe {libc::read(**self.0, buf.as_mut_ptr() as *mut _, buf.len() as libc::size_t)}
        {
            n if n >= 0 => Ok(n as usize),
            _           => Err(io::Error::last_os_error()),
        }
    }
}

pub struct Writer(Arc<Handle>);

impl io::Write for Writer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match unsafe {libc::write(**self.0, buf.as_ptr() as *const _, buf.len() as libc::size_t)}
        {
            n if n >= 0 => Ok(n as usize),
            _           => Err(io::Error::last_os_error()),
        }
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

pub struct Handle(libc::c_int);

impl Handle {
    pub fn set_winsize(&self, width: u16, height: u16) -> io::Result<()> {
        let winsize = Winsize {
            ws_row: height as libc::c_ushort,
            ws_col: width as libc::c_ushort,
            ws_xpixel: 0,
            ws_ypixel: 0
        };
        match unsafe { libc::ioctl(**self, TIOCSWINSZ, &winsize as *const _) } {
            -1  => Err(io::Error::last_os_error()),
            _   => Ok(()),
        }
    }
}

impl ::std::ops::Deref for Handle {
    type Target = libc::c_int;
    fn deref(&self) -> &libc::c_int { &self.0 }
}

impl Drop for Handle {
    fn drop(&mut self) {
        unsafe { libc::close(self.0); }
    }
}
<commit_msg>Implement Deref for Reader and Writer in tty.<commit_after>//  notty is a new kind of terminal emulator.
//  Copyright (C) 2015 without boats
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
use std::io;
use std::ffi::CString;
use std::ops::Deref;
use std::ptr;
use std::sync::Arc;

extern crate libc;

static TIOCSWINSZ: libc::c_ulong = 0x5414;

#[link(name="util")]
extern {
    fn forkpty(amaster: *mut libc::c_int,
               name: *mut libc::c_char,
               termp: *const libc::c_void,
               winsize: *const Winsize) -> libc::pid_t;
}

#[repr(C)]
struct Winsize {
    ws_row: libc::c_ushort,
    ws_col: libc::c_ushort,
    ws_xpixel: libc::c_ushort,
    ws_ypixel: libc::c_ushort,
}

pub fn pty(name: &str, width: u16, height: u16) -> (Reader, Writer) {
    let mut amaster = 0;
    let winsize = Winsize {
        ws_row: height as libc::c_ushort,
        ws_col: width as libc::c_ushort,
        ws_xpixel: 0,
        ws_ypixel: 0
    };
    match unsafe { forkpty(&mut amaster as *mut _,
                           ptr::null_mut(),
                           ptr::null(),
                           &winsize as *const _) } {
        0           => {
            let name = CString::new(name).unwrap();
            unsafe { libc::execvp(name.as_ptr(), ptr::null()); }
            unreachable!();
        }
        n if n > 0  => {
            let handle = Arc::new(Handle(amaster));
            (Reader(handle.clone()), Writer(handle.clone()))
        }
        _           => panic!("Fork failed.")
    }
}

pub struct Reader(Arc<Handle>);

impl Deref for Reader {
    type Target = Handle;
    fn deref(&self) -> &Handle {
        &*self.0
    }
}

impl io::Read for Reader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match unsafe {libc::read(**self.0, buf.as_mut_ptr() as *mut _, buf.len() as libc::size_t)}
        {
            n if n >= 0 => Ok(n as usize),
            _           => Err(io::Error::last_os_error()),
        }
    }
}

pub struct Writer(Arc<Handle>);

impl Deref for Writer {
    type Target = Handle;
    fn deref(&self) -> &Handle {
        &*self.0
    }
}

impl io::Write for Writer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match unsafe {libc::write(**self.0, buf.as_ptr() as *const _, buf.len() as libc::size_t)}
        {
            n if n >= 0 => Ok(n as usize),
            _           => Err(io::Error::last_os_error()),
        }
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

pub struct Handle(libc::c_int);

impl Handle {
    pub fn set_winsize(&self, width: u16, height: u16) -> io::Result<()> {
        let winsize = Winsize {
            ws_row: height as libc::c_ushort,
            ws_col: width as libc::c_ushort,
            ws_xpixel: 0,
            ws_ypixel: 0
        };
        match unsafe { libc::ioctl(**self, TIOCSWINSZ, &winsize as *const _) } {
            -1  => Err(io::Error::last_os_error()),
            _   => Ok(()),
        }
    }
}

impl Deref for Handle {
    type Target = libc::c_int;
    fn deref(&self) -> &libc::c_int { &self.0 }
}

impl Drop for Handle {
    fn drop(&mut self) {
        unsafe { libc::close(self.0); }
    }
}
<|endoftext|>


<commit_before>extern crate digest;
extern crate indy_crypto;
extern crate sha2;
extern crate rust_base58;

use errors::common::CommonError;
use services::blob_storage::BlobStorageService;
use domain::anoncreds::revocation_registry_definition::RevocationRegistryDefinitionV1;

use self::indy_crypto::cl::{Tail, RevocationTailsAccessor, RevocationTailsGenerator};
use self::indy_crypto::errors::IndyCryptoError;
use self::digest::Input;

use self::rust_base58::{ToBase58, FromBase58};

use std::rc::Rc;

const TAILS_BLOB_TAG_SZ: u8 = 2;
const TAIL_SIZE: usize = Tail::BYTES_REPR_SIZE;

pub struct SDKTailsAccessor {
    tails_service: Rc<BlobStorageService>,
    tails_reader_handle: i32,
}

impl SDKTailsAccessor {
    pub fn new(tails_service: Rc<BlobStorageService>,
               tails_reader_handle: i32,
               rev_reg_def: &RevocationRegistryDefinitionV1) -> Result<SDKTailsAccessor, CommonError> {
        let tails_hash = rev_reg_def.value.tails_hash.from_base58()
            .map_err(|_| CommonError::InvalidState("Invalid base58 for Tails hash".to_string()))?;

        let tails_reader_handle = tails_service.open_blob(tails_reader_handle,
                                                          &rev_reg_def.value.tails_location,
                                                          tails_hash.as_slice())?;

        Ok(SDKTailsAccessor {
            tails_service,
            tails_reader_handle
        })
    }
}

impl Drop for SDKTailsAccessor {
    fn drop(&mut self) {
        #[allow(unused_must_use)] //TODO
            {
                self.tails_service.close(self.tails_reader_handle)
                    .map_err(map_err_err!());
            }
    }
}

impl RevocationTailsAccessor for SDKTailsAccessor {
    fn access_tail(&self, tail_id: u32, accessor: &mut FnMut(&Tail)) -> Result<(), IndyCryptoError> {
        debug!("access_tail >>> tail_id: {:?}",tail_id);

        let tail_bytes = self.tails_service
            .read(self.tails_reader_handle,
                  TAIL_SIZE,
                  TAIL_SIZE * tail_id as usize + TAILS_BLOB_TAG_SZ as usize)
            .map_err(|_|
                IndyCryptoError::InvalidState("Can't read tail bytes from blob storage".to_owned()))?; //TODO
        let tail = Tail::from_bytes(tail_bytes.as_slice())?;
        accessor(&tail);

        let res = ();

        debug!("access_tail <<< res: {:?}",res);

        Ok(res)
    }
}

pub fn store_tails_from_generator(service: Rc<BlobStorageService>,
                                  writer_handle: i32,
                                  rtg: &mut RevocationTailsGenerator) -> Result<(String, String), CommonError> {
    debug!("store_tails_from_generator >>> writer_handle: {:?}",writer_handle);

    let blob_handle = service.create_blob(writer_handle)?;

    let version = vec![0u8, TAILS_BLOB_TAG_SZ];
    service.append(blob_handle, version.as_slice())?;

    while let Some(tail) = rtg.next()? {
        let tail_bytes = tail.to_bytes()?;
        service.append(blob_handle, tail_bytes.as_slice())?;
    }

    let res = service.finalize(blob_handle).map(|(location, hash)| (location, hash.to_base58()))?;

    debug!("store_tails_from_generator <<< res: {:?}", res);

    Ok(res)
}
<commit_msg>Fix compilation warning.<commit_after>extern crate digest;
extern crate indy_crypto;
extern crate sha2;
extern crate rust_base58;

use errors::common::CommonError;
use services::blob_storage::BlobStorageService;
use domain::anoncreds::revocation_registry_definition::RevocationRegistryDefinitionV1;

use self::indy_crypto::cl::{Tail, RevocationTailsAccessor, RevocationTailsGenerator};
use self::indy_crypto::errors::IndyCryptoError;

use self::rust_base58::{ToBase58, FromBase58};

use std::rc::Rc;

const TAILS_BLOB_TAG_SZ: u8 = 2;
const TAIL_SIZE: usize = Tail::BYTES_REPR_SIZE;

pub struct SDKTailsAccessor {
    tails_service: Rc<BlobStorageService>,
    tails_reader_handle: i32,
}

impl SDKTailsAccessor {
    pub fn new(tails_service: Rc<BlobStorageService>,
               tails_reader_handle: i32,
               rev_reg_def: &RevocationRegistryDefinitionV1) -> Result<SDKTailsAccessor, CommonError> {
        let tails_hash = rev_reg_def.value.tails_hash.from_base58()
            .map_err(|_| CommonError::InvalidState("Invalid base58 for Tails hash".to_string()))?;

        let tails_reader_handle = tails_service.open_blob(tails_reader_handle,
                                                          &rev_reg_def.value.tails_location,
                                                          tails_hash.as_slice())?;

        Ok(SDKTailsAccessor {
            tails_service,
            tails_reader_handle
        })
    }
}

impl Drop for SDKTailsAccessor {
    fn drop(&mut self) {
        #[allow(unused_must_use)] //TODO
            {
                self.tails_service.close(self.tails_reader_handle)
                    .map_err(map_err_err!());
            }
    }
}

impl RevocationTailsAccessor for SDKTailsAccessor {
    fn access_tail(&self, tail_id: u32, accessor: &mut FnMut(&Tail)) -> Result<(), IndyCryptoError> {
        debug!("access_tail >>> tail_id: {:?}",tail_id);

        let tail_bytes = self.tails_service
            .read(self.tails_reader_handle,
                  TAIL_SIZE,
                  TAIL_SIZE * tail_id as usize + TAILS_BLOB_TAG_SZ as usize)
            .map_err(|_|
                IndyCryptoError::InvalidState("Can't read tail bytes from blob storage".to_owned()))?; //TODO
        let tail = Tail::from_bytes(tail_bytes.as_slice())?;
        accessor(&tail);

        let res = ();

        debug!("access_tail <<< res: {:?}",res);

        Ok(res)
    }
}

pub fn store_tails_from_generator(service: Rc<BlobStorageService>,
                                  writer_handle: i32,
                                  rtg: &mut RevocationTailsGenerator) -> Result<(String, String), CommonError> {
    debug!("store_tails_from_generator >>> writer_handle: {:?}",writer_handle);

    let blob_handle = service.create_blob(writer_handle)?;

    let version = vec![0u8, TAILS_BLOB_TAG_SZ];
    service.append(blob_handle, version.as_slice())?;

    while let Some(tail) = rtg.next()? {
        let tail_bytes = tail.to_bytes()?;
        service.append(blob_handle, tail_bytes.as_slice())?;
    }

    let res = service.finalize(blob_handle).map(|(location, hash)| (location, hash.to_base58()))?;

    debug!("store_tails_from_generator <<< res: {:?}", res);

    Ok(res)
}
<|endoftext|>


<commit_before>// This macro allows to wrap Sodimoxide type to libindy type keeping the same behaviour
macro_rules! sodium_type (($newtype:ident, $sodiumtype:path, $len:ident) => (
    pub struct $newtype(pub(super) $sodiumtype);

    impl $newtype {

        #[allow(dead_code)]
        pub fn new(bytes: [u8; $len]) -> $newtype {
            $newtype($sodiumtype(bytes))
        }

        #[allow(dead_code)]
        pub fn from_slice(bs: &[u8]) -> Result<$newtype, ::errors::IndyError> {
            let inner = <$sodiumtype>::from_slice(bs)
                .ok_or(::errors::err_msg(::errors::IndyErrorKind::InvalidStructure, format!("Invalid bytes for {:?}", stringify!($newtype))))?;

            Ok($newtype(inner))
        }
    }

    impl Clone for $newtype {
        fn clone(&self) -> $newtype {
            $newtype(self.0.clone())
        }
    }

    impl ::std::fmt::Debug for $newtype {
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            self.0.fmt(f)
        }
    }

    impl ::std::cmp::PartialEq for $newtype {
        fn eq(&self, other: &$newtype) -> bool {
            self.0.eq(&other.0)
        }
    }

    impl ::std::cmp::Eq for $newtype {}

    impl ::serde::Serialize for $newtype {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer
        {
            serializer.serialize_bytes(&self.0[..])
        }
    }

    impl<'de> ::serde::Deserialize<'de> for $newtype {
        fn deserialize<D>(deserializer: D) -> Result<$newtype, D::Error> where D: ::serde::Deserializer<'de>
        {
            <$sodiumtype>::deserialize(deserializer).map(|inner| $newtype (inner))
        }
    }

    impl ::std::ops::Index<::std::ops::Range<usize>> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl ::std::ops::Index<::std::ops::RangeFull> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl AsRef<[u8]> for $newtype {
        #[inline]
        fn as_ref(&self) -> &[u8] {
            &self[..]
        }
    }
));<commit_msg>remove redundant closure<commit_after>// This macro allows to wrap Sodimoxide type to libindy type keeping the same behaviour
macro_rules! sodium_type (($newtype:ident, $sodiumtype:path, $len:ident) => (
    pub struct $newtype(pub(super) $sodiumtype);

    impl $newtype {

        #[allow(dead_code)]
        pub fn new(bytes: [u8; $len]) -> $newtype {
            $newtype($sodiumtype(bytes))
        }

        #[allow(dead_code)]
        pub fn from_slice(bs: &[u8]) -> Result<$newtype, ::errors::IndyError> {
            let inner = <$sodiumtype>::from_slice(bs)
                .ok_or(::errors::err_msg(::errors::IndyErrorKind::InvalidStructure, format!("Invalid bytes for {:?}", stringify!($newtype))))?;

            Ok($newtype(inner))
        }
    }

    impl Clone for $newtype {
        fn clone(&self) -> $newtype {
            $newtype(self.0.clone())
        }
    }

    impl ::std::fmt::Debug for $newtype {
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            self.0.fmt(f)
        }
    }

    impl ::std::cmp::PartialEq for $newtype {
        fn eq(&self, other: &$newtype) -> bool {
            self.0.eq(&other.0)
        }
    }

    impl ::std::cmp::Eq for $newtype {}

    impl ::serde::Serialize for $newtype {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer
        {
            serializer.serialize_bytes(&self.0[..])
        }
    }

    impl<'de> ::serde::Deserialize<'de> for $newtype {
        fn deserialize<D>(deserializer: D) -> Result<$newtype, D::Error> where D: ::serde::Deserializer<'de>
        {
            <$sodiumtype>::deserialize(deserializer).map($newtype)
        }
    }

    impl ::std::ops::Index<::std::ops::Range<usize>> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl ::std::ops::Index<::std::ops::RangeFull> for $newtype {
        type Output = [u8];

        fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
            self.0.index(_index)
        }
    }

    impl AsRef<[u8]> for $newtype {
        #[inline]
        fn as_ref(&self) -> &[u8] {
            &self[..]
        }
    }
));<|endoftext|>