1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 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),+ }
    });
    ($($name:pat = $rx:expr, $meth:ident => $code:expr),+) => ({
        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`
            {
                let packets = [ $( &$rx as &Packet, )+ ];

                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)
                    }
                });
            }

            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 } &&
                     // If start_selection() failed, abort_selection() will fail too,
                     // but it still counts as "data available".
                     ($rx.abort_selection() || i == started_count) {
                    // React to the first
                    let $name = $rx.$meth();
                    $code
                })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
        }
    })
}

#[macro_export]
macro_rules! user_enum {
    ($(#[$attr:meta])* pub enum $name:ident { $(#[$doc:meta] $elem:ident <-> $txt:expr),* }) => (
        $(#[$attr])*
        pub enum $name {
            $(#[$doc] $elem),*
        }

        impl ::std::fmt::Debug for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.pad(match *self {
                    $($name::$elem => $txt),*
                })
            }
        }

        impl ::std::fmt::Display for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.pad(match *self {
                    $($name::$elem => $txt),*
                })
            }
        }

        impl ::serde::Deserialize for $name {
            #[inline]
            fn deserialize<D>(d: &mut D) -> Result<$name, D::Error>
                where D: ::serde::Deserializer
            {
                struct Visitor;
                impl ::serde::de::Visitor for Visitor {
                    type Value = $name;

                    fn visit_string<E>(&mut self, v: String) -> Result<$name, E>
                        where E: ::serde::de::Error
                    {
                        self.visit_str(&v)
                    }

                    fn visit_str<E>(&mut self, s: &str) -> Result<$name, E>
                        where E: ::serde::de::Error
                    {
                        $( if s == $txt { Ok($name::$elem) } )else*
                        else { Err(::serde::de::Error::syntax(stringify!($name))) }
                    }
                }

                d.visit(Visitor)
            }
        }

        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer
            {
                s.visit_str(&self.to_string())
            }
        }
    );
}