rust-bitcoin-unsafe-fast/src/macros.rs

117 lines
3.4 KiB
Rust
Raw Normal View History

2014-07-18 13:56:17 +00:00
// Rust Bitcoin Library
// Written in 2014 by
// Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//! # Macros
//!
//! Macros available to users of the Bitcoin library
#[macro_export]
macro_rules! nu_select {
($($name:pat = $rx:expr => $code:expr),+) => ({
nu_select!{ $($name = $rx, recv => $code),+ }
2014-07-18 13:56:17 +00:00
});
($($name:pat = $rx:expr, $meth:ident => $code:expr),+) => ({
2014-07-18 13:56:17 +00:00
use rustrt::local::Local;
use rustrt::task::Task;
use sync::comm::Packet;
// Is anything already ready to receive? Grab it without waiting.
$(
if (&$rx as &Packet).can_recv() {
let $name = $rx.$meth();
$code
}
)else+
else {
// Start selecting on as many as we need to before getting a bite.
// Keep count of how many, since we need to abort every selection
// that we started.
let mut started_count = 0;
// Restrict lifetime of borrows in `packets`
2014-07-27 02:36:38 +00:00
{
let packets = [ $( &$rx as &Packet, )+ ];
2014-07-27 02:36:38 +00:00
let task: Box<Task> = Local::take();
task.deschedule(packets.len(), |task| {
match packets[started_count].start_selection(task) {
Ok(()) => {
started_count += 1;
Ok(())
}
Err(task) => Err(task)
2014-07-18 13:56:17 +00:00
}
2014-07-27 02:36:38 +00:00
});
}
2014-07-18 13:56:17 +00:00
2014-07-27 02:36:38 +00:00
let mut i = 0;
let ret = $(
// Abort the receivers, stopping at the first ready one to get its data.
if { i += 1; i <= started_count } &&
2014-07-18 13:56:17 +00:00
// If start_selection() failed, abort_selection() will fail too,
// but it still counts as "data available".
2014-07-27 02:36:38 +00:00
($rx.abort_selection() || i == started_count) {
2014-07-18 13:56:17 +00:00
// React to the first
let $name = $rx.$meth();
$code
2014-07-27 02:36:38 +00:00
})else+
else {
fail!("we didn't find the ready receiver, but we should have had one");
};
// At this point, the first i receivers have been aborted. We need to abort the rest:
$(if i > 0 {
i -= 1;
} else {
$rx.abort_selection();
})+
let _ = i; // Shut up `i -= 1 but i is never read` warning
// Return
ret
2014-07-18 13:56:17 +00:00
}
})
}
2014-07-18 13:56:17 +00:00
#[macro_export]
macro_rules! user_enum {
($(#[$attr:meta])* pub enum $name:ident { $(#[$doc:meta] $elem:ident <-> $txt:expr),* }) => (
$(#[$attr])*
pub enum $name {
$(#[$doc] $elem),*
}
2015-03-26 15:35:31 +00:00
impl ::std::fmt::Debug for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.pad(match *self {
$($elem => $txt),*
})
}
}
impl<S: ::serialize::Encoder<E>, E> ::serialize::Encodable<S, E> for $name {
fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_str(self.to_string().as_slice())
}
}
impl <D: ::serialize::Decoder<E>, E> ::serialize::Decodable<D, E> for $name {
fn decode(d: &mut D) -> Result<$name, E> {
let s = try!(d.read_str());
$( if s.as_slice() == $txt { Ok($name::$elem) } )else*
else { Err(d.error(format!("unknown `{}`", s).as_slice())) }
}
}
);
}
2014-07-18 13:56:17 +00:00