From 64106c4d3d4ddba8c7bc2af75376e6d3d3d75601 Mon Sep 17 00:00:00 2001 From: Date: Mon, 29 Jun 2015 20:16:15 +0000 Subject: Update documentation --- src/aho_corasick/autiter.rs.html | 747 +++ src/aho_corasick/full.rs.html | 329 + src/aho_corasick/lib.rs.html | 1823 +++++ src/bitflags/lib.rs.html | 1121 ++++ src/carboxyl/lib.rs.html | 419 ++ src/carboxyl/lift.rs.html | 605 ++ src/carboxyl/pending.rs.html | 271 + src/carboxyl/readonly.rs.html | 173 + src/carboxyl/signal.rs.html | 1601 +++++ src/carboxyl/source.rs.html | 359 + src/carboxyl/stream.rs.html | 1645 +++++ src/carboxyl/transaction.rs.html | 459 ++ src/gcc/lib.rs.html | 1093 +++ src/irsc/callback.rs.html | 127 + src/irsc/client.rs.html | 657 ++ src/irsc/color.rs.html | 189 + src/irsc/command.rs.html | 3997 +++++++++++ src/irsc/event.rs.html | 145 + src/irsc/ident.rs.html | 147 + src/irsc/lib.rs.html | 221 + src/irsc/message.rs.html | 567 ++ src/irsc/reply.rs.html | 3053 +++++++++ src/lazy_static/lib.rs.html | 345 + src/libc/lib.rs.html | 12869 ++++++++++++++++++++++++++++++++++++ src/log/lib.rs.html | 1643 +++++ src/log/macros.rs.html | 387 ++ src/memchr/lib.rs.html | 287 + src/openssl/asn1/mod.rs.html | 195 + src/openssl/bio/mod.rs.html | 309 + src/openssl/bn/mod.rs.html | 1305 ++++ src/openssl/crypto/hash.rs.html | 773 +++ src/openssl/crypto/hmac.rs.html | 1053 +++ src/openssl/crypto/memcmp.rs.html | 175 + src/openssl/crypto/mod.rs.html | 145 + src/openssl/crypto/pkcs5.rs.html | 335 + src/openssl/crypto/pkey.rs.html | 1103 +++ src/openssl/crypto/rand.rs.html | 151 + src/openssl/crypto/symm.rs.html | 721 ++ src/openssl/lib.rs.html | 147 + src/openssl/nid.rs.html | 437 ++ src/openssl/ssl/error.rs.html | 373 ++ src/openssl/ssl/mod.rs.html | 2079 ++++++ src/openssl/x509/mod.rs.html | 1461 ++++ src/openssl_sys/lib.rs.html | 1327 ++++ src/openssl_sys/probe.rs.html | 243 + src/pkg_config/lib.rs.html | 679 ++ src/regex/char.rs.html | 311 + src/regex/input.rs.html | 325 + src/regex/lib.rs.html | 959 +++ src/regex/program.rs.html | 1057 +++ src/regex/re.rs.html | 2393 +++++++ src/regex_macros/lib.rs.html | 1215 ++++ src/regex_syntax/lib.rs.html | 2465 +++++++ src/regex_syntax/parser.rs.html | 4751 +++++++++++++ 54 files changed, 61766 insertions(+) create mode 100644 src/aho_corasick/autiter.rs.html create mode 100644 src/aho_corasick/full.rs.html create mode 100644 src/aho_corasick/lib.rs.html create mode 100644 src/bitflags/lib.rs.html create mode 100644 src/carboxyl/lib.rs.html create mode 100644 src/carboxyl/lift.rs.html create mode 100644 src/carboxyl/pending.rs.html create mode 100644 src/carboxyl/readonly.rs.html create mode 100644 src/carboxyl/signal.rs.html create mode 100644 src/carboxyl/source.rs.html create mode 100644 src/carboxyl/stream.rs.html create mode 100644 src/carboxyl/transaction.rs.html create mode 100644 src/gcc/lib.rs.html create mode 100644 src/irsc/callback.rs.html create mode 100644 src/irsc/client.rs.html create mode 100644 src/irsc/color.rs.html create mode 100644 src/irsc/command.rs.html create mode 100644 src/irsc/event.rs.html create mode 100644 src/irsc/ident.rs.html create mode 100644 src/irsc/lib.rs.html create mode 100644 src/irsc/message.rs.html create mode 100644 src/irsc/reply.rs.html create mode 100644 src/lazy_static/lib.rs.html create mode 100644 src/libc/lib.rs.html create mode 100644 src/log/lib.rs.html create mode 100644 src/log/macros.rs.html create mode 100644 src/memchr/lib.rs.html create mode 100644 src/openssl/asn1/mod.rs.html create mode 100644 src/openssl/bio/mod.rs.html create mode 100644 src/openssl/bn/mod.rs.html create mode 100644 src/openssl/crypto/hash.rs.html create mode 100644 src/openssl/crypto/hmac.rs.html create mode 100644 src/openssl/crypto/memcmp.rs.html create mode 100644 src/openssl/crypto/mod.rs.html create mode 100644 src/openssl/crypto/pkcs5.rs.html create mode 100644 src/openssl/crypto/pkey.rs.html create mode 100644 src/openssl/crypto/rand.rs.html create mode 100644 src/openssl/crypto/symm.rs.html create mode 100644 src/openssl/lib.rs.html create mode 100644 src/openssl/nid.rs.html create mode 100644 src/openssl/ssl/error.rs.html create mode 100644 src/openssl/ssl/mod.rs.html create mode 100644 src/openssl/x509/mod.rs.html create mode 100644 src/openssl_sys/lib.rs.html create mode 100644 src/openssl_sys/probe.rs.html create mode 100644 src/pkg_config/lib.rs.html create mode 100644 src/regex/char.rs.html create mode 100644 src/regex/input.rs.html create mode 100644 src/regex/lib.rs.html create mode 100644 src/regex/program.rs.html create mode 100644 src/regex/re.rs.html create mode 100644 src/regex_macros/lib.rs.html create mode 100644 src/regex_syntax/lib.rs.html create mode 100644 src/regex_syntax/parser.rs.html (limited to 'src') diff --git a/src/aho_corasick/autiter.rs.html b/src/aho_corasick/autiter.rs.html new file mode 100644 index 0000000..af7f372 --- /dev/null +++ b/src/aho_corasick/autiter.rs.html @@ -0,0 +1,747 @@ + + + + + + + + + + autiter.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+
+use std::io::{self, BufRead, Read};
+
+use super::{ROOT_STATE, PatIdx, StateIdx};
+
+/// An abstraction over automatons and their corresponding iterators.
+pub trait Automaton: Sized {
+    /// Return the next state given the current state and next character.
+    fn next_state(&self, si: StateIdx, b: u8) -> StateIdx;
+
+    /// Return true if and only if the given state and current pattern index
+    /// indicate a match.
+    fn has_match(&self, si: StateIdx, outi: PatIdx) -> bool;
+
+    /// Build a match given the current state, pattern index and input index.
+    fn get_match(&self, si: StateIdx, outi: PatIdx, texti: usize) -> Match;
+
+    /// Attempt to skip through the input.
+    ///
+    /// This returns the index into `text` at which the next match attempt
+    /// should start. (If no skipping occurred, then the return value should
+    /// be equal to `at`.)
+    ///
+    /// Finally, if no match is possible, then return `text.len()`.
+    fn skip_to(&self, si: StateIdx, text: &[u8], at: usize) -> usize;
+
+    /// Returns true if and only if this automaton can skip through the input.
+    fn is_skippable(&self) -> bool;
+
+    /// Returns all of the patterns matched by this automaton.
+    ///
+    /// The order of the patterns is the order in which they were added.
+    fn patterns(&self) -> &[String];
+
+    /// Returns the pattern indexed at `i`.
+    ///
+    /// The index corresponds to the position at which the pattern was added
+    /// to the automaton, starting at `0`.
+    fn pattern(&self, i: usize) -> &str;
+
+    /// Return the number of patterns in the automaton.
+    #[inline]
+    fn len(&self) -> usize {
+        self.patterns().len()
+    }
+
+    /// Returns true if the automaton has no patterns.
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Returns an iterator of non-overlapping matches in `s`.
+    fn find<'a, 's>(
+        &'a self,
+        s: &'s str,
+    ) -> Matches<'a, 's, Self> {
+        Matches {
+            aut: self,
+            text: s.as_bytes(),
+            texti: 0,
+            si: ROOT_STATE,
+        }
+    }
+
+    /// Returns an iterator of overlapping matches in `s`.
+    fn find_overlapping<'a, 's>(
+        &'a self,
+        s: &'s str,
+    ) -> MatchesOverlapping<'a, 's, Self> {
+        MatchesOverlapping {
+            aut: self,
+            text: s.as_bytes(),
+            texti: 0,
+            si: ROOT_STATE,
+            outi: 0,
+        }
+    }
+
+    /// Returns an iterator of non-overlapping matches in the given reader.
+    fn stream_find<'a, R: io::Read>(
+        &'a self,
+        rdr: R,
+    ) -> StreamMatches<'a, R, Self> {
+        StreamMatches {
+            aut: self,
+            buf: io::BufReader::new(rdr),
+            texti: 0,
+            si: ROOT_STATE,
+        }
+    }
+
+    /// Returns an iterator of overlapping matches in the given reader.
+    fn stream_find_overlapping<'a, R: io::Read>(
+        &'a self,
+        rdr: R,
+    ) -> StreamMatchesOverlapping<'a, R, Self> {
+        StreamMatchesOverlapping {
+            aut: self,
+            buf: io::BufReader::new(rdr),
+            texti: 0,
+            si: ROOT_STATE,
+            outi: 0,
+        }
+    }
+}
+
+/// Records a match in the search text.
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Match {
+    /// The pattern index.
+    ///
+    /// This corresponds to the ordering in which the matched pattern was
+    /// added to the automaton, starting at `0`.
+    pub pati: usize,
+    /// The starting byte offset of the match in the search text.
+    pub start: usize,
+    /// The ending byte offset of the match in the search text.
+    ///
+    /// (This can be re-captiulated with `pati` and adding the pattern's
+    /// length to `start`, but it is convenient to have it here.)
+    pub end: usize,
+}
+
+/// An iterator of non-overlapping matches for in-memory text.
+///
+/// This iterator yields `Match` values.
+///
+/// `'a` is the lifetime of the automaton and `'s` is the lifetime of the
+/// search text.
+#[derive(Debug)]
+pub struct Matches<'a, 's, A: 'a + Automaton> {
+    aut: &'a A,
+    text: &'s [u8],
+    texti: usize,
+    si: StateIdx,
+}
+
+impl<'a, 's, A: Automaton> Iterator for Matches<'a, 's, A> {
+    type Item = Match;
+
+    fn next(&mut self) -> Option<Match> {
+        // When there's an initial lone start byte, it is usually worth it
+        // to use `memchr` to skip along the input. The problem is that
+        // the skipping function is called in the inner match loop, which
+        // can be quite costly if the skipping condition is never met.
+        // Therefore, we lift the case analysis outside of the main loop at
+        // the cost of repeating code.
+        if self.aut.is_skippable() {
+            self.texti = self.aut.skip_to(self.si, self.text, self.texti);
+            while self.texti < self.text.len() {
+                self.si = self.aut.next_state(self.si, self.text[self.texti]);
+                if self.aut.has_match(self.si, 0) {
+                    let m = self.aut.get_match(self.si, 0, self.texti);
+                    self.si = ROOT_STATE;
+                    self.texti += 1;
+                    return Some(m);
+                }
+                self.texti = self.aut.skip_to(
+                    self.si, self.text, self.texti + 1);
+            }
+        } else {
+            while self.texti < self.text.len() {
+                self.si = self.aut.next_state(self.si, self.text[self.texti]);
+                if self.aut.has_match(self.si, 0) {
+                    let m = self.aut.get_match(self.si, 0, self.texti);
+                    self.si = ROOT_STATE;
+                    self.texti += 1;
+                    return Some(m);
+                }
+                self.texti += 1;
+            }
+        }
+        None
+    }
+}
+
+/// An iterator of non-overlapping matches for streaming text.
+///
+/// This iterator yields `io::Result<Match>` values.
+///
+/// `'a` is the lifetime of the automaton and `R` is the type of the underlying
+/// `io::Read`er.
+#[derive(Debug)]
+pub struct StreamMatches<'a, R, A: 'a + Automaton> {
+    aut: &'a A,
+    buf: io::BufReader<R>,
+    texti: usize,
+    si: StateIdx,
+}
+
+impl<'a, R: io::Read, A: Automaton> Iterator for StreamMatches<'a, R, A> {
+    type Item = io::Result<Match>;
+
+    fn next(&mut self) -> Option<io::Result<Match>> {
+        let mut m = None;
+        let mut consumed = 0;
+'LOOP:  loop {
+            self.buf.consume(consumed);
+            let bs = match self.buf.fill_buf() {
+                Err(err) => return Some(Err(err)),
+                Ok(bs) if bs.len() == 0 => break,
+                Ok(bs) => bs,
+            };
+            consumed = bs.len(); // is shortened if we find a match
+            for (i, &b) in bs.iter().enumerate() {
+                self.si = self.aut.next_state(self.si, b);
+                if self.aut.has_match(self.si, 0) {
+                    m = Some(Ok(self.aut.get_match(self.si, 0, self.texti)));
+                    consumed = i + 1;
+                    self.texti += 1;
+                    self.si = ROOT_STATE;
+                    break 'LOOP;
+                }
+                self.texti += 1;
+            }
+        }
+        self.buf.consume(consumed);
+        m
+    }
+}
+
+/// An iterator of overlapping matches for in-memory text.
+///
+/// This iterator yields `Match` values.
+///
+/// `'a` is the lifetime of the automaton and `'s` is the lifetime of the
+/// search text.
+#[derive(Debug)]
+pub struct MatchesOverlapping<'a, 's, A: 'a + Automaton> {
+    aut: &'a A,
+    text: &'s [u8],
+    texti: usize,
+    si: StateIdx,
+    outi: usize,
+}
+
+impl<'a, 's, A: Automaton> Iterator for MatchesOverlapping<'a, 's, A> {
+    type Item = Match;
+
+    fn next(&mut self) -> Option<Match> {
+        if self.aut.has_match(self.si, self.outi) {
+            let m = self.aut.get_match(self.si, self.outi, self.texti);
+            self.outi += 1;
+            if !self.aut.has_match(self.si, self.outi) {
+                self.texti += 1;
+            }
+            return Some(m);
+        }
+
+        self.outi = 0;
+        self.texti = self.aut.skip_to(self.si, self.text, self.texti);
+        while self.texti < self.text.len() {
+            let b = self.text[self.texti];
+            self.si = self.aut.next_state(self.si, b);
+            if self.aut.has_match(self.si, self.outi) {
+                return self.next();
+            }
+            self.texti = self.aut.skip_to(self.si, self.text, self.texti + 1);
+        }
+        None
+    }
+}
+
+/// An iterator of overlapping matches for streaming text.
+///
+/// This iterator yields `io::Result<Match>` values.
+///
+/// `'a` is the lifetime of the automaton and `R` is the type of the underlying
+/// `io::Read`er.
+#[derive(Debug)]
+pub struct StreamMatchesOverlapping<'a, R, A: 'a + Automaton> {
+    aut: &'a A,
+    buf: io::BufReader<R>,
+    texti: usize,
+    si: StateIdx,
+    outi: usize,
+}
+
+impl<
+    'a,
+    R: io::Read,
+    A: Automaton,
+> Iterator for StreamMatchesOverlapping<'a, R, A> {
+    type Item = io::Result<Match>;
+
+    fn next(&mut self) -> Option<io::Result<Match>> {
+        if self.aut.has_match(self.si, self.outi) {
+            let m = self.aut.get_match(self.si, self.outi, self.texti);
+            self.outi += 1;
+            if !self.aut.has_match(self.si, self.outi) {
+                self.texti += 1;
+            }
+            return Some(Ok(m));
+        }
+        let mut m = None;
+        let mut consumed = 0;
+        self.outi = 0;
+'LOOP:  loop {
+            self.buf.consume(consumed);
+            let bs = match self.buf.fill_buf() {
+                Err(err) => return Some(Err(err)),
+                Ok(bs) if bs.len() == 0 => break,
+                Ok(bs) => bs,
+            };
+            consumed = bs.len(); // is shortened if we find a match
+            for (i, &b) in bs.iter().enumerate() {
+                self.si = self.aut.next_state(self.si, b);
+                if self.aut.has_match(self.si, self.outi) {
+                    m = Some(Ok(self.aut.get_match(self.si, self.outi,
+                                                   self.texti)));
+                    consumed = i + 1;
+                    self.outi += 1;
+                    if !self.aut.has_match(self.si, self.outi) {
+                        self.texti += 1;
+                    }
+                    break 'LOOP;
+                }
+                self.texti += 1;
+            }
+        }
+        self.buf.consume(consumed);
+        m
+    }
+}
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/aho_corasick/full.rs.html b/src/aho_corasick/full.rs.html new file mode 100644 index 0000000..f9f4f65 --- /dev/null +++ b/src/aho_corasick/full.rs.html @@ -0,0 +1,329 @@ + + + + + + + + + + full.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+use memchr::memchr;
+
+use super::{
+    FAIL_STATE, ROOT_STATE,
+    StateIdx, PatIdx,
+    AcAutomaton, Transitions, Match,
+};
+use super::autiter::Automaton;
+
+/// A complete Aho-Corasick automaton.
+///
+/// This uses a single transition matrix that permits each input character
+/// to move to the next state with a single lookup in the matrix.
+///
+/// This is as fast as it gets, but it is guaranteed to use a lot of memory.
+/// Namely, it will use at least `4 * 256 * #states`, where the number of
+/// states is capped at length of all patterns concatenated.
+#[derive(Clone, Debug)]
+pub struct FullAcAutomaton {
+    pats: Vec<String>,
+    // i * #states + si
+    trans: Vec<StateIdx>,  // row-major, where states are rows
+    out: Vec<Vec<PatIdx>>, // indexed by StateIdx
+    start_bytes: Vec<u8>,
+}
+
+impl FullAcAutomaton {
+    /// Build a new expanded Aho-Corasick automaton from an existing
+    /// Aho-Corasick automaton.
+    pub fn new<T: Transitions>(ac: AcAutomaton<T>) -> FullAcAutomaton {
+        let mut fac = FullAcAutomaton {
+            pats: vec![],
+            trans: vec![FAIL_STATE; 256 * ac.states.len()],
+            out: vec![vec![]; ac.states.len()],
+            start_bytes: vec![],
+        };
+        fac.build_matrix(&ac);
+        fac.pats = ac.pats;
+        fac.start_bytes = ac.start_bytes;
+        fac
+    }
+
+    fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) {
+        let ns = self.num_states();
+        self.trans[i as usize * ns + si as usize] = goto;
+    }
+
+    #[inline]
+    fn num_states(&self) -> usize {
+        self.out.len()
+    }
+}
+
+impl Automaton for FullAcAutomaton {
+    #[inline]
+    fn next_state(&self, si: StateIdx, i: u8) -> StateIdx {
+        self.trans[i as usize * self.num_states() + si as usize]
+    }
+
+    #[inline]
+    fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
+        let pati = self.out[si as usize][outi];
+        let patlen = self.pats[pati].len();
+        let start = texti + 1 - patlen;
+        Match {
+            pati: pati,
+            start: start,
+            end: start + patlen,
+        }
+    }
+
+    #[inline]
+    fn has_match(&self, si: StateIdx, outi: usize) -> bool {
+        outi < self.out[si as usize].len()
+    }
+
+    #[inline]
+    fn skip_to(&self, si: StateIdx, text: &[u8], at: usize) -> usize {
+        if si != ROOT_STATE || !self.is_skippable() {
+            return at;
+        }
+        let b = self.start_bytes[0];
+        match memchr(b, &text[at..]) {
+            None => text.len(),
+            Some(i) => at + i,
+        }
+    }
+
+    #[inline]
+    fn is_skippable(&self) -> bool {
+        self.start_bytes.len() == 1
+    }
+
+    #[inline]
+    fn patterns(&self) -> &[String] {
+        &self.pats
+    }
+
+    #[inline]
+    fn pattern(&self, i: usize) -> &str {
+        &self.pats[i]
+    }
+}
+
+impl FullAcAutomaton {
+    fn build_matrix<T: Transitions>(&mut self, ac: &AcAutomaton<T>) {
+        for (si, s) in ac.states.iter().enumerate().skip(1) {
+            for b in (0..256).map(|b| b as u8) {
+                self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b));
+            }
+            for &pati in &s.out {
+                self.out[si].push(pati);
+            }
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/aho_corasick/lib.rs.html b/src/aho_corasick/lib.rs.html new file mode 100644 index 0000000..e75bc4d --- /dev/null +++ b/src/aho_corasick/lib.rs.html @@ -0,0 +1,1823 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+
+/*!
+An implementation of the
+[Aho-Corasick string search algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm).
+
+The Aho-Corasick algorithm is principally useful when you need to search many
+large texts for a fixed (possibly large) set of keywords. In particular, the
+Aho-Corasick algorithm preprocesses the set of keywords by constructing a
+finite state machine. The search phase is then a quick linear scan through the
+text. Each character in the search text causes a state transition in the
+automaton. Matches are reported when the automaton enters a match state.
+
+# Examples
+
+The main type exposed by this crate is `AcAutomaton`, which can be constructed
+from an iterator of pattern strings:
+
+```rust
+use aho_corasick::{Automaton, AcAutomaton};
+
+let aut = AcAutomaton::new(vec!["apple", "maple"]);
+
+// AcAutomaton also implements `FromIterator`:
+let aut: AcAutomaton = ["apple", "maple"].iter().cloned().collect();
+```
+
+Finding matches can be done with `find`:
+
+```rust
+use aho_corasick::{Automaton, AcAutomaton, Match};
+
+let aut = AcAutomaton::new(vec!["apple", "maple"]);
+let mut it = aut.find("I like maple apples.");
+assert_eq!(it.next(), Some(Match {
+    pati: 1,
+    start: 7,
+    end: 12,
+}));
+assert_eq!(it.next(), Some(Match {
+    pati: 0,
+    start: 13,
+    end: 18,
+}));
+assert_eq!(it.next(), None);
+```
+
+Use `find_overlapping` if you want to report all matches, even if they
+overlap with each other.
+
+```rust
+use aho_corasick::{Automaton, AcAutomaton, Match};
+
+let aut = AcAutomaton::new(vec!["abc", "a"]);
+let matches: Vec<_> = aut.find_overlapping("abc").collect();
+assert_eq!(matches, vec![
+    Match { pati: 1, start: 0, end: 1}, Match { pati: 0, start: 0, end: 3 },
+]);
+
+// Regular `find` will report only one match:
+let matches: Vec<_> = aut.find("abc").collect();
+assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]);
+```
+
+Finally, there are also methods for finding matches on *streams*. Namely, the
+search text does not have to live in memory. It's useful to run this on files
+that can't fit into memory:
+
+```no_run
+use std::fs::File;
+
+use aho_corasick::{Automaton, AcAutomaton};
+
+let aut = AcAutomaton::new(vec!["foo", "bar", "baz"]);
+let rdr = File::open("search.txt").unwrap();
+for m in aut.stream_find(rdr) {
+    let m = m.unwrap(); // could be an IO error
+    println!("Pattern '{}' matched at: ({}, {})",
+             aut.pattern(m.pati), m.start, m.end);
+}
+```
+
+There is also `stream_find_overlapping`, which is just like `find_overlapping`,
+but it operates on streams.
+
+Please see `dict-search.rs` in this crate's `examples` directory for a more
+complete example. It creates a large automaton from a dictionary and can do a
+streaming match over arbitrarily large data.
+
+# Memory usage
+
+A key aspect of an Aho-Corasick implementation is how the state transitions
+are represented. The easiest way to make the automaton fast is to store a
+sparse 256-slot map in each state. It maps an input byte to a state index.
+This makes the matching loop extremely fast, since it translates to a simple
+pointer read.
+
+The problem is that as the automaton accumulates more states, you end up paying
+a `256 * 4` (`4` is for the `u32` state index) byte penalty for every state
+regardless of how many transitions it has.
+
+To solve this, only states near the root of the automaton have this sparse
+map representation. States near the leaves of the automaton use a dense mapping
+that requires a linear scan.
+
+(The specific limit currently set is `3`, so that states with a depth less than
+or equal to `3` are less memory efficient. The result is that the memory usage
+of the automaton stops growing rapidly past ~60MB, even for automatons with
+thousands of patterns.)
+
+If you'd like to opt for the less-memory-efficient-but-faster version, then
+you can construct an `AcAutomaton` with a `Sparse` transition strategy:
+
+```rust
+use aho_corasick::{Automaton, AcAutomaton, Match, Sparse};
+
+let aut = AcAutomaton::<Sparse>::with_transitions(vec!["abc", "a"]);
+let matches: Vec<_> = aut.find("abc").collect();
+assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]);
+```
+*/
+
+#![deny(missing_docs)]
+
+extern crate memchr;
+#[cfg(test)] extern crate quickcheck;
+#[cfg(test)] extern crate rand;
+
+use std::collections::VecDeque;
+use std::fmt;
+use std::iter::FromIterator;
+
+use memchr::memchr;
+
+pub use self::autiter::{
+    Automaton, Match,
+    Matches, MatchesOverlapping, StreamMatches, StreamMatchesOverlapping,
+};
+pub use self::full::FullAcAutomaton;
+
+// We're specifying paths explicitly so that we can use
+// these modules simultaneously from `main.rs`.
+// Should probably make just make `main.rs` a separate crate.
+#[path = "autiter.rs"]
+mod autiter;
+#[path = "full.rs"]
+mod full;
+
+/// The integer type used for the state index.
+///
+/// Limiting this to 32 bit integers can have a big impact on memory usage
+/// when using the `Sparse` transition representation.
+pub type StateIdx = u32;
+
+type PatIdx = usize;
+
+// Constants for special state indexes.
+const FAIL_STATE: u32 = 0;
+const ROOT_STATE: u32 = 1;
+
+// Limit the depth at which we use a dense alphabet map. Once the limit is
+// reached, a sparse set is used (and lookup becomes O(n)).
+//
+// This does have a performance hit, but the (straight forward) alternative
+// is to have a `256 * 4` byte overhead for every state.
+// Given that Aho-Corasick is typically used for dictionary searching, this
+// can lead to dramatic memory bloat.
+//
+// This limit should only be increased at your peril. Namely, in the worst
+// case, `256^DENSE_DEPTH_THRESHOLD * 4` corresponds to the memory usage in
+// bytes. A value of `3` gives us a solid cap at around 64MB, which works
+// well in practice even for dictionary sized automatons.
+//
+// Why not make this user configurable? Well, it doesn't make much sense
+// because we pay for it with case analysis in the matching loop. Increasing it
+// doesn't have much impact on performance (outside of pathological cases?).
+//
+// There is probably room for adding a new automaton type that doesn't have
+// this restriction.
+//
+// N.B. Someone else seems to have discovered an alternative, but I haven't
+// grokked it yet: https://github.com/mischasan/aho-corasick
+const DENSE_DEPTH_THRESHOLD: u32 = 3;
+
+/// An Aho-Corasick finite automaton.
+#[derive(Clone)]
+pub struct AcAutomaton<T=Dense> {
+    pats: Vec<String>,
+    states: Vec<State<T>>,
+    start_bytes: Vec<u8>,
+}
+
+#[derive(Clone)]
+struct State<T> {
+    out: Vec<PatIdx>,
+    fail: StateIdx,
+    goto: T,
+    depth: u32,
+}
+
+impl AcAutomaton {
+    /// Create a new automaton from an iterator of patterns.
+    ///
+    /// The patterns must be convertible to Unicode `String` values via the
+    /// `Into` trait.
+    pub fn new<S, I>(pats: I) -> AcAutomaton<Dense>
+            where S: Into<String>, I: IntoIterator<Item=S> {
+        AcAutomaton::with_transitions(pats)
+    }
+}
+
+impl<T: Transitions> AcAutomaton<T> {
+    /// Create a new automaton from an iterator of patterns.
+    ///
+    /// This constructor allows one to choose the transition representation.
+    ///
+    /// The patterns must be convertible to Unicode `String` values via the
+    /// `Into` trait.
+    pub fn with_transitions<S, I>(pats: I) -> AcAutomaton<T>
+            where S: Into<String>, I: IntoIterator<Item=S> {
+        AcAutomaton {
+            pats: vec![], // filled in later, avoid wrath of borrow checker
+            states: vec![State::new(0), State::new(0)], // empty and root
+            start_bytes: vec![], // also filled in later
+        }.build(pats.into_iter().map(Into::into).collect())
+    }
+
+    /// Build out the entire automaton into a single matrix.
+    ///
+    /// This will make searching as fast as possible at the expense of using
+    /// at least `4 * 256 * #states` bytes of memory.
+    pub fn into_full(self) -> FullAcAutomaton {
+        FullAcAutomaton::new(self)
+    }
+}
+
+impl<T: Transitions> Automaton for AcAutomaton<T> {
+    #[inline]
+    fn next_state(&self, mut si: StateIdx, b: u8) -> StateIdx {
+        loop {
+            let maybe_si = self.states[si as usize].goto(b);
+            if maybe_si != FAIL_STATE {
+                si = maybe_si;
+                break;
+            } else {
+                si = self.states[si as usize].fail;
+            }
+        }
+        si
+    }
+
+    #[inline]
+    fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
+        let pati = self.states[si as usize].out[outi];
+        let patlen = self.pats[pati].len();
+        let start = texti + 1 - patlen;
+        Match {
+            pati: pati,
+            start: start,
+            end: start + patlen,
+        }
+    }
+
+    #[inline]
+    fn has_match(&self, si: StateIdx, outi: usize) -> bool {
+        outi < self.states[si as usize].out.len()
+    }
+
+    #[inline]
+    fn skip_to(&self, si: StateIdx, text: &[u8], at: usize) -> usize {
+        if si != ROOT_STATE || !self.is_skippable() {
+            return at;
+        }
+        let b = self.start_bytes[0];
+        match memchr(b, &text[at..]) {
+            None => text.len(),
+            Some(i) => at + i,
+        }
+    }
+
+    #[inline]
+    fn is_skippable(&self) -> bool {
+        self.start_bytes.len() == 1
+    }
+
+    #[inline]
+    fn patterns(&self) -> &[String] {
+        &self.pats
+    }
+
+    #[inline]
+    fn pattern(&self, i: usize) -> &str {
+        &self.pats[i]
+    }
+}
+
+// Below contains code for *building* the automaton. It's a reasonably faithful
+// translation of the description/psuedo-code from:
+// http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf
+
+impl<T: Transitions> AcAutomaton<T> {
+    // This is the first phase and builds the initial keyword tree.
+    fn build(mut self, pats: Vec<String>) -> AcAutomaton<T> {
+        for (pati, pat) in pats.iter().enumerate() {
+            if pat.is_empty() {
+                continue;
+            }
+            let mut previ = ROOT_STATE;
+            for &b in pat.as_bytes() {
+                if self.states[previ as usize].goto(b) != FAIL_STATE {
+                    previ = self.states[previ as usize].goto(b);
+                } else {
+                    let depth = self.states[previ as usize].depth + 1;
+                    let nexti = self.add_state(State::new(depth));
+                    self.states[previ as usize].set_goto(b, nexti);
+                    previ = nexti;
+                }
+            }
+            self.states[previ as usize].out.push(pati);
+        }
+        for c in (0..256).into_iter().map(|c| c as u8) {
+            if self.states[ROOT_STATE as usize].goto(c) == FAIL_STATE {
+                self.states[ROOT_STATE as usize].set_goto(c, ROOT_STATE);
+            } else {
+                self.start_bytes.push(c);
+            }
+        }
+        self.pats = pats;
+        self.fill()
+    }
+
+    // The second phase that fills in the back links.
+    fn fill(mut self) -> AcAutomaton<T> {
+        // Fill up the queue with all non-root transitions out of the root
+        // node. Then proceed by breadth first traversal.
+        let mut q = VecDeque::new();
+        for c in (0..256).into_iter().map(|c| c as u8) {
+            let si = self.states[ROOT_STATE as usize].goto(c);
+            if si != ROOT_STATE {
+                q.push_front(si);
+            }
+        }
+        while let Some(si) = q.pop_back() {
+            for c in (0..256).into_iter().map(|c| c as u8) {
+                let u = self.states[si as usize].goto(c);
+                if u != FAIL_STATE {
+                    q.push_front(u);
+                    let mut v = self.states[si as usize].fail;
+                    while self.states[v as usize].goto(c) == FAIL_STATE {
+                        v = self.states[v as usize].fail;
+                    }
+                    let ufail = self.states[v as usize].goto(c);
+                    self.states[u as usize].fail = ufail;
+                    let ufail_out = self.states[ufail as usize].out.clone();
+                    self.states[u as usize].out.extend(ufail_out);
+                }
+            }
+        }
+        self
+    }
+
+    fn add_state(&mut self, state: State<T>) -> StateIdx {
+        let i = self.states.len();
+        self.states.push(state);
+        i as StateIdx
+    }
+}
+
+impl<T: Transitions> State<T> {
+    fn new(depth: u32) -> State<T> {
+        State {
+            out: vec![],
+            fail: 1,
+            goto: Transitions::new(depth),
+            depth: depth,
+        }
+    }
+
+    fn goto(&self, b: u8) -> StateIdx { self.goto.goto(b) }
+    fn set_goto(&mut self, b: u8, si: StateIdx) { self.goto.set_goto(b, si); }
+}
+
+/// An abstraction over state transition strategies.
+///
+/// This is an attempt to let the caller choose the space/time trade offs
+/// used for state transitions.
+///
+/// (It's possible that this interface is merely good enough for just the two
+/// implementations in this crate.)
+pub trait Transitions {
+    /// Return a new state at the given depth.
+    fn new(depth: u32) -> Self;
+    /// Return the next state index given the next character.
+    fn goto(&self, alpha: u8) -> StateIdx;
+    /// Set the next state index for the character given.
+    fn set_goto(&mut self, alpha: u8, si: StateIdx);
+}
+
+/// State transitions that can be stored either sparsely or densely.
+///
+/// This uses less space but at the expense of slower matching.
+#[derive(Clone, Debug)]
+pub struct Dense(DenseChoice);
+
+#[derive(Clone, Debug)]
+enum DenseChoice {
+    Sparse(Vec<StateIdx>), // indexed by alphabet
+    Dense(Vec<(u8, StateIdx)>),
+}
+
+impl Transitions for Dense {
+    fn new(depth: u32) -> Dense {
+        if depth <= DENSE_DEPTH_THRESHOLD {
+            Dense(DenseChoice::Sparse(vec![0; 256]))
+        } else {
+            Dense(DenseChoice::Dense(vec![]))
+        }
+    }
+
+    fn goto(&self, b1: u8) -> StateIdx {
+        match self.0 {
+            DenseChoice::Sparse(ref m) => m[b1 as usize],
+            DenseChoice::Dense(ref m) => {
+                for &(b2, si) in m {
+                    if b1 == b2 {
+                        return si;
+                    }
+                }
+                FAIL_STATE
+            }
+        }
+    }
+
+    fn set_goto(&mut self, b: u8, si: StateIdx) {
+        match self.0 {
+            DenseChoice::Sparse(ref mut m) => m[b as usize] = si,
+            DenseChoice::Dense(ref mut m) => m.push((b, si)),
+        }
+    }
+}
+
+/// State transitions that are always sparse.
+///
+/// This can use enormous amounts of memory when there are many patterns,
+/// but matching is very fast.
+#[derive(Clone, Debug)]
+pub struct Sparse(Vec<StateIdx>);
+
+impl Transitions for Sparse {
+    fn new(_: u32) -> Sparse {
+        Sparse(vec![0; 256])
+    }
+
+    #[inline]
+    fn goto(&self, b: u8) -> StateIdx {
+        self.0[b as usize]
+    }
+
+    fn set_goto(&mut self, b: u8, si: StateIdx) {
+        self.0[b as usize] = si;
+    }
+}
+
+impl<S: Into<String>> FromIterator<S> for AcAutomaton {
+    /// Create an automaton from an iterator of strings.
+    fn from_iter<T>(it: T) -> AcAutomaton where T: IntoIterator<Item=S> {
+        AcAutomaton::new(it)
+    }
+}
+
+// Provide some question debug impls for viewing automatons.
+// The custom impls mostly exist for special showing of sparse maps.
+
+impl<T: Transitions> fmt::Debug for AcAutomaton<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use std::iter::repeat;
+
+        try!(writeln!(f, "{}", repeat('-').take(79).collect::<String>()));
+        try!(writeln!(f, "Patterns: {:?}", self.pats));
+        for (i, state) in self.states.iter().enumerate().skip(1) {
+            try!(writeln!(f, "{:3}: {}", i, state.debug(i == 1)));
+        }
+        write!(f, "{}", repeat('-').take(79).collect::<String>())
+    }
+}
+
+impl<T: Transitions> State<T> {
+    fn debug(&self, root: bool) -> String {
+        format!("State {{ depth: {:?}, out: {:?}, fail: {:?}, goto: {{{}}} }}",
+                self.depth, self.out, self.fail, self.goto_string(root))
+    }
+
+    fn goto_string(&self, root: bool) -> String {
+        use std::char::from_u32;
+
+        let mut goto = vec![];
+        for b in (0..256).map(|b| b as u8) {
+            let si = self.goto(b);
+            if (!root && si == FAIL_STATE) || (root && si == ROOT_STATE) {
+                continue;
+            }
+            goto.push(format!("{} => {}", from_u32(b as u32).unwrap(), si));
+        }
+        goto.connect(", ")
+    }
+}
+
+impl<T: Transitions> fmt::Debug for State<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.debug(false))
+    }
+}
+
+impl<T: Transitions> AcAutomaton<T> {
+    #[doc(hidden)]
+    pub fn dot(&self) -> String {
+        use std::fmt::Write;
+        let mut out = String::new();
+        macro_rules! w {
+            ($w:expr, $($tt:tt)*) => { {write!($w, $($tt)*)}.unwrap() }
+        }
+
+        w!(out, r#"
+digraph automaton {{
+    label=<<FONT POINT-SIZE="20">{}</FONT>>;
+    labelloc="l";
+    labeljust="l";
+    rankdir="LR";
+"#, self.pats.connect(", "));
+        for (i, s) in self.states.iter().enumerate().skip(1) {
+            let i = i as u32;
+            if s.out.len() == 0 {
+                w!(out, "    {};\n", i);
+            } else {
+                w!(out, "    {} [peripheries=2];\n", i);
+            }
+            w!(out, "    {} -> {} [style=dashed];\n", i, s.fail);
+            for b in (0..256).map(|b| b as u8) {
+                let si = s.goto(b);
+                if si == FAIL_STATE || (i == ROOT_STATE && si == ROOT_STATE) {
+                    continue;
+                }
+                w!(out, "    {} -> {} [label={}];\n", i, si, b as char);
+            }
+        }
+        w!(out, "}}");
+        out
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::collections::HashSet;
+    use std::io;
+
+    use quickcheck::{Arbitrary, Gen, quickcheck};
+    use rand::Rng;
+
+    use super::{Automaton, AcAutomaton, Match};
+
+    fn aut_find<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        AcAutomaton::new(xs.to_vec()).find(&haystack).collect()
+    }
+
+    fn aut_finds<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        let cur = io::Cursor::new(haystack.as_bytes());
+        AcAutomaton::new(xs.to_vec())
+            .stream_find(cur).map(|r| r.unwrap()).collect()
+    }
+
+    fn aut_findf<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        AcAutomaton::new(xs.to_vec()).into_full().find(haystack).collect()
+    }
+
+    fn aut_findfs<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        let cur = io::Cursor::new(haystack.as_bytes());
+        AcAutomaton::new(xs.to_vec())
+            .into_full()
+            .stream_find(cur).map(|r| r.unwrap()).collect()
+    }
+
+    fn aut_findo<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        AcAutomaton::new(xs.to_vec()).find_overlapping(haystack).collect()
+    }
+
+    fn aut_findos<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        let cur = io::Cursor::new(haystack.as_bytes());
+        AcAutomaton::new(xs.to_vec())
+            .stream_find_overlapping(cur).map(|r| r.unwrap()).collect()
+    }
+
+    fn aut_findfo<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        AcAutomaton::new(xs.to_vec())
+            .into_full().find_overlapping(haystack).collect()
+    }
+
+    fn aut_findfos<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        let cur = io::Cursor::new(haystack.as_bytes());
+        AcAutomaton::new(xs.to_vec())
+            .into_full()
+            .stream_find_overlapping(cur).map(|r| r.unwrap()).collect()
+    }
+
+    #[test]
+    fn one_pattern_one_match() {
+        let ns = vec!["a"];
+        let hay = "za";
+        let matches = vec![
+            Match { pati: 0, start: 1, end: 2 },
+        ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn one_pattern_many_match() {
+        let ns = vec!["a"];
+        let hay = "zazazzzza";
+        let matches = vec![
+            Match { pati: 0, start: 1, end: 2 },
+            Match { pati: 0, start: 3, end: 4 },
+            Match { pati: 0, start: 8, end: 9 },
+        ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn one_longer_pattern_one_match() {
+        let ns = vec!["abc"];
+        let hay = "zazabcz";
+        let matches = vec![ Match { pati: 0, start: 3, end: 6 } ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn one_longer_pattern_many_match() {
+        let ns = vec!["abc"];
+        let hay = "zazabczzzzazzzabc";
+        let matches = vec![
+            Match { pati: 0, start: 3, end: 6 },
+            Match { pati: 0, start: 14, end: 17 },
+        ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_pattern_one_match() {
+        let ns = vec!["a", "b"];
+        let hay = "zb";
+        let matches = vec![ Match { pati: 1, start: 1, end: 2 } ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_pattern_many_match() {
+        let ns = vec!["a", "b"];
+        let hay = "zbzazzzzb";
+        let matches = vec![
+            Match { pati: 1, start: 1, end: 2 },
+            Match { pati: 0, start: 3, end: 4 },
+            Match { pati: 1, start: 8, end: 9 },
+        ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_longer_pattern_one_match() {
+        let ns = vec!["abc", "xyz"];
+        let hay = "zazxyzz";
+        let matches = vec![ Match { pati: 1, start: 3, end: 6 } ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_longer_pattern_many_match() {
+        let ns = vec!["abc", "xyz"];
+        let hay = "zazxyzzzzzazzzabcxyz";
+        let matches = vec![
+            Match { pati: 1, start: 3, end: 6 },
+            Match { pati: 0, start: 14, end: 17 },
+            Match { pati: 1, start: 17, end: 20 },
+        ];
+        assert_eq!(&aut_find(&ns, hay), &matches);
+        assert_eq!(&aut_finds(&ns, hay), &matches);
+        assert_eq!(&aut_findf(&ns, hay), &matches);
+        assert_eq!(&aut_findfs(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_longer_pattern_overlap_one_match() {
+        let ns = vec!["abc", "bc"];
+        let hay = "zazabcz";
+        let matches = vec![
+            Match { pati: 0, start: 3, end: 6 },
+            Match { pati: 1, start: 4, end: 6 },
+        ];
+        assert_eq!(&aut_findo(&ns, hay), &matches);
+        assert_eq!(&aut_findos(&ns, hay), &matches);
+        assert_eq!(&aut_findfo(&ns, hay), &matches);
+        assert_eq!(&aut_findfos(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_longer_pattern_overlap_one_match_reverse() {
+        let ns = vec!["abc", "bc"];
+        let hay = "xbc";
+        let matches = vec![ Match { pati: 1, start: 1, end: 3 } ];
+        assert_eq!(&aut_findo(&ns, hay), &matches);
+        assert_eq!(&aut_findos(&ns, hay), &matches);
+        assert_eq!(&aut_findfo(&ns, hay), &matches);
+        assert_eq!(&aut_findfos(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_longer_pattern_overlap_many_match() {
+        let ns = vec!["abc", "bc", "c"];
+        let hay = "zzzabczzzbczzzc";
+        let matches = vec![
+            Match { pati: 0, start: 3, end: 6 },
+            Match { pati: 1, start: 4, end: 6 },
+            Match { pati: 2, start: 5, end: 6 },
+            Match { pati: 1, start: 9, end: 11 },
+            Match { pati: 2, start: 10, end: 11 },
+            Match { pati: 2, start: 14, end: 15 },
+        ];
+        assert_eq!(&aut_findo(&ns, hay), &matches);
+        assert_eq!(&aut_findos(&ns, hay), &matches);
+        assert_eq!(&aut_findfo(&ns, hay), &matches);
+        assert_eq!(&aut_findfos(&ns, hay), &matches);
+    }
+
+    #[test]
+    fn many_longer_pattern_overlap_many_match_reverse() {
+        let ns = vec!["abc", "bc", "c"];
+        let hay = "zzzczzzbczzzabc";
+        let matches = vec![
+            Match { pati: 2, start: 3, end: 4 },
+            Match { pati: 1, start: 7, end: 9 },
+            Match { pati: 2, start: 8, end: 9 },
+            Match { pati: 0, start: 12, end: 15 },
+            Match { pati: 1, start: 13, end: 15 },
+            Match { pati: 2, start: 14, end: 15 },
+        ];
+        assert_eq!(&aut_findo(&ns, hay), &matches);
+        assert_eq!(&aut_findos(&ns, hay), &matches);
+        assert_eq!(&aut_findfo(&ns, hay), &matches);
+        assert_eq!(&aut_findfos(&ns, hay), &matches);
+    }
+
+    // Quickcheck time.
+
+    // This generates very small ascii strings, which makes them more likely
+    // to interact in interesting ways with larger haystack strings.
+    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+    pub struct SmallAscii(String);
+
+    impl Arbitrary for SmallAscii {
+        fn arbitrary<G: Gen>(g: &mut G) -> SmallAscii {
+            use std::char::from_u32;
+            SmallAscii((0..2)
+                       .map(|_| from_u32(g.gen_range(97, 123)).unwrap())
+                       .collect())
+        }
+
+        fn shrink(&self) -> Box<Iterator<Item=SmallAscii>> {
+            Box::new(self.0.shrink().map(SmallAscii))
+        }
+    }
+
+    impl From<SmallAscii> for String {
+        fn from(s: SmallAscii) -> String { s.0 }
+    }
+
+    // This is the same arbitrary impl as `String`, except it has a bias toward
+    // ASCII characters.
+    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+    pub struct BiasAscii(String);
+
+    impl Arbitrary for BiasAscii {
+        fn arbitrary<G: Gen>(g: &mut G) -> BiasAscii {
+            use std::char::from_u32;
+            let size = { let s = g.size(); g.gen_range(0, s) };
+            let mut s = String::with_capacity(size);
+            for _ in 0..size {
+                if g.gen_weighted_bool(3) {
+                    s.push(char::arbitrary(g));
+                } else {
+                    for _ in 0..5 {
+                        s.push(from_u32(g.gen_range(97, 123)).unwrap());
+                    }
+                }
+            }
+            BiasAscii(s)
+        }
+
+        fn shrink(&self) -> Box<Iterator<Item=BiasAscii>> {
+            Box::new(self.0.shrink().map(BiasAscii))
+        }
+    }
+
+    fn naive_find<S>(xs: &[S], haystack: &str) -> Vec<Match>
+            where S: Clone + Into<String> {
+        let needles: Vec<String> =
+            xs.to_vec().into_iter().map(Into::into).collect();
+        let mut matches = vec![];
+        for hi in 0..haystack.len() {
+            for (pati, needle) in needles.iter().enumerate() {
+                let needle = needle.as_bytes();
+                if needle.len() == 0 || needle.len() > haystack.len() - hi {
+                    continue;
+                }
+                if needle == &haystack.as_bytes()[hi..hi+needle.len()] {
+                    matches.push(Match {
+                        pati: pati,
+                        start: hi,
+                        end: hi + needle.len(),
+                    });
+                }
+            }
+        }
+        matches
+    }
+
+    #[test]
+    fn qc_ac_equals_naive() {
+        fn prop(needles: Vec<SmallAscii>, haystack: BiasAscii) -> bool {
+            let aut_matches = aut_findo(&needles, &haystack.0);
+            let naive_matches = naive_find(&needles, &haystack.0);
+            // Ordering isn't always the same. I don't think we care, so do
+            // an unordered comparison.
+            let aset: HashSet<Match> = aut_matches.iter().cloned().collect();
+            let nset: HashSet<Match> = naive_matches.iter().cloned().collect();
+            aset == nset
+        }
+        quickcheck(prop as fn(Vec<SmallAscii>, BiasAscii) -> bool);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/bitflags/lib.rs.html b/src/bitflags/lib.rs.html new file mode 100644 index 0000000..83312e8 --- /dev/null +++ b/src/bitflags/lib.rs.html @@ -0,0 +1,1121 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A typesafe bitmask flag generator.
+
+/// The `bitflags!` macro generates a `struct` that holds a set of C-style
+/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
+///
+/// The flags should only be defined for integer types, otherwise unexpected
+/// type errors may occur at compile time.
+///
+/// # Example
+///
+/// ```{.rust}
+/// #[macro_use]
+/// extern crate bitflags;
+///
+/// bitflags! {
+///     flags Flags: u32 {
+///         const FLAG_A       = 0b00000001,
+///         const FLAG_B       = 0b00000010,
+///         const FLAG_C       = 0b00000100,
+///         const FLAG_ABC     = FLAG_A.bits
+///                            | FLAG_B.bits
+///                            | FLAG_C.bits,
+///     }
+/// }
+///
+/// fn main() {
+///     let e1 = FLAG_A | FLAG_C;
+///     let e2 = FLAG_B | FLAG_C;
+///     assert!((e1 | e2) == FLAG_ABC);   // union
+///     assert!((e1 & e2) == FLAG_C);     // intersection
+///     assert!((e1 - e2) == FLAG_A);     // set difference
+///     assert!(!e2 == FLAG_A);           // set complement
+/// }
+/// ```
+///
+/// The generated `struct`s can also be extended with type and trait
+/// implementations:
+///
+/// ```{.rust}
+/// #[macro_use]
+/// extern crate bitflags;
+///
+/// use std::fmt;
+///
+/// bitflags! {
+///     flags Flags: u32 {
+///         const FLAG_A   = 0b00000001,
+///         const FLAG_B   = 0b00000010,
+///     }
+/// }
+///
+/// impl Flags {
+///     pub fn clear(&mut self) {
+///         self.bits = 0;  // The `bits` field can be accessed from within the
+///                         // same module where the `bitflags!` macro was invoked.
+///     }
+/// }
+///
+/// impl fmt::Display for Flags {
+///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+///         write!(f, "hi!")
+///     }
+/// }
+///
+/// fn main() {
+///     let mut flags = FLAG_A | FLAG_B;
+///     flags.clear();
+///     assert!(flags.is_empty());
+///     assert_eq!(format!("{}", flags), "hi!");
+///     assert_eq!(format!("{:?}", FLAG_A | FLAG_B), "Flags { bits: 0b11 }");
+///     assert_eq!(format!("{:?}", FLAG_B), "Flags { bits: 0b10 }");
+/// }
+/// ```
+///
+/// # Attributes
+///
+/// Attributes can be attached to the generated `struct` by placing them
+/// before the `flags` keyword.
+///
+/// # Derived traits
+///
+/// The `PartialEq` and `Clone` traits are automatically derived for the
+/// `struct` using the `deriving` attribute. Additional traits can be derived by
+/// providing an explicit `deriving` attribute on `flags`. The `Debug` trait is
+/// also implemented by displaying the bits value of the internal struct.
+///
+/// # Operators
+///
+/// The following operator traits are implemented for the generated `struct`:
+///
+/// - `BitOr`: union
+/// - `BitAnd`: intersection
+/// - `BitXor`: toggle
+/// - `Sub`: set difference
+/// - `Not`: set complement
+///
+/// # Methods
+///
+/// The following methods are defined for the generated `struct`:
+///
+/// - `empty`: an empty set of flags
+/// - `all`: the set of all flags
+/// - `bits`: the raw value of the flags currently stored
+/// - `from_bits`: convert from underlying bit representation, unless that
+///                representation contains bits that do not correspond to a flag
+/// - `from_bits_truncate`: convert from underlying bit representation, dropping
+///                         any bits that do not correspond to flags
+/// - `is_empty`: `true` if no flags are currently stored
+/// - `is_all`: `true` if all flags are currently set
+/// - `intersects`: `true` if there are flags common to both `self` and `other`
+/// - `contains`: `true` all of the flags in `other` are contained within `self`
+/// - `insert`: inserts the specified flags in-place
+/// - `remove`: removes the specified flags in-place
+/// - `toggle`: the specified flags will be inserted if not present, and removed
+///             if they are.
+#[macro_export]
+macro_rules! bitflags {
+    ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
+        $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+
+    }) => {
+        #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
+        $(#[$attr])*
+        pub struct $BitFlags {
+            bits: $T,
+        }
+
+        $($(#[$Flag_attr])* pub const $Flag: $BitFlags = $BitFlags { bits: $value };)+
+
+        impl ::std::fmt::Debug for $BitFlags {
+            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                let out = format!("{} {{ bits: {:#b} }}",
+                                  stringify!($BitFlags),
+                                  self.bits);
+                f.write_str(&out[..])
+            }
+        }
+
+        impl $BitFlags {
+            /// Returns an empty set of flags.
+            #[inline]
+            pub fn empty() -> $BitFlags {
+                $BitFlags { bits: 0 }
+            }
+
+            /// Returns the set containing all flags.
+            #[inline]
+            pub fn all() -> $BitFlags {
+                $BitFlags { bits: $($value)|+ }
+            }
+
+            /// Returns the raw value of the flags currently stored.
+            #[inline]
+            pub fn bits(&self) -> $T {
+                self.bits
+            }
+
+            /// Convert from underlying bit representation, unless that
+            /// representation contains bits that do not correspond to a flag.
+            #[inline]
+            pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> {
+                if (bits & !$BitFlags::all().bits()) != 0 {
+                    ::std::option::Option::None
+                } else {
+                    ::std::option::Option::Some($BitFlags { bits: bits })
+                }
+            }
+
+            /// Convert from underlying bit representation, dropping any bits
+            /// that do not correspond to flags.
+            #[inline]
+            pub fn from_bits_truncate(bits: $T) -> $BitFlags {
+                $BitFlags { bits: bits } & $BitFlags::all()
+            }
+
+            /// Returns `true` if no flags are currently stored.
+            #[inline]
+            pub fn is_empty(&self) -> bool {
+                *self == $BitFlags::empty()
+            }
+
+            /// Returns `true` if all flags are currently set.
+            #[inline]
+            pub fn is_all(&self) -> bool {
+                *self == $BitFlags::all()
+            }
+
+            /// Returns `true` if there are flags common to both `self` and `other`.
+            #[inline]
+            pub fn intersects(&self, other: $BitFlags) -> bool {
+                !(*self & other).is_empty()
+            }
+
+            /// Returns `true` all of the flags in `other` are contained within `self`.
+            #[inline]
+            pub fn contains(&self, other: $BitFlags) -> bool {
+                (*self & other) == other
+            }
+
+            /// Inserts the specified flags in-place.
+            #[inline]
+            pub fn insert(&mut self, other: $BitFlags) {
+                self.bits |= other.bits;
+            }
+
+            /// Removes the specified flags in-place.
+            #[inline]
+            pub fn remove(&mut self, other: $BitFlags) {
+                self.bits &= !other.bits;
+            }
+
+            /// Toggles the specified flags in-place.
+            #[inline]
+            pub fn toggle(&mut self, other: $BitFlags) {
+                self.bits ^= other.bits;
+            }
+        }
+
+        impl ::std::ops::BitOr for $BitFlags {
+            type Output = $BitFlags;
+
+            /// Returns the union of the two sets of flags.
+            #[inline]
+            fn bitor(self, other: $BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits | other.bits }
+            }
+        }
+
+        impl ::std::ops::BitXor for $BitFlags {
+            type Output = $BitFlags;
+
+            /// Returns the left flags, but with all the right flags toggled.
+            #[inline]
+            fn bitxor(self, other: $BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits ^ other.bits }
+            }
+        }
+
+        impl ::std::ops::BitAnd for $BitFlags {
+            type Output = $BitFlags;
+
+            /// Returns the intersection between the two sets of flags.
+            #[inline]
+            fn bitand(self, other: $BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits & other.bits }
+            }
+        }
+
+        impl ::std::ops::Sub for $BitFlags {
+            type Output = $BitFlags;
+
+            /// Returns the set difference of the two sets of flags.
+            #[inline]
+            fn sub(self, other: $BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits & !other.bits }
+            }
+        }
+
+        impl ::std::ops::Not for $BitFlags {
+            type Output = $BitFlags;
+
+            /// Returns the complement of this set of flags.
+            #[inline]
+            fn not(self) -> $BitFlags {
+                $BitFlags { bits: !self.bits } & $BitFlags::all()
+            }
+        }
+    };
+    ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
+        $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+,
+    }) => {
+        bitflags! {
+            $(#[$attr])*
+            flags $BitFlags: $T {
+                $($(#[$Flag_attr])* const $Flag = $value),+
+            }
+        }
+    };
+}
+
+#[cfg(test)]
+#[allow(non_upper_case_globals, dead_code)]
+mod tests {
+    use std::hash::{SipHasher, Hash, Hasher};
+
+    bitflags! {
+        #[doc = "> The first principle is that you must not fool yourself — and"]
+        #[doc = "> you are the easiest person to fool."]
+        #[doc = "> "]
+        #[doc = "> - Richard Feynman"]
+        flags Flags: u32 {
+            const FlagA       = 0b00000001,
+            #[doc = "<pcwalton> macros are way better at generating code than trans is"]
+            const FlagB       = 0b00000010,
+            const FlagC       = 0b00000100,
+            #[doc = "* cmr bed"]
+            #[doc = "* strcat table"]
+            #[doc = "<strcat> wait what?"]
+            const FlagABC     = FlagA.bits
+                               | FlagB.bits
+                               | FlagC.bits,
+        }
+    }
+
+    bitflags! {
+        flags _CfgFlags: u32 {
+            #[cfg(windows)]
+            const _CfgA = 0b01,
+            #[cfg(unix)]
+            const _CfgB = 0b01,
+        }
+    }
+
+    bitflags! {
+        flags AnotherSetOfFlags: i8 {
+            const AnotherFlag = -1_i8,
+        }
+    }
+
+    #[test]
+    fn test_bits(){
+        assert_eq!(Flags::empty().bits(), 0b00000000);
+        assert_eq!(FlagA.bits(), 0b00000001);
+        assert_eq!(FlagABC.bits(), 0b00000111);
+
+        assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
+        assert_eq!(AnotherFlag.bits(), !0_i8);
+    }
+
+    #[test]
+    fn test_from_bits() {
+        assert!(Flags::from_bits(0) == Some(Flags::empty()));
+        assert!(Flags::from_bits(0b1) == Some(FlagA));
+        assert!(Flags::from_bits(0b10) == Some(FlagB));
+        assert!(Flags::from_bits(0b11) == Some(FlagA | FlagB));
+        assert!(Flags::from_bits(0b1000) == None);
+
+        assert!(AnotherSetOfFlags::from_bits(!0_i8) == Some(AnotherFlag));
+    }
+
+    #[test]
+    fn test_from_bits_truncate() {
+        assert!(Flags::from_bits_truncate(0) == Flags::empty());
+        assert!(Flags::from_bits_truncate(0b1) == FlagA);
+        assert!(Flags::from_bits_truncate(0b10) == FlagB);
+        assert!(Flags::from_bits_truncate(0b11) == (FlagA | FlagB));
+        assert!(Flags::from_bits_truncate(0b1000) == Flags::empty());
+        assert!(Flags::from_bits_truncate(0b1001) == FlagA);
+
+        assert!(AnotherSetOfFlags::from_bits_truncate(0_i8) == AnotherSetOfFlags::empty());
+    }
+
+    #[test]
+    fn test_is_empty(){
+        assert!(Flags::empty().is_empty());
+        assert!(!FlagA.is_empty());
+        assert!(!FlagABC.is_empty());
+
+        assert!(!AnotherFlag.is_empty());
+    }
+
+    #[test]
+    fn test_is_all() {
+        assert!(Flags::all().is_all());
+        assert!(!FlagA.is_all());
+        assert!(FlagABC.is_all());
+
+        assert!(AnotherFlag.is_all());
+    }
+
+    #[test]
+    fn test_two_empties_do_not_intersect() {
+        let e1 = Flags::empty();
+        let e2 = Flags::empty();
+        assert!(!e1.intersects(e2));
+
+        assert!(AnotherFlag.intersects(AnotherFlag));
+    }
+
+    #[test]
+    fn test_empty_does_not_intersect_with_full() {
+        let e1 = Flags::empty();
+        let e2 = FlagABC;
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_disjoint_intersects() {
+        let e1 = FlagA;
+        let e2 = FlagB;
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_overlapping_intersects() {
+        let e1 = FlagA;
+        let e2 = FlagA | FlagB;
+        assert!(e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_contains() {
+        let e1 = FlagA;
+        let e2 = FlagA | FlagB;
+        assert!(!e1.contains(e2));
+        assert!(e2.contains(e1));
+        assert!(FlagABC.contains(e2));
+
+        assert!(AnotherFlag.contains(AnotherFlag));
+    }
+
+    #[test]
+    fn test_insert(){
+        let mut e1 = FlagA;
+        let e2 = FlagA | FlagB;
+        e1.insert(e2);
+        assert!(e1 == e2);
+
+        let mut e3 = AnotherSetOfFlags::empty();
+        e3.insert(AnotherFlag);
+        assert!(e3 == AnotherFlag);
+    }
+
+    #[test]
+    fn test_remove(){
+        let mut e1 = FlagA | FlagB;
+        let e2 = FlagA | FlagC;
+        e1.remove(e2);
+        assert!(e1 == FlagB);
+
+        let mut e3 = AnotherFlag;
+        e3.remove(AnotherFlag);
+        assert!(e3 == AnotherSetOfFlags::empty());
+    }
+
+    #[test]
+    fn test_operators() {
+        let e1 = FlagA | FlagC;
+        let e2 = FlagB | FlagC;
+        assert!((e1 | e2) == FlagABC);     // union
+        assert!((e1 & e2) == FlagC);       // intersection
+        assert!((e1 - e2) == FlagA);       // set difference
+        assert!(!e2 == FlagA);             // set complement
+        assert!(e1 ^ e2 == FlagA | FlagB); // toggle
+        let mut e3 = e1;
+        e3.toggle(e2);
+        assert!(e3 == FlagA | FlagB);
+
+        let mut m4 = AnotherSetOfFlags::empty();
+        m4.toggle(AnotherSetOfFlags::empty());
+        assert!(m4 == AnotherSetOfFlags::empty());
+    }
+
+    #[test]
+    fn test_lt() {
+        let mut a = Flags::empty();
+        let mut b = Flags::empty();
+
+        assert!(!(a < b) && !(b < a));
+        b = FlagB;
+        assert!(a < b);
+        a = FlagC;
+        assert!(!(a < b) && b < a);
+        b = FlagC | FlagB;
+        assert!(a < b);
+    }
+
+    #[test]
+    fn test_ord() {
+        let mut a = Flags::empty();
+        let mut b = Flags::empty();
+
+        assert!(a <= b && a >= b);
+        a = FlagA;
+        assert!(a > b && a >= b);
+        assert!(b < a && b <= a);
+        b = FlagB;
+        assert!(b > a && b >= a);
+        assert!(a < b && a <= b);
+    }
+
+    fn hash<T: Hash>(t: &T) -> u64 {
+        let mut s = SipHasher::new_with_keys(0, 0);
+        t.hash(&mut s);
+        s.finish()
+    }
+
+    #[test]
+    fn test_hash() {
+        let mut x = Flags::empty();
+        let mut y = Flags::empty();
+        assert!(hash(&x) == hash(&y));
+        x = Flags::all();
+        y = FlagABC;
+        assert!(hash(&x) == hash(&y));
+    }
+
+    #[test]
+    fn test_debug() {
+        assert_eq!(format!("{:?}", FlagA | FlagB), "Flags { bits: 0b11 }");
+        assert_eq!(format!("{:?}", FlagABC), "Flags { bits: 0b111 }");
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/lib.rs.html b/src/carboxyl/lib.rs.html new file mode 100644 index 0000000..912fa0d --- /dev/null +++ b/src/carboxyl/lib.rs.html @@ -0,0 +1,419 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+
+//! *Carboxyl* provides primitives for functional reactive programming in Rust.
+//! It draws inspiration from the [Sodium][sodium] libraries and Push-Pull FRP,
+//! as described by [Elliott (2009)][elliott_push_pull].
+//!
+//! [sodium]: https://github.com/SodiumFRP/sodium/
+//! [elliott_push_pull]: http://conal.net/papers/push-pull-frp/push-pull-frp.pdf
+//!
+//!
+//! # Overview
+//!
+//! Functional reactive programming (FRP) is a composable and modular
+//! abstraction for creating dynamic and reactive systems. In its most general
+//! form it models these systems as a composition of two basic primitives:
+//! *streams* are a series of singular events and *signals* are continuously
+//! changing values.
+//!
+//! *Carboxyl* is an imperative, hybrid push- and pull-based implementation of
+//! FRP. Streams and the discrete components of signals are data-driven, i.e.
+//! whenever an event occurs the resulting changes are propagated to everything
+//! that depends on it.
+//!
+//! However, the continuous components of signals are demand-driven. Internally,
+//! *Carboxyl* stores the state of a signal as a function. This function has to
+//! be evaluated by consumers of a signal to obtain a concrete value.
+//!
+//! Nonetheless, *Carboxyl* has no explicit notion of time. Its signals are
+//! functions that can be evaluated at any time, but they do not carry any
+//! inherent notion of time. Synchronization and atomicity is achieved by a
+//! transaction system.
+//!
+//!
+//! # Functional reactive primitives
+//!
+//! This library provides two basic types: `Stream` and `Signal`. A stream is a
+//! discrete sequence of events, a signal is a container for values that change
+//! (discretely) over time.
+//!
+//! The FRP primitives are mostly implemented as methods of the basic types to
+//! ease method chaining, except for the various lifting functions, as they do
+//! not really belong to any type in particular.
+//!
+//! In addition, the `Sink` type allows one to create a stream of events by
+//! sending values into it. It is the only way to create a stream from scratch,
+//! i.e. without using any of the other primitives.
+//!
+//!
+//! # Usage example
+//!
+//! Here is a simple example of how you can use the primitives provided by
+//! *Carboxyl*. First of all, events can be sent into a *sink*. From a sink one
+//! can create a *stream* of events. Streams can also be filtered, mapped and
+//! merged. One can e.g. hold the last event from a stream as a signal.
+//!
+//! ```
+//! use carboxyl::Sink;
+//!
+//! let sink = Sink::new();
+//! let stream = sink.stream();
+//! let signal = stream.hold(3);
+//!
+//! // The current value of the signal is initially 3
+//! assert_eq!(signal.sample(), 3);
+//!
+//! // When we fire an event, the signal get updated accordingly
+//! sink.send(5);
+//! assert_eq!(signal.sample(), 5);
+//! ```
+//!
+//! One can also directly iterate over the stream instead of holding it in a
+//! signal:
+//!
+//! ```
+//! # use carboxyl::Sink;
+//! # let sink = Sink::new();
+//! # let stream = sink.stream();
+//! let mut events = stream.events();
+//! sink.send(4);
+//! assert_eq!(events.next(), Some(4));
+//! ```
+//!
+//! Streams and signals can be combined using various primitives. We can map a
+//! stream to another stream using a function:
+//!
+//! ```
+//! # use carboxyl::Sink;
+//! # let sink: Sink<i32> = Sink::new();
+//! # let stream = sink.stream();
+//! let squares = stream.map(|x| x * x).hold(0);
+//! sink.send(4);
+//! assert_eq!(squares.sample(), 16);
+//! ```
+//!
+//! Or we can filter a stream to create a new one that only contains events that
+//! satisfy a certain predicate:
+//!
+//! ```
+//! # use carboxyl::Sink;
+//! # let sink: Sink<i32> = Sink::new();
+//! # let stream = sink.stream();
+//! let negatives = stream.filter(|&x| x < 0).hold(0);
+//!
+//! // This won't arrive at the signal.
+//! sink.send(4);
+//! assert_eq!(negatives.sample(), 0);
+//!
+//! // But this will!
+//! sink.send(-3);
+//! assert_eq!(negatives.sample(), -3);
+//! ```
+//!
+//! There are some other methods on streams and signals, that you can find in
+//! their respective APIs.
+//!
+//! Note that all these objects are `Send + Sync + Clone`. This means you can
+//! easily pass them around in your code, make clones, give them to another
+//! thread, and they will still be updated correctly.
+//!
+//! You may have noticed that certain primitives take a function as an argument.
+//! There is a limitation on what kind of functions can and should be used here.
+//! In general, as FRP provides an abstraction around mutable state, they should
+//! be pure functions (i.e. free of side effects).
+//!
+//! For the most part this is guaranteed by Rust's type system. A static
+//! function with a matching signature always works. A closure though is very
+//! restricted: it must not borrow its environment, as it is impossible to
+//! satisfy the lifetime requirements for that. So you can only move stuff into
+//! it from the environment. However, the moved contents of the closure may also
+//! not be altered, which is guaranteed by the `Fn(…) -> …)` trait bound.
+//!
+//! However, both closures and functions could still have side effects such as
+//! I/O, changing mutable state via `Mutex` or `RefCell`, etc. While Rust's type
+//! system cannot prevent this, you should generally not pass such functions to
+//! the FRP primitives, as they break the benefits you get from using FRP.
+//! (An exception here is debugging output.)
+
+#![feature(arc_weak, fnbox)]
+#![cfg_attr(test, feature(test, scoped))]
+#![warn(missing_docs)]
+
+#[cfg(test)]
+extern crate test;
+#[cfg(test)]
+extern crate rand;
+#[cfg(test)]
+extern crate quickcheck;
+#[macro_use(lazy_static)]
+extern crate lazy_static;
+
+pub use stream::{ Sink, Stream };
+pub use signal::{ Signal, SignalMut };
+
+mod transaction;
+mod source;
+mod pending;
+mod readonly;
+mod stream;
+mod signal;
+#[macro_use]
+pub mod lift;
+#[cfg(test)]
+mod testing;
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/lift.rs.html b/src/carboxyl/lift.rs.html new file mode 100644 index 0000000..224dbe8 --- /dev/null +++ b/src/carboxyl/lift.rs.html @@ -0,0 +1,605 @@ + + + + + + + + + + lift.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+
+//! Lifting of n-ary functions.
+//!
+//! A lift maps a function on values to a function on signals. Given a function of
+//! type `F: Fn(A, B, …) -> R` and signals of types `Signal<A>, Signal<B>, …` the
+//! `lift!` macro creates a `Signal<R>`, whose content is computed using the
+//! function.
+//!
+//! Currently lift is only implemented for functions with up to four arguments.
+//! This limitation is due to the current implementation strategy (and maybe
+//! limitations of Rust's type system), but it can be increased to arbitrary but
+//! finite arity if required.
+//!
+//! # Example
+//!
+//! ```
+//! # #[macro_use] extern crate carboxyl;
+//! # fn main() {
+//! # use carboxyl::Sink;
+//! let sink_a = Sink::new();
+//! let sink_b = Sink::new();
+//! let product = lift!(
+//!     |a, b| a * b,
+//!     &sink_a.stream().hold(0),
+//!     &sink_b.stream().hold(0)
+//! );
+//! assert_eq!(product.sample(), 0);
+//! sink_a.send(3);
+//! sink_b.send(5);
+//! assert_eq!(product.sample(), 15);
+//! # }
+//! ```
+
+use std::sync::Arc;
+use signal::{ Signal, SignalFn, signal_build, signal_current, signal_source, reg_signal, sample_raw };
+use transaction::commit;
+
+
+#[macro_export]
+macro_rules! lift {
+    ($f: expr)
+        => ( $crate::lift::lift0($f) );
+
+    ($f: expr, $a: expr)
+        => ( $crate::lift::lift1($f, $a) );
+
+    ($f: expr, $a: expr, $b: expr)
+        => ( $crate::lift::lift2($f, $a, $b) );
+
+    ($f: expr, $a: expr, $b: expr, $c: expr)
+        => ( $crate::lift::lift3($f, $a, $b, $c) );
+
+    ($f: expr, $a: expr, $b: expr, $c: expr, $d: expr)
+        => ( $crate::lift::lift4($f, $a, $b, $c, $d) );
+}
+
+
+/// Lift a 0-ary function.
+pub fn lift0<A, F>(f: F) -> Signal<A>
+    where F: Fn() -> A + Send + Sync + 'static
+{
+    commit(|| signal_build(SignalFn::from_fn(f), ()))
+}
+
+
+/// Lift a unary function.
+pub fn lift1<A, B, F>(f: F, sa: &Signal<A>) -> Signal<B>
+    where A: Send + Sync + Clone + 'static,
+          B: Send + Sync + Clone + 'static,
+          F: Fn(A) -> B + Send + Sync + 'static,
+{
+    fn make_callback<A, B, F>(f: &Arc<F>, parent: &Signal<A>) -> SignalFn<B>
+        where A: Send + Sync + Clone + 'static,
+              B: Send + Sync + Clone + 'static,
+              F: Fn(A) -> B + Send + Sync + 'static,
+    {
+        let pclone = parent.clone();
+        let f = f.clone();
+        match *signal_current(&parent).read().unwrap().future() {
+            SignalFn::Const(ref a) => SignalFn::Const(f(a.clone())),
+            SignalFn::Func(_) => SignalFn::from_fn(move || f(sample_raw(&pclone))),
+        }
+    }
+
+    commit(|| {
+        let f = Arc::new(f);
+        let signal = signal_build(make_callback(&f, &sa), ());
+        let sa_clone = sa.clone();
+        reg_signal(&mut signal_source(&sa).write().unwrap(), &signal,
+            move |_| make_callback(&f, &sa_clone));
+        signal
+    })
+}
+
+
+/// Lift a binary function.
+pub fn lift2<A, B, C, F>(f: F, sa: &Signal<A>, sb: &Signal<B>) -> Signal<C>
+    where A: Send + Sync + Clone + 'static,
+          B: Send + Sync + Clone + 'static,
+          C: Send + Sync + Clone + 'static,
+          F: Fn(A, B) -> C + Send + Sync + 'static,
+{
+    fn make_callback<A, B, C, F>(f: &Arc<F>, sa: &Signal<A>, sb: &Signal<B>) -> SignalFn<C>
+        where A: Send + Sync + Clone + 'static,
+              B: Send + Sync + Clone + 'static,
+              C: Send + Sync + Clone + 'static,
+              F: Fn(A, B) -> C + Send + Sync + 'static,
+    {
+        use signal::SignalFn::{ Const, Func };
+        let sa_clone = sa.clone();
+        let sb_clone = sb.clone();
+        let f = f.clone();
+        match (
+            signal_current(&sa).read().unwrap().future(),
+            signal_current(&sb).read().unwrap().future(),
+        ) {
+            (&Const(ref a), &Const(ref b)) => Const(f(a.clone(), b.clone())),
+            (&Const(ref a), &Func(_)) => {
+                let a = a.clone();
+                SignalFn::from_fn(move || f(a.clone(), sample_raw(&sb_clone)))
+            },
+            (&Func(_), &Const(ref b)) => {
+                let b = b.clone();
+                SignalFn::from_fn(move || f(sample_raw(&sa_clone), b.clone()))
+            },
+            (&Func(_), &Func(_)) => SignalFn::from_fn(
+                move || f(sample_raw(&sa_clone), sample_raw(&sb_clone))
+            ),
+        }
+    }
+
+    commit(move || {
+        let f = Arc::new(f);
+        let signal = signal_build(make_callback(&f, &sa, &sb), ());
+        reg_signal(&mut signal_source(&sa).write().unwrap(), &signal, {
+            let sa_clone = sa.clone();
+            let sb_clone = sb.clone();
+            let f = f.clone();
+            move |_| make_callback(&f, &sa_clone, &sb_clone)
+        });
+        reg_signal(&mut signal_source(&sb).write().unwrap(), &signal, {
+            let sa_clone = sa.clone();
+            let sb_clone = sb.clone();
+            move |_| make_callback(&f, &sa_clone, &sb_clone)
+        });
+        signal
+    })
+}
+
+/// Lift a ternary function.
+pub fn lift3<F, A, B, C, Ret>(f: F, ca: &Signal<A>, cb: &Signal<B>, cc: &Signal<C>)
+    -> Signal<Ret>
+where F: Fn(A, B, C) -> Ret + Send + Sync + 'static,
+      A: Send + Sync + Clone + 'static,
+      B: Send + Sync + Clone + 'static,
+      C: Send + Sync + Clone + 'static,
+      Ret: Send + Sync + Clone + 'static,
+{
+    lift2(move |(a, b), c| f(a, b, c), &lift2(|a, b| (a, b), ca, cb), cc)
+}
+
+/// Lift a quarternary function.
+pub fn lift4<F, A, B, C, D, Ret>(f: F, ca: &Signal<A>, cb: &Signal<B>, cc: &Signal<C>, cd: &Signal<D>)
+    -> Signal<Ret>
+where F: Fn(A, B, C, D) -> Ret + Send + Sync + 'static,
+      A: Send + Sync + Clone + 'static,
+      B: Send + Sync + Clone + 'static,
+      C: Send + Sync + Clone + 'static,
+      D: Send + Sync + Clone + 'static,
+      Ret: Send + Sync + Clone + 'static,
+{
+    lift2(
+        move |(a, b), (c, d)| f(a, b, c, d),
+        &lift2(|a, b| (a, b), ca, cb),
+        &lift2(|c, d| (c, d), cc, cd)
+    )
+}
+
+
+#[cfg(test)]
+mod test {
+    use stream::Sink;
+    use signal::Signal;
+
+    #[test]
+    fn lift0() {
+        let signal = lift!(|| 3);
+        assert_eq!(signal.sample(), 3);
+    }
+
+    #[test]
+    fn lift1() {
+        let sig2 = lift!(|n| n + 2, &Signal::new(3));
+        assert_eq!(sig2.sample(), 5);
+    }
+
+    #[test]
+    fn lift2() {
+        let sink1 = Sink::new();
+        let sink2 = Sink::new();
+        let lifted = lift!(|a, b| a + b, &sink1.stream().hold(0),
+            &sink2.stream().hold(3));
+        assert_eq!(lifted.sample(), 3);
+        sink1.send(1);
+        assert_eq!(lifted.sample(), 4);
+        sink2.send(11);
+        assert_eq!(lifted.sample(), 12);
+    }
+
+    #[test]
+    fn lift2_identical() {
+        let sig = Signal::new(16);
+        let sig2 = lift!(|a, b| a + b, &sig, &sig);
+        assert_eq!(sig2.sample(), 32);
+    }
+
+    #[test]
+    fn lift3() {
+        let sink = Sink::new();
+        assert_eq!(
+            lift!(|x, y, z| x + 2 * y + z,
+                &sink.stream().hold(5),
+                &sink.stream().hold(3),
+                &sink.stream().hold(-4)
+            ).sample(),
+            7
+        );
+    }
+
+    #[test]
+    fn lift4() {
+        let sink = Sink::new();
+        assert_eq!(
+            lift!(|w, x, y, z| 4 * w + x + 2 * y + z,
+                &sink.stream().hold(-2),
+                &sink.stream().hold(5),
+                &sink.stream().hold(3),
+                &sink.stream().hold(-4)
+            ).sample(),
+            -1
+        );
+    }
+
+    #[test]
+    fn lift0_equal_within_transaction() {
+        use rand::random;
+        // Generate a completely random signal
+        let rnd = lift!(random::<i64>);
+        // Make a tuple with itself
+        let gather = lift!(|a, b| (a, b), &rnd, &rnd);
+        // Both components should be equal
+        let (a, b) = gather.sample();
+        assert_eq!(a, b);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/pending.rs.html b/src/carboxyl/pending.rs.html new file mode 100644 index 0000000..6e0f11f --- /dev/null +++ b/src/carboxyl/pending.rs.html @@ -0,0 +1,271 @@ + + + + + + + + + + pending.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+//! Pending wrapper
+
+use std::ops::Deref;
+
+
+/// A pending value. This is a wrapper type that allows one to queue one new
+/// value without actually overwriting the old value. Later the most recently
+/// queued value can be updated.
+pub struct Pending<T> {
+    current: T,
+    update: Option<T>,
+}
+
+impl<T> Pending<T> {
+    /// Create a new pending value.
+    pub fn new(t: T) -> Pending<T> {
+        Pending { current: t, update: None }
+    }
+
+    /// Put an item in the queue. Ignores any previously queued items.
+    pub fn queue(&mut self, new: T) {
+        self.update = Some(new);
+    }
+
+    /// Updates any update pending.
+    pub fn update(&mut self) {
+        if let Some(t) = self.update.take() {
+            self.current = t;
+        }
+    }
+
+    /// Get the future value.
+    pub fn future(&self) -> &T {
+        self.update.as_ref().unwrap_or(&self.current)
+    }
+}
+
+impl<T> Deref for Pending<T> {
+    type Target = T;
+    fn deref(&self) -> &T { &self.current }
+}
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn new_derefs_identical() {
+        assert_eq!(*Pending::new(3), 3);
+    }
+
+    #[test]
+    fn queue_does_not_affect_deref() {
+        let mut p = Pending::new(2);
+        p.queue(4);
+        assert_eq!(*p, 2);
+    }
+
+    #[test]
+    fn new_future_identical() {
+        assert_eq!(*Pending::new(5).future(), 5);
+    }
+
+    #[test]
+    fn queue_affects_future() {
+        let mut p = Pending::new(10);
+        p.queue(6);
+        assert_eq!(*p.future(), 6);
+    }
+
+    #[test]
+    fn updated_deref() {
+        let mut p = Pending::new(-2);
+        p.queue(2);
+        p.update();
+        assert_eq!(*p, 2);
+    }
+
+    #[test]
+    fn updated_future() {
+        let mut p = Pending::new(-7);
+        p.queue(0);
+        p.update();
+        assert_eq!(*p.future(), 0);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/readonly.rs.html b/src/carboxyl/readonly.rs.html new file mode 100644 index 0000000..84fce7f --- /dev/null +++ b/src/carboxyl/readonly.rs.html @@ -0,0 +1,173 @@ + + + + + + + + + + readonly.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+//! Thread-safe read-only smart pointer.
+
+use std::sync::{ Arc, RwLock, RwLockReadGuard };
+use std::ops::Deref;
+
+/// Guards read-access into a read-only pointer.
+pub struct ReadOnlyGuard<'a, T: 'a> {
+    guard: RwLockReadGuard<'a, T>,
+}
+
+impl<'a, T> Deref for ReadOnlyGuard<'a, T> {
+    type Target = T;
+    fn deref(&self) -> &T { &self.guard }
+}
+
+/// A thread-safe read-only smart pointer.
+pub struct ReadOnly<T> {
+    ptr: Arc<RwLock<T>>,
+}
+
+impl<T> Clone for ReadOnly<T> {
+    fn clone(&self) -> ReadOnly<T> {
+        ReadOnly { ptr: self.ptr.clone() }
+    }
+}
+
+/// Create a new read-only pointer.
+pub fn create<T>(ptr: Arc<RwLock<T>>) -> ReadOnly<T> { ReadOnly { ptr: ptr } }
+
+impl<T> ReadOnly<T> {
+    /// Gain read-access to the stored value.
+    ///
+    /// In case, the underlying data structure has been poisoned, it returns
+    /// `None`.
+    pub fn read(&self) -> Option<ReadOnlyGuard<T>> {
+        self.ptr.read().ok().map(|g| ReadOnlyGuard { guard: g })
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/signal.rs.html b/src/carboxyl/signal.rs.html new file mode 100644 index 0000000..659a0a7 --- /dev/null +++ b/src/carboxyl/signal.rs.html @@ -0,0 +1,1601 @@ + + + + + + + + + + signal.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+
+//! Continuous time signals
+
+use std::sync::{ Arc, Mutex, RwLock };
+use std::ops::Deref;
+use std::fmt;
+#[cfg(test)]
+use quickcheck::{ Arbitrary, Gen };
+
+use source::{ Source, with_weak, CallbackError };
+use stream::{ self, BoxClone, Stream };
+use transaction::{ commit, end };
+use pending::Pending;
+use readonly::{ self, ReadOnly };
+use lift;
+#[cfg(test)]
+use testing::ArcFn;
+
+
+/// A functional signal. Caches its return value during a transaction.
+struct FuncSignal<A> {
+    func: Box<Fn() -> A + Send + Sync + 'static>,
+    cache: Arc<Mutex<Option<A>>>,
+}
+
+impl<A> FuncSignal<A> {
+    pub fn new<F: Fn() -> A + Send + Sync + 'static>(f: F) -> FuncSignal<A> {
+        FuncSignal {
+            func: Box::new(f),
+            cache: Arc::new(Mutex::new(None)),
+        }
+    }
+}
+
+impl<A: Clone + 'static> FuncSignal<A> {
+    /// Call the function or fetch the cached value if present.
+    pub fn call(&self) -> A {
+        let mut cached = self.cache.lock().unwrap();
+        match &mut *cached {
+            &mut Some(ref value) => value.clone(),
+            cached => {
+                // Register callback to reset cache at the end of the transaction
+                let cache = self.cache.clone();
+                end(move || {
+                    let mut live = cache.lock().unwrap();
+                    *live = None;
+                });
+                // Calculate & cache value
+                let value = (self.func)();
+                *cached = Some(value.clone());
+                value
+            },
+        }
+    }
+}
+
+
+pub enum SignalFn<A> {
+    Const(A),
+    Func(FuncSignal<A>),
+}
+
+impl<A> SignalFn<A> {
+    pub fn from_fn<F: Fn() -> A + Send + Sync + 'static>(f: F) -> SignalFn<A> {
+        SignalFn::Func(FuncSignal::new(f))
+    }
+}
+
+impl<A: Clone + 'static> SignalFn<A> {
+    pub fn call(&self) -> A {
+        match *self {
+            SignalFn::Const(ref a) => a.clone(),
+            SignalFn::Func(ref f) => f.call(),
+        }
+    }
+}
+
+
+/// Helper function to register callback handlers related to signal construction.
+pub fn reg_signal<A, B, F>(parent_source: &mut Source<A>, signal: &Signal<B>, handler: F)
+    where A: Send + Sync + 'static,
+          B: Send + Sync + 'static,
+          F: Fn(A) -> SignalFn<B> + Send + Sync + 'static,
+{
+    let weak_source = signal.source.downgrade();
+    let weak_current = signal.current.downgrade();
+    parent_source.register(move |a|
+        weak_current.upgrade().map(|cur| end(
+            move || { let _ = cur.write().map(|mut cur| cur.update()); }))
+            .ok_or(CallbackError::Disappeared)
+        .and(with_weak(&weak_current, |cur| cur.queue(handler(a))))
+        .and(with_weak(&weak_source, |src| src.send(())))
+    );
+}
+
+
+/// External helper function to build a signal.
+pub fn signal_build<A, K>(func: SignalFn<A>, keep_alive: K) -> Signal<A>
+        where K: Send + Sync + Clone + 'static
+{
+    Signal::build(func, keep_alive)
+}
+
+/// External accessor to current state of a signal.
+pub fn signal_current<A>(signal: &Signal<A>) -> &Arc<RwLock<Pending<SignalFn<A>>>> {
+    &signal.current
+}
+
+/// External accessor to signal source.
+pub fn signal_source<A>(signal: &Signal<A>) -> &Arc<RwLock<Source<()>>> {
+    &signal.source
+}
+
+/// Sample the value of the signal without committing it as a transaction.
+pub fn sample_raw<A: Clone + 'static>(signal: &Signal<A>) -> A {
+    signal.current.read().unwrap().call()
+}
+
+
+/// A continuous signal that changes over time.
+///
+/// Signals can be thought of as values that change over time. They have both a
+/// continuous and a discrete component. This means that their current value is
+/// defined by a function that can be called at any time. That function is only
+/// evaluated on-demand, when the signal's current value is sampled. (This is
+/// also called pull semantics in the literature on FRP.)
+///
+/// In addition, the current function used to sample a signal may change
+/// discretely in reaction to some event. For instance, it is possible to create
+/// a signal from an event stream, by holding the last event occurence as the
+/// current value of the stream.
+///
+/// # Algebraic laws
+///
+/// Signals come with some primitive methods to compose them with each other and
+/// with streams. Some of these primitives give the signals an algebraic
+/// structure.
+///
+/// ## Functor
+///
+/// Signals form a functor under unary lifting. Thus, the following laws hold:
+///
+/// - Preservation of identity: `lift!(|x| x, &a) == a`,
+/// - Function composition: `lift!(|x| g(f(x)), &a) == lift!(g, &lift!(f, &a))`.
+///
+/// ## Applicative functor
+///
+/// By extension, using the notion of a signal of a function, signals also
+/// become an [applicative][ghc-applicative] using `Signal::new` as `pure` and
+/// `|sf, sa| lift!(|f, a| f(a), &sf, &sa)` as `<*>`.
+///
+/// *TODO: Expand on this and replace the Haskell reference.*
+///
+/// [ghc-applicative]: https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base/Control-Applicative.html
+pub struct Signal<A> {
+    current: Arc<RwLock<Pending<SignalFn<A>>>>,
+    source: Arc<RwLock<Source<()>>>,
+    #[allow(dead_code)]
+    keep_alive: Box<BoxClone>,
+}
+
+impl<A> Clone for Signal<A> {
+    fn clone(&self) -> Signal<A> {
+        Signal {
+            current: self.current.clone(),
+            source: self.source.clone(),
+            keep_alive: self.keep_alive.box_clone(),
+        }
+    }
+}
+
+impl<A> Signal<A> {
+    fn build<K>(func: SignalFn<A>, keep_alive: K) -> Signal<A>
+        where K: Send + Sync + Clone + 'static
+    {
+        Signal {
+            current: Arc::new(RwLock::new(Pending::new(func))),
+            source: Arc::new(RwLock::new(Source::new())),
+            keep_alive: Box::new(keep_alive),
+        }
+    }
+}
+
+impl<A: Clone + 'static> Signal<A> {
+    /// Create a constant signal.
+    pub fn new(a: A) -> Signal<A> {
+        Signal::build(SignalFn::Const(a), ())
+    }
+
+    /// Sample the current value of the signal.
+    pub fn sample(&self) -> A {
+        commit(|| sample_raw(self))
+    }
+}
+
+impl<A: Clone + Send + Sync + 'static> Signal<A> {
+    /// Create a signal with a cyclic definition.
+    ///
+    /// The closure gets an undefined forward-declaration of a signal. It is
+    /// supposed to return a self-referential definition of the same signal.
+    ///
+    /// Sampling the forward-declared signal, before it is properly defined,
+    /// will cause a run-time panic.
+    ///
+    /// This pattern is useful to implement accumulators, counters and other
+    /// loops that depend on the sampling behaviour of a signal before a
+    /// transaction.
+    pub fn cyclic<F>(def: F) -> Signal<A>
+        where F: FnOnce(&Signal<A>) -> Signal<A>
+    {
+        commit(|| {
+            let cycle = SignalCycle::new();
+            let finished = def(&cycle);
+            cycle.define(finished)
+        })
+    }
+
+    /// Combine the signal with a stream in a snapshot.
+    ///
+    /// `snapshot` creates a new stream given a signal and a stream. Whenever
+    /// the input stream fires an event, the output stream fires an event
+    /// created from the signal's current value and that event using the
+    /// supplied function.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink1: Sink<i32> = Sink::new();
+    /// let sink2: Sink<f64> = Sink::new();
+    /// let mut events = sink1.stream().hold(1)
+    ///     .snapshot(&sink2.stream(), |a, b| (a, b))
+    ///     .events();
+    ///
+    /// // Updating its signal does not cause the snapshot to fire
+    /// sink1.send(4);
+    ///
+    /// // However sending an event down the stream does
+    /// sink2.send(3.0);
+    /// assert_eq!(events.next(), Some((4, 3.0)));
+    /// ```
+    pub fn snapshot<B, C, F>(&self, stream: &Stream<B>, f: F) -> Stream<C>
+        where B: Clone + Send + Sync + 'static,
+              C: Clone + Send + Sync + 'static,
+              F: Fn(A, B) -> C + Send + Sync + 'static,
+    {
+        stream::snapshot(self, stream, f)
+    }
+}
+
+impl<A: Clone + Send + Sync + 'static> Signal<Signal<A>> {
+    /// Switch between signals.
+    ///
+    /// This transforms a `Signal<Signal<A>>` into a `Signal<A>`. The nested
+    /// signal can be thought of as a representation of a switch between different
+    /// input signals, that allows one to change the structure of the dependency
+    /// graph at run-time. `switch` provides a way to access the inner value of
+    /// the currently active signal.
+    ///
+    /// The following example demonstrates how to use this to switch between two
+    /// input signals based on a `Button` event stream:
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// // Button type
+    /// #[derive(Clone, Show)]
+    /// enum Button { A, B };
+    ///
+    /// // The input sinks
+    /// let sink_a = Sink::<i32>::new();
+    /// let sink_b = Sink::<i32>::new();
+    ///
+    /// // The button sink
+    /// let sink_button = Sink::<Button>::new();
+    ///
+    /// // Create the output
+    /// let output = {
+    ///
+    ///     // Hold input sinks in a signal with some initials
+    ///     let channel_a = sink_a.stream().hold(1);
+    ///     let channel_b = sink_b.stream().hold(2);
+    ///
+    ///     // A trivial default channel used before any button event
+    ///     let default_channel = Sink::new().stream().hold(0);
+    ///
+    ///     // Map button to the channel signals, hold with the default channel as
+    ///     // initial value and switch between the signals
+    ///     sink_button
+    ///         .stream()
+    ///         .map(move |b| match b {
+    ///             Button::A => channel_a.clone(),
+    ///             Button::B => channel_b.clone(),
+    ///         })
+    ///         .hold(default_channel)
+    ///         .switch()
+    /// };
+    ///
+    /// // In the beginning, output will come from the default channel
+    /// assert_eq!(output.sample(), 0);
+    ///
+    /// // Let's switch to channel A
+    /// sink_button.send(Button::A);
+    /// assert_eq!(output.sample(), 1);
+    ///
+    /// // And to channel B
+    /// sink_button.send(Button::B);
+    /// assert_eq!(output.sample(), 2);
+    ///
+    /// // The channels can change, too, of course
+    /// for k in 4..13 {
+    ///     sink_b.send(k);
+    ///     assert_eq!(output.sample(), k);
+    /// }
+    /// sink_button.send(Button::A);
+    /// for k in 21..77 {
+    ///     sink_a.send(k);
+    ///     assert_eq!(output.sample(), k);
+    /// }
+    /// ```
+    pub fn switch(&self) -> Signal<A> {
+        fn make_callback<A>(parent: &Signal<Signal<A>>) -> SignalFn<A>
+            where A: Send + Clone + Sync + 'static,
+        {
+            // TODO: use information on inner value
+            let current_signal = parent.current.clone();
+            SignalFn::from_fn(move ||
+                sample_raw(&current_signal.read().unwrap().call())
+            )
+        }
+        commit(|| {
+            let signal = Signal::build(make_callback(self), ());
+            let parent = self.clone();
+            reg_signal(&mut self.source.write().unwrap(), &signal,
+                move |_| make_callback(&parent));
+            signal
+        })
+    }
+}
+
+#[cfg(test)]
+impl<A, B> Signal<ArcFn<A, B>>
+    where A: Clone + Send + Sync + 'static,
+          B: Clone + Send + Sync + 'static,
+{
+    /// Applicative functionality. Applies a signal of function to a signal of
+    /// its argument.
+    fn apply(&self, signal: &Signal<A>) -> Signal<B> {
+        lift::lift2(|f, a| f(a), self, signal)
+    }
+}
+
+#[cfg(test)]
+impl<A: Arbitrary + Sync + Clone + 'static> Arbitrary for Signal<A> {
+    fn arbitrary<G: Gen>(g: &mut G) -> Signal<A> {
+        let values = Vec::<A>::arbitrary(g);
+        if values.is_empty() {
+            Signal::new(Arbitrary::arbitrary(g))
+        } else {
+            let n = Mutex::new(0);
+            lift::lift0(move || {
+                let mut n = n.lock().unwrap();
+                *n += 1;
+                if *n >= values.len() { *n = 0 }
+                values[*n].clone()
+            })
+        }
+    }
+}
+
+impl<A: fmt::Debug + Clone + 'static> fmt::Debug for Signal<A> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        commit(|| match **self.current.read().unwrap() {
+            SignalFn::Const(ref a) =>
+                fmt.debug_struct("Signal::const").field("value", &a).finish(),
+            SignalFn::Func(ref f) =>
+                fmt.debug_struct("Signal::fn").field("current", &f.call()).finish(),
+        })
+    }
+}
+
+
+/// Forward declaration of a signal to create value loops.
+struct SignalCycle<A> {
+    signal: Signal<A>,
+}
+
+impl<A: Send + Sync + Clone + 'static> SignalCycle<A> {
+    /// Forward-declare a new signal.
+    pub fn new() -> SignalCycle<A> {
+        const ERR: &'static str = "sampled on forward-declaration of signal";
+        SignalCycle { signal: Signal::build(SignalFn::from_fn(|| panic!(ERR)), ()) }
+    }
+
+    /// Provide the signal with a definition.
+    pub fn define(self, definition: Signal<A>) -> Signal<A> {
+        /// Generate a callback from the signal definition's current value.
+        fn make_callback<A>(current_def: &Arc<RwLock<Pending<SignalFn<A>>>>) -> SignalFn<A>
+            where A: Send + Sync + Clone + 'static
+        {
+            match *current_def.read().unwrap().future() {
+                SignalFn::Const(ref a) => SignalFn::Const(a.clone()),
+                SignalFn::Func(_) => SignalFn::from_fn({
+                    let sig = current_def.downgrade();
+                    move || {
+                        let strong = sig.upgrade().unwrap();
+                        let ret = strong.read().unwrap().call();
+                        ret
+                    }
+                }),
+            }
+        }
+        commit(move || {
+            *self.signal.current.write().unwrap() = Pending::new(make_callback(&definition.current));
+            let weak_parent = definition.current.downgrade();
+            reg_signal(&mut definition.source.write().unwrap(), &self.signal,
+                move |_| make_callback(&weak_parent.upgrade().unwrap()));
+            Signal { keep_alive: Box::new(definition), ..self.signal }
+        })
+    }
+}
+
+impl<A> Deref for SignalCycle<A> {
+    type Target = Signal<A>;
+    fn deref(&self) -> &Signal<A> { &self.signal }
+}
+
+
+/// Signal variant using inner mutability for efficient in-place updates.
+///
+/// This is the only kind of primitive that allows non-`Clone` types to be
+/// wrapped into functional reactive abstractions. The API is somewhat different
+/// from that of a regular signal to accommodate this.
+///
+/// One cannot directly sample a `SignalMut` as this would require a clone.
+/// Instead it comes with a couple of adaptor methods that mimick a subset of
+/// the `Signal` API. However, all functions passed to these methods take the
+/// argument coming from the `SignalMut` by reference.
+pub struct SignalMut<A> {
+    inner: Signal<ReadOnly<A>>,
+}
+
+impl<A: Send + Sync + 'static> SignalMut<A> {
+    /// Semantically the same as `Signal::snapshot`
+    ///
+    /// The key difference here is, that the combining function takes its first
+    /// argument by reference, as it can't be moved out of the `SignalMut`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink1 = Sink::new();
+    /// let sink2 = Sink::new();
+    /// // Collect values in a mutable `Vec`
+    /// let values = sink1.stream().scan_mut(vec![], |v, a| v.push(a));
+    /// // Snapshot some value from it
+    /// let mut index = values.snapshot(&sink2.stream(),
+    ///     |v, k| v.get(k).map(|x| *x)
+    /// ).events();
+    ///
+    /// sink1.send(4);
+    /// sink1.send(5);
+    /// sink2.send(0);
+    /// assert_eq!(index.next(), Some(Some(4)));
+    ///
+    /// sink2.send(1);
+    /// assert_eq!(index.next(), Some(Some(5)));
+    ///
+    /// sink2.send(2);
+    /// assert_eq!(index.next(), Some(None));
+    /// ```
+    pub fn snapshot<B, C, F>(&self, stream: &Stream<B>, f: F) -> Stream<C>
+        where B: Clone + Send + Sync + 'static,
+              C: Clone + Send + Sync + 'static,
+              F: Fn(&A, B) -> C + Send + Sync + 'static,
+    {
+        self.inner.snapshot(stream, move |a, b| f(&a.read().unwrap(), b))
+    }
+
+    /// Similar to `lift2`. Combines a `SignalMut` with a `Signal` using a
+    /// function. The function takes its first argument by reference.
+    pub fn combine<B, C, F>(&self, signal: &Signal<B>, f: F) -> Signal<C>
+        where B: Clone + Send + Sync + 'static,
+              C: Clone + Send + Sync + 'static,
+              F: Fn(&A, B) -> C + Send + Sync + 'static,
+    {
+        lift::lift2(
+            move |a, b| f(&a.read().unwrap(), b),
+            &self.inner, &signal
+        )
+    }
+
+    /// Similar to `lift2`, but combines two `SignalMut` using a function. The
+    /// supplied function takes both arguments by reference.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink: Sink<i32> = Sink::new();
+    /// let sum = sink.stream().scan_mut(0, |sum, a| *sum += a);
+    /// let product = sink.stream().scan_mut(1, |prod, a| *prod *= a);
+    /// let combo = sum.combine_mut(&product, |s, p| (*s, *p));
+    ///
+    /// sink.send(1);
+    /// assert_eq!(combo.sample(), (1, 1));
+    ///
+    /// sink.send(3);
+    /// assert_eq!(combo.sample(), (4, 3));
+    ///
+    /// sink.send(5);
+    /// assert_eq!(combo.sample(), (9, 15));
+    /// ```
+    pub fn combine_mut<B, C, F>(&self, other: &SignalMut<B>, f: F) -> Signal<C>
+        where B: Clone + Send + Sync + 'static,
+              C: Clone + Send + Sync + 'static,
+              F: Fn(&A, &B) -> C + Send + Sync + 'static,
+    {
+        lift::lift2(
+            move |a, b| f(&a.read().unwrap(), &b.read().unwrap()),
+            &self.inner, &other.inner
+        )
+    }
+}
+
+
+/// Same as Stream::hold.
+pub fn hold<A>(initial: A, stream: &Stream<A>) -> Signal<A>
+    where A: Send + Sync + 'static,
+{
+    commit(|| {
+        let signal = Signal::build(SignalFn::Const(initial), stream.clone());
+        reg_signal(&mut stream::source(&stream).write().unwrap(), &signal, SignalFn::Const);
+        signal
+    })
+}
+
+
+/// Same as Stream::scan_mut.
+pub fn scan_mut<A, B, F>(stream: &Stream<A>, initial: B, f: F) -> SignalMut<B>
+    where A: Send + Sync + 'static,
+          B: Send + Sync + 'static,
+          F: Fn(&mut B, A) + Send + Sync + 'static,
+{
+    commit(move || {
+        let state = Arc::new(RwLock::new(initial));
+        let signal = Signal::build(SignalFn::Const(readonly::create(state.clone())), stream.clone());
+        reg_signal(&mut stream::source(&stream).write().unwrap(), &signal,
+            move |a| { f(&mut state.write().unwrap(), a); SignalFn::Const(readonly::create(state.clone())) });
+        SignalMut { inner: signal }
+    })
+}
+
+
+#[cfg(test)]
+mod test {
+    use quickcheck::quickcheck;
+
+    use ::stream::Sink;
+    use ::signal::{ self, Signal, SignalCycle };
+    use ::lift::lift1;
+    use ::testing::{ ArcFn, signal_eq, id, pure_fn, partial_comp };
+
+    #[test]
+    fn functor_identity() {
+        fn check(signal: Signal<i32>) -> bool {
+            let eq = signal_eq(&signal, &lift1(id, &signal));
+            (0..10).all(|_| eq.sample())
+        }
+        quickcheck(check as fn(Signal<i32>) -> bool);
+    }
+
+    #[test]
+    fn functor_composition() {
+        fn check(signal: Signal<i32>) -> bool {
+            fn f(n: i32) -> i32 { 3 * n }
+            fn g(n: i32) -> i32 { n + 2 }
+            let eq = signal_eq(
+                &lift1(|n| f(g(n)), &signal),
+                &lift1(f, &lift1(g, &signal))
+            );
+            (0..10).all(|_| eq.sample())
+        }
+        quickcheck(check as fn(Signal<i32>) -> bool);
+    }
+
+    #[test]
+    fn applicative_identity() {
+        fn check(signal: Signal<i32>) -> bool {
+            let eq = signal_eq(&pure_fn(id).apply(&signal), &signal);
+            (0..10).all(|_| eq.sample())
+        }
+        quickcheck(check as fn(Signal<i32>) -> bool);
+    }
+
+    #[test]
+    fn applicative_composition() {
+        fn check(signal: Signal<i32>) -> bool {
+            fn f(n: i32) -> i32 { n * 4 }
+            fn g(n: i32) -> i32 { n - 3 }
+            let u = pure_fn(f);
+            let v = pure_fn(g);
+            let eq = signal_eq(
+                &pure_fn(partial_comp).apply(&u).apply(&v).apply(&signal),
+                &u.apply(&v.apply(&signal))
+            );
+            (0..10).all(|_| eq.sample())
+        }
+        quickcheck(check as fn(Signal<i32>) -> bool);
+    }
+
+    #[test]
+    fn applicative_homomorphism() {
+        fn check(x: i32) -> bool {
+            fn f(x: i32) -> i32 { x * (-5) }
+            let eq = signal_eq(
+                &pure_fn(f).apply(&Signal::new(x)),
+                &Signal::new(f(x))
+            );
+            (0..10).all(|_| eq.sample())
+        }
+        quickcheck(check as fn(i32) -> bool);
+    }
+
+    #[test]
+    fn applicative_interchange() {
+        fn check(x: i32) -> bool {
+            fn f(x: i32) -> i32 { x * 2 - 7 }
+            let u = pure_fn(f);
+            let eq = signal_eq(
+                &u.apply(&Signal::new(x)),
+                &pure_fn(move |f: ArcFn<i32, i32>| f(x)).apply(&u)
+            );
+            (0..10).all(|_| eq.sample())
+        }
+        quickcheck(check as fn(i32) -> bool);
+    }
+
+    #[test]
+    fn clone() {
+        let b = Signal::new(3);
+        assert_eq!(b.clone().sample(), 3);
+    }
+
+    #[test]
+    fn hold() {
+        let sink = Sink::new();
+        let signal = sink.stream().hold(3);
+        assert_eq!(signal.sample(), 3);
+        sink.send(4);
+        assert_eq!(signal.sample(), 4);
+    }
+
+    #[test]
+    fn hold_implicit_stream() {
+        let sink = Sink::new();
+        let signal = signal::hold(0, &sink.stream().map(|n| 2 * n));
+        assert_eq!(signal.sample(), 0);
+        sink.send(4);
+        assert_eq!(signal.sample(), 8);
+    }
+
+    #[test]
+    fn snapshot() {
+        let sink1: Sink<i32> = Sink::new();
+        let sink2: Sink<f64> = Sink::new();
+        let mut snap_events = sink1.stream().hold(1)
+            .snapshot(&sink2.stream().map(|x| x + 3.0), |a, b| (a, b))
+            .events();
+        sink2.send(4.0);
+        assert_eq!(snap_events.next(), Some((1, 7.0)));
+    }
+
+    #[test]
+    fn snapshot_2() {
+        let ev1 = Sink::new();
+        let beh1 = ev1.stream().hold(5);
+        let ev2 = Sink::new();
+        let snap = beh1.snapshot(&ev2.stream(), |a, b| (a, b));
+        let mut events = snap.events();
+        ev2.send(4);
+        assert_eq!(events.next(), Some((5, 4)));
+        ev1.send(-2);
+        ev2.send(6);
+        assert_eq!(events.next(), Some((-2, 6)));
+    }
+
+    #[test]
+    fn cyclic_snapshot_accum() {
+        let sink = Sink::new();
+        let stream = sink.stream();
+        let accum = SignalCycle::new();
+        let def = accum.snapshot(&stream, |a, s| a + s).hold(0);
+        let accum = accum.define(def);
+        assert_eq!(accum.sample(), 0);
+        sink.send(3);
+        assert_eq!(accum.sample(), 3);
+        sink.send(7);
+        assert_eq!(accum.sample(), 10);
+        sink.send(-21);
+        assert_eq!(accum.sample(), -11);
+    }
+
+    #[test]
+    fn snapshot_order_standard() {
+        let sink = Sink::new();
+        let signal = sink.stream().hold(0);
+        let mut events = signal
+            .snapshot(&sink.stream(), |a, b| (a, b))
+            .events();
+        sink.send(1);
+        assert_eq!(events.next(), Some((0, 1)));
+    }
+
+    #[test]
+    fn snapshot_lift_order_standard() {
+        let sink = Sink::new();
+        let signal = sink.stream().hold(0);
+        let mut events = lift1(|x| x, &signal)
+            .snapshot(&sink.stream(), |a, b| (a, b))
+            .events();
+        sink.send(1);
+        assert_eq!(events.next(), Some((0, 1)));
+    }
+
+    #[test]
+    fn snapshot_order_alternative() {
+        let sink = Sink::new();
+        // Invert the "natural" order of the registry by declaring the stream before
+        // the signal, which are both used by the snapshot.
+        let first = sink.stream().map(|x| x);
+        let signal = sink.stream().hold(0);
+        let mut events = signal.snapshot(&first, |a, b| (a, b)).events();
+        sink.send(1);
+        assert_eq!(events.next(), Some((0, 1)));
+    }
+
+    #[test]
+    fn cyclic_signal_intermediate() {
+        let sink = Sink::new();
+        let stream = sink.stream();
+        let mut snap = None;
+        let sum = Signal::cyclic(|a| {
+            let my_snap = a.snapshot(&stream, |a, e| e + a);
+            snap = Some(my_snap.clone());
+            my_snap.hold(0)
+        });
+        let snap = snap.unwrap();
+        let mut events = snap.events();
+
+        sink.send(3);
+        assert_eq!(sum.sample(), 3);
+        assert_eq!(events.next(), Some(3));
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/source.rs.html b/src/carboxyl/source.rs.html new file mode 100644 index 0000000..5aab27b --- /dev/null +++ b/src/carboxyl/source.rs.html @@ -0,0 +1,359 @@ + + + + + + + + + + source.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+//! Event sources and callbacks.
+//!
+//! This is a light-weight implementation of the observer pattern. Subjects are
+//! modelled as the `Source` type and observers as boxed closures.
+
+use std::sync::{ RwLock, Weak };
+
+/// An error that can occur with a weakly referenced callback.
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub enum CallbackError {
+    Disappeared,
+    Poisoned,
+}
+
+/// Shorthand for common callback results.
+pub type CallbackResult<T=()> = Result<T, CallbackError>;
+
+/// A boxed callback.
+type Callback<A> = Box<FnMut(A) -> CallbackResult + Send + Sync + 'static>;
+
+
+/// Perform some callback on a weak reference to a mutex and handle errors
+/// gracefully.
+pub fn with_weak<T, U, F: FnOnce(&mut T) -> U>(weak: &Weak<RwLock<T>>, f: F) -> CallbackResult<U> {
+    weak.upgrade()
+        .ok_or(CallbackError::Disappeared)
+        .and_then(|mutex| mutex.write()
+            .map(|mut t| f(&mut t))
+            .map_err(|_| CallbackError::Poisoned)
+        )
+}
+
+
+/// An event source.
+pub struct Source<A> {
+    callbacks: Vec<Callback<A>>,
+}
+
+impl<A> Source<A> {
+    /// Create a new source.
+    pub fn new() -> Source<A> {
+        Source { callbacks: vec![] }
+    }
+
+    /// Register a callback. The callback will be a mutable closure that takes
+    /// an event and must return a result. To unsubscribe from further events,
+    /// the callback has to return an error.
+    pub fn register<F>(&mut self, callback: F)
+        where F: FnMut(A) -> CallbackResult + Send + Sync + 'static
+    {
+        self.callbacks.push(Box::new(callback));
+    }
+}
+
+impl<A: Send + Sync + Clone + 'static> Source<A> {
+    /// Make the source send an event to all its observers.
+    pub fn send(&mut self, a: A) {
+        use std::mem;
+        let mut new_callbacks = vec!();
+        mem::swap(&mut new_callbacks, &mut self.callbacks);
+        self.callbacks = new_callbacks
+            .into_iter()
+            .filter_map(|mut callback| {
+                let result = callback(a.clone());
+                match result {
+                    Ok(_) => Some(callback),
+                    Err(_) => None,
+                }
+            })
+            .collect();
+    }
+}
+
+
+#[cfg(test)]
+mod test {
+    use std::sync::{ Arc, RwLock };
+    use std::thread;
+    use super::*;
+
+    #[test]
+    fn with_weak_no_error() {
+        let a = Arc::new(RwLock::new(3));
+        let weak = a.downgrade();
+        assert_eq!(with_weak(&weak, |a| { *a = 4; }), Ok(()));
+        assert_eq!(*a.read().unwrap(), 4);
+    }
+
+    #[test]
+    fn with_weak_disappeared() {
+        let weak = Arc::new(RwLock::new(3)).downgrade();
+        assert_eq!(with_weak(&weak, |_| ()), Err(CallbackError::Disappeared));
+    }
+
+    #[test]
+    fn with_weak_poisoned() {
+        let a = Arc::new(RwLock::new(3));
+        let a2 = a.clone();
+        let weak = a.downgrade();
+        let _ = thread::spawn(move || {
+            let _g = a2.write().unwrap();
+            panic!();
+        }).join();
+        assert_eq!(with_weak(&weak, |_| ()), Err(CallbackError::Poisoned));
+    }
+
+    #[test]
+    fn source_register_and_send() {
+        let mut src = Source::new();
+        let a = Arc::new(RwLock::new(3));
+        {
+            let a = a.clone();
+            src.register(move |x| {
+                *a.write().unwrap() = x;
+                Ok(())
+            });
+        }
+        assert_eq!(src.callbacks.len(), 1);
+        src.send(4);
+        assert_eq!(*a.read().unwrap(), 4);
+    }
+
+    #[test]
+    fn source_unregister() {
+        let mut src = Source::new();
+        src.register(|_| Err(CallbackError::Disappeared));
+        assert_eq!(src.callbacks.len(), 1);
+        src.send(());
+        assert_eq!(src.callbacks.len(), 0);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/stream.rs.html b/src/carboxyl/stream.rs.html new file mode 100644 index 0000000..8290275 --- /dev/null +++ b/src/carboxyl/stream.rs.html @@ -0,0 +1,1645 @@ + + + + + + + + + + stream.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+
+//! Streams of discrete events
+
+use std::sync::{ Arc, RwLock, Mutex, Weak };
+use std::sync::mpsc::{ Receiver, channel };
+use std::thread;
+use source::{ Source, CallbackError, CallbackResult, with_weak };
+use signal::{ self, Signal, SignalMut, sample_raw };
+use transaction::{ commit, later };
+
+
+/// An event sink.
+///
+/// This primitive is a way of generating streams of events. One can send
+/// input values into a sink and generate a stream that fires all these inputs
+/// as events:
+///
+/// ```
+/// # use carboxyl::Sink;
+/// // A new sink
+/// let sink = Sink::new();
+///
+/// // Make an iterator over a stream.
+/// let mut events = sink.stream().events();
+///
+/// // Send a value into the sink
+/// sink.send(5);
+///
+/// // The stream
+/// assert_eq!(events.next(), Some(5));
+/// ```
+///
+/// You can also feed a sink with an iterator:
+///
+/// ```
+/// # use carboxyl::Sink;
+/// # let sink = Sink::new();
+/// # let mut events = sink.stream().events();
+/// sink.feed(20..40);
+/// assert_eq!(events.take(4).collect::<Vec<_>>(), vec![20, 21, 22, 23]);
+/// ```
+///
+/// # Asynchronous calls
+///
+/// It is possible to send events into the sink asynchronously using the methods
+/// `send_async` and `feed_async`. Note though, that this will void some
+/// guarantees on the order of events. In the following example, it is unclear,
+/// which event is the first in the stream:
+///
+/// ```
+/// # use carboxyl::Sink;
+/// let sink = Sink::new();
+/// let mut events = sink.stream().events();
+/// sink.send_async(13);
+/// sink.send_async(22);
+/// let first = events.next().unwrap();
+/// assert!(first == 13 || first == 22);
+/// ```
+///
+/// `feed_async` provides a workaround, as it preserves the order of events from
+/// the iterator. However, any event sent into the sink after a call to it, may
+/// come at any point between the iterator events.
+pub struct Sink<A> {
+    source: Arc<RwLock<Source<A>>>,
+}
+
+impl<A> Clone for Sink<A> {
+    fn clone(&self) -> Sink<A> {
+        Sink { source: self.source.clone() }
+    }
+}
+
+impl<A: Send + Sync> Sink<A> {
+    /// Create a new sink.
+    pub fn new() -> Sink<A> {
+        Sink { source: Arc::new(RwLock::new(Source::new())) }
+    }
+
+    /// Generate a stream that fires all events sent into the sink.
+    pub fn stream(&self) -> Stream<A> {
+        Stream { source: self.source.clone(), keep_alive: Box::new(()), }
+    }
+}
+
+impl<A: Send + Sync + Clone + 'static> Sink<A> {
+    /// Asynchronous send.
+    ///
+    /// Same as `send`, but it spawns a new thread to process the updates to
+    /// dependent streams and signals.
+    pub fn send_async(&self, a: A) {
+        let clone = self.clone();
+        thread::spawn(move || clone.send(a));
+    }
+
+    /// Feed values from an iterator into the sink.
+    ///
+    /// This method feeds events into the sink from an iterator.
+    pub fn feed<I: IntoIterator<Item=A>>(&self, iterator: I) {
+        for event in iterator {
+            self.send(event);
+        }
+    }
+
+    /// Asynchronous feed.
+    ///
+    /// This is the same as `feed`, but it does not block, since it spawns the
+    /// feeding as a new task. This is useful, if the provided iterator is large
+    /// or even infinite (e.g. an I/O event loop).
+    pub fn feed_async<I: IntoIterator<Item=A> + Send + 'static>(&self, iterator: I) {
+        let clone = self.clone();
+        thread::spawn(move || clone.feed(iterator));
+    }
+
+    /// Send a value into the sink.
+    ///
+    /// When a value is sent into the sink, an event is fired in all dependent
+    /// streams.
+    pub fn send(&self, a: A) {
+        commit(|| self.source.write().unwrap().send(a))
+    }
+}
+
+
+/// Trait to wrap cloning of boxed values in a object-safe manner
+pub trait BoxClone: Sync + Send {
+    /// Clone the object as a boxed trait object
+    fn box_clone(&self) -> Box<BoxClone>; 
+}
+
+impl<T: Sync + Send + Clone + 'static> BoxClone for T {
+    fn box_clone(&self) -> Box<BoxClone> {
+        Box::new(self.clone())
+    }
+}
+
+
+/// Access a stream's source.
+///
+/// This is not defined as a method, so that it can be public to other modules
+/// in this crate while being private outside the crate.
+pub fn source<A>(stream: &Stream<A>) -> &Arc<RwLock<Source<A>>> {
+    &stream.source
+}
+
+
+/// A stream of events.
+///
+/// Conceptually a stream can be thought of as a series of discrete events that
+/// occur at specific times. They are ordered by a transaction system. This
+/// means that firings of disjoint events can not interfere with each other. The
+/// consequences of one event are atomically reflected in dependent quantities.
+///
+/// Streams provide a number of primitive operations. These can be used to
+/// compose streams and combine them with signals. For instance, streams can be
+/// mapped over with a function, merged with another stream of the same type or
+/// filtered by some predicate.
+///
+/// # Algebraic laws
+///
+/// Furthermore, streams satisfy certain algebraic properties that are useful to
+/// reason about them.
+///
+/// ## Monoid
+///
+/// For once, streams of the same type form a **monoid** under merging. The
+/// neutral element in this context is `Stream::never()`. So the following laws
+/// always hold for streams `a`, `b` and `c` of the same type:
+///
+/// - Left identity: `Stream::never().merge(&a) == a`,
+/// - Right identity: `a.merge(&Stream::never()) == a`,
+/// - Associativity: `a.merge(&b).merge(&c) == a.merge(&b.merge(&c))`.
+///
+/// *Note that equality in this context is not actually implemented as such,
+/// since comparing two (potentially infinite) streams is a prohibitive
+/// operation. Instead, the expressions above can be used interchangably and
+/// behave identically.*
+///
+/// ## Functor
+///
+/// Under the mapping operation streams also become a functor. A functor is a
+/// generic type like `Stream` with some mapping operation that takes a function
+/// `Fn(A) -> B` to map a `Stream<A>` to a `Stream<B>`. Algebraically it
+/// satisfies the following laws:
+///
+/// - The identity function is preserved: `a.map(|x| x) == a`,
+/// - Function composition is respected: `a.map(f).map(g) == a.map(|x| g(f(x)))`.
+pub struct Stream<A> {
+    source: Arc<RwLock<Source<A>>>,
+    #[allow(dead_code)]
+    keep_alive: Box<BoxClone>,
+}
+
+impl<A> Clone for Stream<A> {
+    fn clone(&self) -> Stream<A> {
+        Stream {
+            source: self.source.clone(),
+            keep_alive: self.keep_alive.box_clone(),
+        }
+    }
+}
+
+impl<A: Clone + Send + Sync + 'static> Stream<A> {
+    /// Create a stream that never fires. This can be useful in certain
+    /// situations, where a stream is logically required, but no events are
+    /// expected.
+    pub fn never() -> Stream<A> {
+        Stream {
+            source: Arc::new(RwLock::new(Source::new())),
+            keep_alive: Box::new(()) 
+        }
+    }
+
+    /// Map the stream to another stream using a function.
+    ///
+    /// `map` applies a function to every event fired in this stream to create a
+    /// new stream of type `B`.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink: Sink<i32> = Sink::new();
+    /// let mut events = sink.stream().map(|x| x + 4).events();
+    /// sink.send(3);
+    /// assert_eq!(events.next(), Some(7));
+    /// ```
+    pub fn map<B, F>(&self, f: F) -> Stream<B>
+        where B: Send + Sync + Clone + 'static,
+              F: Fn(A) -> B + Send + Sync + 'static,
+    {
+        commit(|| {
+            let src = Arc::new(RwLock::new(Source::new()));
+            let weak = src.downgrade();
+            self.source.write().unwrap()
+                .register(move |a| with_weak(&weak, |src| src.send(f(a))));
+            Stream {
+                source: src,
+                keep_alive: Box::new(self.clone()),
+            }
+        })
+    }
+
+    /// Filter a stream according to a predicate.
+    ///
+    /// `filter` creates a new stream that only fires those events from the
+    /// original stream that satisfy the predicate.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink: Sink<i32> = Sink::new();
+    /// let mut events = sink.stream()
+    ///     .filter(|&x| (x >= 4) && (x <= 10))
+    ///     .events();
+    /// sink.send(2); // won't arrive
+    /// sink.send(5); // will arrive
+    /// assert_eq!(events.next(), Some(5));
+    /// ```
+    pub fn filter<F>(&self, f: F) -> Stream<A>
+        where F: Fn(&A) -> bool + Send + Sync + 'static,
+    {
+        self.filter_map(move |a| if f(&a) { Some(a) } else { None })
+    }
+
+    /// Both filter and map a stream.
+    ///
+    /// This is equivalent to `.map(f).filter_some()`.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink = Sink::new();
+    /// let mut events = sink.stream()
+    ///     .filter_map(|i| if i > 3 { Some(i + 2) } else { None })
+    ///     .events();
+    /// sink.send(2);
+    /// sink.send(4);
+    /// assert_eq!(events.next(), Some(6));
+    /// ```
+    pub fn filter_map<B, F>(&self, f: F) -> Stream<B>
+        where B: Send + Sync + Clone + 'static,
+              F: Fn(A) -> Option<B> + Send + Sync + 'static,
+    {
+        self.map(f).filter_some()
+    }
+
+    /// Merge with another stream.
+    ///
+    /// `merge` takes two streams and creates a new stream that fires events
+    /// from both input streams.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink_1 = Sink::<i32>::new();
+    /// let sink_2 = Sink::<i32>::new();
+    /// let mut events = sink_1.stream().merge(&sink_2.stream()).events();
+    /// sink_1.send(2);
+    /// assert_eq!(events.next(), Some(2));
+    /// sink_2.send(4);
+    /// assert_eq!(events.next(), Some(4));
+    /// ```
+    pub fn merge(&self, other: &Stream<A>) -> Stream<A> {
+        commit(|| {
+            let src = Arc::new(RwLock::new(Source::new()));
+            for parent in [self, other].iter() {
+                let weak = src.downgrade();
+                parent.source.write().unwrap()
+                    .register(move |a| with_weak(&weak, |src| src.send(a)));
+            }
+            Stream {
+                source: src,
+                keep_alive: Box::new((self.clone(), other.clone())),
+            }
+        })
+    }
+
+    /// Coalesce multiple event firings within the same transaction into a
+    /// single event.
+    ///
+    /// The function should ideally commute, as the order of events within a
+    /// transaction is not well-defined.
+    pub fn coalesce<F>(&self, f: F) -> Stream<A>
+        where F: Fn(A, A) -> A + Send + Sync + 'static,
+    {
+        commit(|| {
+            let src = Arc::new(RwLock::new(Source::new()));
+            let weak = src.downgrade();
+            self.source.write().unwrap().register({
+                let mutex = Arc::new(Mutex::new(None));
+                move |a| {
+                    let mut inner = mutex.lock().unwrap();
+                    *inner = Some(match inner.take() {
+                        Some(b) => f(a, b),
+                        None => a,
+                    });
+                    // Send the updated value later
+                    later({
+                        let mutex = mutex.clone();
+                        let weak = weak.clone();
+                        move || {
+                            let mut inner = mutex.lock().unwrap();
+                            // Take it out and map, so that it does not happen twice
+                            inner.take().map(|value|
+                                with_weak(&weak, |src| src.send(value))
+                            );
+                        }
+                    });
+                    Ok(())
+                }
+            });
+            Stream { source: src, keep_alive: Box::new(self.clone()) }
+        })
+    }
+
+    /// Hold an event in a signal.
+    ///
+    /// The resulting signal `hold`s the value of the last event fired by the
+    /// stream.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink = Sink::new();
+    /// let signal = sink.stream().hold(0);
+    /// assert_eq!(signal.sample(), 0);
+    /// sink.send(2);
+    /// assert_eq!(signal.sample(), 2);
+    /// ```
+    pub fn hold(&self, initial: A) -> Signal<A> {
+        signal::hold(initial, self)
+    }
+
+    /// A blocking iterator over the stream.
+    pub fn events(&self) -> Events<A> { Events::new(self) }
+
+    /// Scan a stream and accumulate its event firings in a signal.
+    ///
+    /// Starting at some initial value, each new event changes the value of the
+    /// resulting signal as prescribed by the supplied function.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink = Sink::new();
+    /// let sum = sink.stream().scan(0, |a, b| a + b);
+    /// assert_eq!(sum.sample(), 0);
+    /// sink.send(2);
+    /// assert_eq!(sum.sample(), 2);
+    /// sink.send(4);
+    /// assert_eq!(sum.sample(), 6);
+    /// ```
+    pub fn scan<B, F>(&self, initial: B, f: F) -> Signal<B>
+        where B: Send + Sync + Clone + 'static,
+              F: Fn(B, A) -> B + Send + Sync + 'static,
+    {
+        Signal::cyclic(|scan| scan.snapshot(self, f).hold(initial))
+    }
+
+    /// Scan a stream and accumulate its event firings in some mutable state.
+    ///
+    /// Semantically this is equivalent to `scan`. However, it allows one to use
+    /// a non-Clone type as an accumulator and update it with efficient in-place
+    /// operations.
+    ///
+    /// The resulting `SignalMut` does have a slightly different API from a
+    /// regular `Signal` as it does not allow clones.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use carboxyl::{ Sink, Signal };
+    /// let sink: Sink<i32> = Sink::new();
+    /// let sum = sink.stream()
+    ///     .scan_mut(0, |sum, a| *sum += a)
+    ///     .combine(&Signal::new(()), |sum, ()| *sum);
+    /// assert_eq!(sum.sample(), 0);
+    /// sink.send(2);
+    /// assert_eq!(sum.sample(), 2);
+    /// sink.send(4);
+    /// assert_eq!(sum.sample(), 6);
+    /// ```
+    pub fn scan_mut<B, F>(&self, initial: B, f: F) -> SignalMut<B>
+        where B: Send + Sync + 'static,
+              F: Fn(&mut B, A) + Send + Sync + 'static,
+    {
+        signal::scan_mut(self, initial, f)
+    }
+}
+
+impl<A: Clone + Send + Sync + 'static> Stream<Option<A>> {
+    /// Filter a stream of options.
+    ///
+    /// `filter_some` creates a new stream that only fires the unwrapped
+    /// `Some(…)` events from the original stream omitting any `None` events.
+    ///
+    /// ```
+    /// # use carboxyl::Sink;
+    /// let sink = Sink::new();
+    /// let mut events = sink.stream().filter_some().events();
+    /// sink.send(None); // won't arrive
+    /// sink.send(Some(5)); // will arrive
+    /// assert_eq!(events.next(), Some(5));
+    /// ```
+    pub fn filter_some(&self) -> Stream<A> {
+        commit(|| {
+            let src = Arc::new(RwLock::new(Source::new()));
+            let weak = src.downgrade();
+            self.source.write().unwrap()
+                .register(move |a| a.map_or(
+                    Ok(()),
+                    |a| with_weak(&weak, |src| src.send(a))
+                ));
+            Stream {
+                source: src,
+                keep_alive: Box::new(self.clone())
+            }
+        })
+    }
+}
+
+impl<A: Send + Sync + Clone + 'static> Stream<Stream<A>> {
+    /// Switch between streams.
+    ///
+    /// This takes a stream of streams and maps it to a new stream, which fires
+    /// all events from the most recent stream fired into it.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use carboxyl::{ Sink, Stream };
+    /// // Create sinks
+    /// let stream_sink: Sink<Stream<i32>> = Sink::new();
+    /// let sink1: Sink<i32> = Sink::new();
+    /// let sink2: Sink<i32> = Sink::new();
+    ///
+    /// // Switch and listen
+    /// let switched = stream_sink.stream().switch();
+    /// let mut events = switched.events();
+    ///
+    /// // Should not receive events from either sink
+    /// sink1.send(1); sink2.send(2);
+    ///
+    /// // Now switch to sink 2
+    /// stream_sink.send(sink2.stream());
+    /// sink1.send(3); sink2.send(4);
+    /// assert_eq!(events.next(), Some(4));
+    ///
+    /// // And then to sink 1
+    /// stream_sink.send(sink1.stream());
+    /// sink1.send(5); sink2.send(6);
+    /// assert_eq!(events.next(), Some(5));
+    /// ```
+    pub fn switch(&self) -> Stream<A> {
+        fn rewire_callbacks<A>(new_stream: Stream<A>, source: Weak<RwLock<Source<A>>>,
+                               terminate: &mut Arc<()>)
+            -> CallbackResult
+            where A: Send + Sync + Clone + 'static,
+        {
+            *terminate = Arc::new(());
+            let weak = terminate.downgrade();
+            new_stream.source.write().unwrap().register(move |a|
+                weak.upgrade()
+                    .ok_or(CallbackError::Disappeared)
+                    .and_then(|_| with_weak(&source, |src| src.send(a)))
+            );
+            Ok(())
+        }
+        commit(|| {
+            let src = Arc::new(RwLock::new(Source::new()));
+            let weak = src.downgrade();
+            self.source.write().unwrap().register({
+                let mut terminate = Arc::new(());
+                move |stream| rewire_callbacks(stream, weak.clone(), &mut terminate)
+            });
+            Stream {
+                source: src,
+                keep_alive: Box::new(self.clone()),
+            }
+        })
+    }
+}
+
+
+/// Make a snapshot of a signal, whenever a stream fires an event.
+pub fn snapshot<A, B, C, F>(signal: &Signal<A>, stream: &Stream<B>, f: F) -> Stream<C>
+    where A: Clone + Send + Sync + 'static,
+          B: Clone + Send + Sync + 'static,
+          C: Clone + Send + Sync + 'static,
+          F: Fn(A, B) -> C + Send + Sync + 'static,
+{
+    commit(|| {
+        let src = Arc::new(RwLock::new(Source::new()));
+        let weak = src.downgrade();
+        stream.source.write().unwrap().register({
+            let signal = signal.clone();
+            move |b| with_weak(&weak, |src| src.send(f(sample_raw(&signal), b)))
+        });
+        Stream {
+            source: src,
+            keep_alive: Box::new((stream.clone(), signal.clone())),
+        }
+    })
+}
+
+
+/// A blocking iterator over events in a stream.
+pub struct Events<A> {
+    receiver: Receiver<A>,
+    #[allow(dead_code)]
+    keep_alive: Box<BoxClone>,
+}
+
+impl<A: Send + Sync + 'static> Events<A> {
+    /// Create a new events iterator.
+    fn new(stream: &Stream<A>) -> Events<A> {
+        commit(|| {
+            let (tx, rx) = channel();
+            let tx = Mutex::new(tx);
+            stream.source.write().unwrap().register(
+                move |a| tx.lock().unwrap().send(a).map_err(|_| CallbackError::Disappeared)
+            );
+            Events {
+                receiver: rx,
+                keep_alive: Box::new(stream.clone()),
+            }
+        })
+    }
+}
+
+impl<A: Send + Sync + 'static> Iterator for Events<A> {
+    type Item = A;
+    fn next(&mut self) -> Option<A> { self.receiver.recv().ok() }
+}
+
+
+#[cfg(test)]
+mod test {
+    use std::thread;
+    use quickcheck::quickcheck;
+
+    use testing::{ id, stream_eq };
+    use super::*;
+
+    #[test]
+    fn sink() {
+        let sink = Sink::new();
+        let mut events = sink.stream().events();
+        sink.send(1);
+        sink.send(2);
+        assert_eq!(events.next(), Some(1));
+        assert_eq!(events.next(), Some(2));
+    }
+
+    #[test]
+    fn map() {
+        let sink = Sink::new();
+        let triple = sink.stream().map(|x| 3 * x);
+        let mut events = triple.events();
+        sink.send(1);
+        assert_eq!(events.next(), Some(3));
+    }
+
+    #[test]
+    fn filter_some() {
+        let sink = Sink::new();
+        let small = sink.stream().filter_some();
+        let mut events = small.events();
+        sink.send(None);
+        sink.send(Some(9));
+        assert_eq!(events.next(), Some(9));
+    }
+
+    #[test]
+    fn chain_1() {
+        let sink: Sink<i32> = Sink::new();
+        let chain = sink.stream()
+            .map(|x| x / 2)
+            .filter(|&x| x < 3);
+        let mut events = chain.events();
+        sink.send(7);
+        sink.send(4);
+        assert_eq!(events.next(), Some(2));
+    }
+
+    #[test]
+    fn merge() {
+        let sink1 = Sink::new();
+        let sink2 = Sink::new();
+        let mut events = sink1.stream().merge(&sink2.stream()).events();
+        sink1.send(12);
+        sink2.send(9);
+        assert_eq!(events.next(), Some(12));
+        assert_eq!(events.next(), Some(9));
+    }
+
+    #[test]
+    fn chain_2() {
+        let sink1: Sink<i32> = Sink::new();
+        let sink2: Sink<i32> = Sink::new();
+        let mut events = sink1.stream().map(|x| x + 4)
+            .merge(
+                &sink2.stream()
+                .filter_map(|x| if x < 4 { Some(x) } else { None })
+                .map(|x| x * 5))
+            .events();
+        sink1.send(12);
+        sink2.send(3);
+        assert_eq!(events.next(), Some(16));
+        assert_eq!(events.next(), Some(15));
+    }
+
+    #[test]
+    fn move_closure() {
+        let sink = Sink::<i32>::new();
+        let x = 3;
+        sink.stream().map(move |y| y + x);
+    }
+
+    #[test]
+    fn scan_race_condition() {
+        let sink = Sink::new();
+        // Feed the sink in the background
+        sink.feed_async(0..100000);
+        // Try it multiple times to increase failure probability, when a data
+        // race can potentially happen.
+        for _ in 0..10 {
+            let _sum = sink.stream().scan(0, |a, b| a + b);
+        }
+    }
+
+    #[test]
+    fn sink_send_async() {
+        let sink = Sink::new();
+        let mut events = sink.stream().events();
+        sink.send_async(1);
+        assert_eq!(events.next(), Some(1));
+    }
+
+    #[test]
+    fn sink_feed() {
+        let sink = Sink::new();
+        let events = sink.stream().events();
+        sink.feed(0..10);
+        for (n, m) in events.take(10).enumerate() {
+            assert_eq!(n as i32, m);
+        }
+    }
+
+    #[test]
+    fn sink_feed_async() {
+        let sink = Sink::new();
+        let events = sink.stream().events();
+        sink.feed_async(0..10);
+        for (n, m) in events.take(10).enumerate() {
+            assert_eq!(n as i32, m);
+        }
+    }
+
+    #[test]
+    fn coalesce() {
+        let sink = Sink::new();
+        let stream = sink.stream()
+            .merge(&sink.stream())
+            .coalesce(|a, b| a + b);
+        let mut events = stream.events();
+
+        sink.send(1);
+        assert_eq!(events.next(), Some(2));
+    }
+
+    #[test]
+    fn monoid_left_identity() {
+        fn check(input: Vec<i32>) -> Result<bool, String> {
+            let sink = Sink::new();
+            let a = sink.stream();
+            let eq = stream_eq(&Stream::never().merge(&a), &a);
+            sink.feed(input.into_iter());
+            eq.sample()
+        }
+        quickcheck(check as fn(Vec<i32>) -> Result<bool, String>);
+    }
+
+    #[test]
+    fn monoid_right_identity() {
+        fn check(input: Vec<i32>) -> Result<bool, String> {
+            let sink = Sink::new();
+            let a = sink.stream();
+            let eq = stream_eq(&a.merge(&Stream::never()), &a);
+            sink.feed(input.into_iter());
+            eq.sample()
+        }
+        quickcheck(check as fn(Vec<i32>) -> Result<bool, String>);
+    }
+
+    #[test]
+    fn monoid_associative() {
+        fn check(input_a: Vec<i32>, input_b: Vec<i32>, input_c: Vec<i32>) -> Result<bool, String> {
+            let sink_a = Sink::new();
+            let sink_b = Sink::new();
+            let sink_c = Sink::new();
+            let a = sink_a.stream();
+            let b = sink_b.stream();
+            let c = sink_c.stream();
+            let eq = stream_eq(&a.merge(&b.merge(&c)), &a.merge(&b).merge(&c));
+            /* feed in parallel */ {
+                let _g1 = thread::scoped(|| sink_a.feed(input_a.into_iter()));
+                let _g2 = thread::scoped(|| sink_b.feed(input_b.into_iter()));
+                let _g3 = thread::scoped(|| sink_c.feed(input_c.into_iter()));
+            }
+            eq.sample()
+        }
+        quickcheck(check as fn(Vec<i32>, Vec<i32>, Vec<i32>) -> Result<bool, String>);
+    }
+
+    #[test]
+    fn functor_identity() {
+        fn check(input: Vec<i32>) -> Result<bool, String> {
+            let sink = Sink::new();
+            let a = sink.stream();
+            let eq = stream_eq(&a.map(id), &a);
+            sink.feed(input.into_iter());
+            eq.sample()
+        }
+        quickcheck(check as fn(Vec<i32>) -> Result<bool, String>);
+    }
+
+    #[test]
+    fn functor_composition() {
+        fn check(input: Vec<i32>) -> Result<bool, String> {
+            fn f(n: i32) -> i64 { (n + 3) as i64 }
+            fn g(n: i64) -> f64 { n as f64 / 2.5 }
+
+            let sink = Sink::new();
+            let a = sink.stream();
+            let eq = stream_eq(&a.map(f).map(g), &a.map(|n| g(f(n))));
+            sink.feed(input.into_iter());
+            eq.sample()
+        }
+        quickcheck(check as fn(Vec<i32>) -> Result<bool, String>);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carboxyl/transaction.rs.html b/src/carboxyl/transaction.rs.html new file mode 100644 index 0000000..e9cc7b6 --- /dev/null +++ b/src/carboxyl/transaction.rs.html @@ -0,0 +1,459 @@ + + + + + + + + + + transaction.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+
+//! A trivial global lock transaction system.
+//!
+//! At the moment, this is really just a global static mutex, that needs to be
+//! locked, to ensure the atomicity of a transaction.
+
+use std::sync::Mutex;
+use std::cell::RefCell;
+use std::boxed::FnBox;
+
+
+/// The global transaction lock.
+///
+/// TODO: revert this to use a static mutex, as soon as that is stabilized in
+/// the standard library.
+lazy_static! {
+    static ref TRANSACTION_MUTEX: Mutex<()> = Mutex::new(());
+}
+
+/// Registry for callbacks to be executed at the end of a transaction.
+thread_local!(
+    static CURRENT_TRANSACTION: RefCell<Option<Transaction>> =
+        RefCell::new(None)
+);
+
+
+/// A callback.
+type Callback = Box<FnBox() + 'static>;
+
+
+/// A transaction.
+pub struct Transaction {
+    intermediate: Vec<Callback>,
+    finalizers: Vec<Callback>,
+}
+
+impl Transaction {
+    /// Create a new transaction
+    fn new() -> Transaction {
+        Transaction {
+            intermediate: vec![],
+            finalizers: vec![],
+        }
+    }
+
+    /// Add a callback that will be called, when the transaction is done
+    /// except for finalizers.
+    pub fn later<F: FnOnce() + 'static>(&mut self, callback: F) {
+        self.intermediate.push(Box::new(callback));
+    }
+
+    /// Add a finalizing callback. This should not have far reaching
+    /// side-effects, and in particular not commit by itself. Typical operations
+    /// for a finalizer are executing queued state updates.
+    pub fn end<F: FnOnce() + 'static>(&mut self, callback: F) {
+        self.finalizers.push(Box::new(callback));
+    }
+
+    /// Advance transactions by moving out intermediate stage callbacks.
+    fn advance(&mut self) -> Vec<Callback> {
+        use std::mem;
+        let mut intermediate = vec![];
+        mem::swap(&mut intermediate, &mut self.intermediate);
+        intermediate
+    }
+
+    /// Finalize the transaction
+    fn finalize(self) {
+        for finalizer in self.finalizers {
+            finalizer.call_box(());
+        }
+    }
+}
+
+
+/// Commit a transaction.
+///
+/// If the thread is not running any transactions currently, the global lock is
+/// acquired. Otherwise a new transaction begins, since given the interface of
+/// this module it is safely assumed that the lock is already held.
+pub fn commit<A, F: FnOnce() -> A>(body: F) -> A {
+    use std::mem;
+    // Begin a new transaction
+    let mut prev = CURRENT_TRANSACTION.with(|current| {
+        let mut prev = Some(Transaction::new());
+        mem::swap(&mut prev, &mut current.borrow_mut());
+        prev
+    });
+    // Acquire global lock if necessary
+    let _lock = match prev {
+        None => Some(TRANSACTION_MUTEX.lock().ok()
+                .expect("global transaction mutex poisoned")
+        ),
+        Some(_) => None,
+    };
+    // Perform the main body of the transaction
+    let result = body();
+    // Advance the transaction as long as necessary
+    loop {
+        let callbacks = with_current(Transaction::advance);
+        if callbacks.is_empty() { break }
+        for callback in callbacks {
+            callback.call_box(());
+        }
+    }
+    // Call all finalizers and drop the transaction
+    CURRENT_TRANSACTION.with(|current|
+        mem::swap(&mut prev, &mut current.borrow_mut())
+    );
+    prev.unwrap().finalize();
+    // Return
+    result
+}
+
+
+/// Register a callback during a transaction.
+pub fn with_current<A, F: FnOnce(&mut Transaction) -> A>(action: F) -> A {
+    CURRENT_TRANSACTION.with(|current|
+        match &mut *current.borrow_mut() {
+            &mut Some(ref mut trans) => action(trans),
+            _ => panic!("there is no active transaction to register a callback"),
+        }
+    )
+}
+
+pub fn later<F: FnOnce() + 'static>(action: F) {
+    with_current(|c| c.later(action))
+}
+
+pub fn end<F: FnOnce() + 'static>(action: F) {
+    with_current(|c| c.end(action))
+}
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn commit_single() {
+        let mut v = 3;
+        commit(|| v += 5);
+        assert_eq!(v, 8);
+    }
+
+    #[test]
+    fn commit_nested() {
+        let mut v = 3;
+        commit(|| {
+            commit(|| v *= 2);
+            v += 4;
+        });
+        assert_eq!(v, 10);
+    }
+
+    #[test]
+    fn commits_parallel() {
+        use std::sync::{Arc, Mutex};
+        use std::thread;
+
+        // Set up a ref-counted value
+        let v = Arc::new(Mutex::new(3));
+        // Spawn a couple of scoped threads performing atomic operations on it
+        let guards: Vec<_> = (0..3)
+            .map(|_| {
+                let v = v.clone();
+                thread::spawn(move || commit(move || {
+                    // Acquire locks independently, s.t. commit atomicity does
+                    // not rely on the local locks here
+                    *v.lock().unwrap() *= 2;
+                    // …and sleep for a bit
+                    thread::sleep_ms(1);
+                    *v.lock().unwrap() -= 1;
+                }))
+            })
+            .collect();
+        // Rejoin with all guards
+        for guard in guards { guard.join().ok().expect("thread failed"); }
+        // Check result
+        assert_eq!(&*v.lock().unwrap(), &17);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/gcc/lib.rs.html b/src/gcc/lib.rs.html new file mode 100644 index 0000000..40271e9 --- /dev/null +++ b/src/gcc/lib.rs.html @@ -0,0 +1,1093 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+
+//! A library for build scripts to compile custom C code
+//!
+//! This library is intended to be used as a `build-dependencies` entry in
+//! `Cargo.toml`:
+//!
+//! ```toml
+//! [build-dependencies]
+//! gcc = "0.2"
+//! ```
+//!
+//! The purpose of this crate is to provide the utility functions necessary to
+//! compile C code into a static archive which is then linked into a Rust crate.
+//! The top-level `compile_library` function serves as a convenience and more
+//! advanced configuration is available through the `Config` builder.
+//!
+//! This crate will automatically detect situations such as cross compilation or
+//! other environment variables set by Cargo and will build code appropriately.
+//!
+//! # Examples
+//!
+//! Use the default configuration:
+//!
+//! ```no_run
+//! extern crate gcc;
+//!
+//! fn main() {
+//!     gcc::compile_library("libfoo.a", &["src/foo.c"]);
+//! }
+//! ```
+//!
+//! Use more advanced configuration:
+//!
+//! ```no_run
+//! extern crate gcc;
+//!
+//! fn main() {
+//!     gcc::Config::new()
+//!                 .file("src/foo.c")
+//!                 .define("FOO", Some("bar"))
+//!                 .include("src")
+//!                 .compile("libfoo.a");
+//! }
+//! ```
+
+#![doc(html_root_url = "http://alexcrichton.com/gcc-rs")]
+#![cfg_attr(test, deny(warnings))]
+
+use std::env;
+use std::ffi::OsString;
+use std::fs;
+use std::io;
+use std::path::{PathBuf, Path};
+use std::process::{Command, Stdio};
+
+/// Extra configuration to pass to gcc.
+pub struct Config {
+    include_directories: Vec<PathBuf>,
+    definitions: Vec<(String, Option<String>)>,
+    objects: Vec<PathBuf>,
+    flags: Vec<String>,
+    files: Vec<PathBuf>,
+    cpp: bool,
+    cpp_link_stdlib: Option<String>,
+    cpp_set_stdlib: Option<String>,
+}
+
+/// Returns the default C++ standard library for the current target: `libc++`
+/// for OS X and `libstdc++` for anything else.
+fn target_default_cpp_stdlib() -> Option<&'static str> {
+    let target = getenv_unwrap("TARGET");
+    if target.contains("msvc") {
+        None
+    } else if target.contains("darwin") {
+        Some("c++")
+    } else {
+        Some("stdc++")
+    }
+}
+
+fn getenv(v: &str) -> Option<String> {
+    let r = env::var(v).ok();
+    println!("{} = {:?}", v, r);
+    r
+}
+
+fn getenv_unwrap(v: &str) -> String {
+    match getenv(v) {
+        Some(s) => s,
+        None => fail(&format!("environment variable `{}` not defined", v)),
+    }
+}
+
+/// Compile a library from the given set of input C files.
+///
+/// This will simply compile all files into object files and then assemble them
+/// into the output. This will read the standard environment variables to detect
+/// cross compilations and such.
+///
+/// This function will also print all metadata on standard output for Cargo.
+///
+/// # Example
+///
+/// ```no_run
+/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
+/// ```
+pub fn compile_library(output: &str, files: &[&str]) {
+    let mut c = Config::new();
+    for f in files.iter() {
+        c.file(*f);
+    }
+    c.compile(output)
+}
+
+impl Config {
+    /// Construct a new instance of a blank set of configuration.
+    ///
+    /// This builder is finished with the `compile` function.
+    pub fn new() -> Config {
+        Config {
+            include_directories: Vec::new(),
+            definitions: Vec::new(),
+            objects: Vec::new(),
+            flags: Vec::new(),
+            files: Vec::new(),
+            cpp: false,
+            cpp_link_stdlib: target_default_cpp_stdlib().map(|s| s.into()),
+            cpp_set_stdlib: None,
+        }
+    }
+
+    /// Add a directory to the `-I` or include path for headers
+    pub fn include<P: AsRef<Path>>(&mut self, dir: P) -> &mut Config {
+        self.include_directories.push(dir.as_ref().to_path_buf());
+        self
+    }
+
+    /// Specify a `-D` variable with an optional value.
+    pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config {
+        self.definitions.push((var.to_string(), val.map(|s| s.to_string())));
+        self
+    }
+
+    /// Add an arbitrary object file to link in
+    pub fn object<P: AsRef<Path>>(&mut self, obj: P) -> &mut Config {
+        self.objects.push(obj.as_ref().to_path_buf());
+        self
+    }
+
+    /// Add an arbitrary flag to the invocation of the compiler
+    pub fn flag(&mut self, flag: &str) -> &mut Config {
+        self.flags.push(flag.to_string());
+        self
+    }
+
+    /// Add a file which will be compiled
+    pub fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut Config {
+        self.files.push(p.as_ref().to_path_buf());
+        self
+    }
+
+    /// Set C++ support.
+    ///
+    /// The other `cpp_*` options will only become active if this is set to
+    /// `true`.
+    pub fn cpp(&mut self, cpp: bool) -> &mut Config {
+        self.cpp = cpp;
+        self
+    }
+
+    /// Set the standard library to link against when compiling with C++
+    /// support.
+    ///
+    /// The default value of this property depends on the current target: On
+    /// OS X `Some("c++")` is used, when compiling for a Visual Studio based
+    /// target `None` is used and for other targets `Some("stdc++")` is used.
+    ///
+    /// A value of `None` indicates that no automatic linking should happen,
+    /// otherwise cargo will link against the specified library.
+    ///
+    /// The given library name must not contain the `lib` prefix.
+    pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>) -> &mut Config {
+        self.cpp_link_stdlib = cpp_link_stdlib.map(|s| s.into());
+        self
+    }
+
+    /// Force the C++ compiler to use the specified standard library.
+    ///
+    /// Setting this option will automatically set `cpp_link_stdlib` to the same
+    /// value.
+    ///
+    /// The default value of this option is always `None`.
+    ///
+    /// This option has no effect when compiling for a Visual Studio based
+    /// target.
+    ///
+    /// This option sets the `-stdlib` flag, which is only supported by some
+    /// compilers (clang, icc) but not by others (gcc). The library will not
+    /// detect which compiler is used, as such it is the responsibility of the
+    /// caller to ensure that this option is only used in conjuction with a
+    /// compiler which supports the `-stdlib` flag.
+    ///
+    /// A value of `None` indicates that no specific C++ standard library should
+    /// be used, otherwise `-stdlib` is added to the compile invocation.
+    ///
+    /// The given library name must not contain the `lib` prefix.
+    pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>) -> &mut Config {
+        self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into());
+
+        self.cpp_link_stdlib(cpp_set_stdlib);
+
+        self
+    }
+
+    /// Run the compiler, generating the file `output`
+    ///
+    /// The name `output` must begin with `lib` and end with `.a`
+    pub fn compile(&self, output: &str) {
+        assert!(output.starts_with("lib"));
+        assert!(output.ends_with(".a"));
+        let lib_name = &output[3..output.len() - 2];
+
+        let target = getenv_unwrap("TARGET");
+        let src = PathBuf::from(getenv_unwrap("CARGO_MANIFEST_DIR"));
+        let dst = PathBuf::from(getenv_unwrap("OUT_DIR"));
+        let mut objects = Vec::new();
+        for file in self.files.iter() {
+            let mut cmd = self.compile_cmd(&target);
+            cmd.arg(src.join(file));
+
+            let obj = dst.join(file).with_extension("o");
+            fs::create_dir_all(&obj.parent().unwrap()).unwrap();
+            if target.contains("msvc") {
+                let mut s = OsString::from("/Fo:");
+                s.push(&obj);
+                cmd.arg(s);
+            } else {
+                cmd.arg("-o").arg(&obj);
+            }
+            run(&mut cmd, &self.compiler(&target));
+            objects.push(obj);
+        }
+
+        if target.contains("msvc") {
+            let mut out = OsString::from("/OUT:");
+            out.push(dst.join(output));
+            run(Command::new("lib").arg(out).args(&objects).args(&self.objects),
+                "lib");
+
+            // The Rust compiler will look for libfoo.a and foo.lib, but the
+            // MSVC linker will also be passed foo.lib, so be sure that both
+            // exist for now.
+            let lib_dst = dst.join(format!("{}.lib", lib_name));
+            let _ = fs::remove_file(&lib_dst);
+            fs::hard_link(dst.join(output), lib_dst).unwrap();
+        } else {
+            run(Command::new(&ar(&target)).arg("crus")
+                                          .arg(&dst.join(output))
+                                          .args(&objects)
+                                          .args(&self.objects),
+                &ar(&target));
+        }
+        println!("cargo:rustc-link-search=native={}", dst.display());
+        println!("cargo:rustc-link-lib=static={}",
+                 &output[3..output.len() - 2]);
+
+        // Add specific C++ libraries, if enabled.
+        if self.cpp {
+            if let Some(ref stdlib) = self.cpp_link_stdlib {
+                println!("cargo:rustc-link-lib={}", stdlib);
+            }
+        }
+    }
+
+    fn compiler(&self, target: &str) -> String {
+        if self.cpp {
+            gxx(target)
+        } else {
+            gcc(target)
+        }
+    }
+
+    fn compile_flags(&self) -> Vec<String> {
+        if self.cpp {
+            cxxflags()
+        } else {
+            cflags()
+        }
+    }
+
+    fn compile_cmd(&self, target: &str) -> Command {
+        let opt_level = getenv_unwrap("OPT_LEVEL");
+        let profile = getenv_unwrap("PROFILE");
+        println!("{} {}", profile, opt_level);
+
+        let mut cmd = Command::new(self.compiler(&target));
+
+        if target.contains("msvc") {
+            cmd.arg("/c");
+            cmd.arg("/MD"); // link against msvcrt.dll for now
+            cmd.arg(format!("/O{}", opt_level));
+        } else {
+            cmd.arg(format!("-O{}", opt_level));
+            cmd.arg("-c");
+            cmd.arg("-ffunction-sections").arg("-fdata-sections");
+        }
+        cmd.args(&self.compile_flags());
+
+        if target.contains("-ios") {
+            cmd.args(&ios_flags(&target));
+        } else if !target.contains("msvc") {
+            if target.contains("windows") {
+                cmd.arg("-mwin32");
+            }
+
+            if target.contains("i686") {
+                cmd.arg("-m32");
+            } else if target.contains("x86_64") {
+                cmd.arg("-m64");
+            }
+
+            if !target.contains("i686") {
+                cmd.arg("-fPIC");
+            }
+        }
+
+        if self.cpp && !target.contains("msvc") {
+            if let Some(ref stdlib) = self.cpp_set_stdlib {
+                cmd.arg(&format!("-stdlib=lib{}", stdlib));
+            }
+        }
+
+        for directory in self.include_directories.iter() {
+            cmd.arg(if target.contains("msvc") {"/I"} else {"-I"});
+            cmd.arg(directory);
+        }
+
+        for flag in self.flags.iter() {
+            cmd.arg(flag);
+        }
+
+        for &(ref key, ref value) in self.definitions.iter() {
+            let lead = if target.contains("msvc") {"/"} else {"-"};
+            if let &Some(ref value) = value {
+                cmd.arg(&format!("{}D{}={}", lead, key, value));
+            } else {
+                cmd.arg(&format!("{}D{}", lead, key));
+            }
+        }
+        return cmd;
+    }
+}
+
+fn run(cmd: &mut Command, program: &str) {
+    println!("running: {:?}", cmd);
+    let status = match cmd.status() {
+        Ok(status) => status,
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
+            let extra = if cfg!(windows) {
+                " (see https://github.com/alexcrichton/gcc-rs#windows-notes \
+                   for help)"
+            } else {
+                ""
+            };
+            fail(&format!("failed to execute command: {}\nIs `{}` \
+                           not installed?{}", e, program, extra));
+        }
+        Err(e) => fail(&format!("failed to execute command: {}", e)),
+    };
+    if !status.success() {
+        fail(&format!("command did not execute successfully, got: {}", status));
+    }
+}
+
+fn get_var(var_base: &str) -> Result<String, String> {
+    let target = getenv_unwrap("TARGET");
+    let host = getenv_unwrap("HOST");
+    let kind = if host == target {"HOST"} else {"TARGET"};
+    let target_u = target.replace("-", "_");
+    let res = getenv(&format!("{}_{}", var_base, target))
+        .or_else(|| getenv(&format!("{}_{}", var_base, target_u)))
+        .or_else(|| getenv(&format!("{}_{}", kind, var_base)))
+        .or_else(|| getenv(var_base));
+
+    match res {
+        Some(res) => Ok(res),
+        None => Err("Could not get environment variable".to_string()),
+    }
+}
+
+fn gcc(target: &str) -> String {
+    let is_android = target.find("android").is_some();
+
+    get_var("CC").unwrap_or(if cfg!(windows) {
+        if target.contains("msvc") {
+            "cl".to_string()
+        } else {
+            "gcc".to_string()
+        }
+    } else if is_android {
+        format!("{}-gcc", target)
+    } else {
+        "cc".to_string()
+    })
+}
+
+fn gxx(target: &str) -> String {
+    let is_android = target.find("android").is_some();
+
+    get_var("CXX").unwrap_or(if cfg!(windows) {
+        if target.contains("msvc") {
+            "cl".to_string()
+        } else {
+            "g++".to_string()
+        }
+    } else if is_android {
+        format!("{}-g++", target)
+    } else {
+        "c++".to_string()
+    })
+}
+
+fn ar(target: &str) -> String {
+    let is_android = target.find("android").is_some();
+
+    get_var("AR").unwrap_or(if is_android {
+        format!("{}-ar", target)
+    } else {
+        "ar".to_string()
+    })
+}
+
+fn envflags(name: &str) -> Vec<String> {
+    get_var(name).unwrap_or(String::new())
+       .split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty())
+       .map(|s| s.to_string())
+       .collect()
+}
+
+fn cflags() -> Vec<String> {
+    envflags("CFLAGS")
+}
+
+fn cxxflags() -> Vec<String> {
+    envflags("CXXFLAGS")
+}
+
+fn ios_flags(target: &str) -> Vec<String> {
+    enum ArchSpec {
+        Device(&'static str),
+        Simulator(&'static str),
+    }
+
+    let mut res = Vec::new();
+
+    let arch = target.split('-').nth(0).expect("expected target in format `arch-vendor-os`");
+    let arch = match arch {
+        "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
+        "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
+        "arm64" | "aarch64" => ArchSpec::Device("arm64"),
+        "i386" | "i686" => ArchSpec::Simulator("-m32"),
+        "x86_64" => ArchSpec::Simulator("-m64"),
+        _ => unreachable!("Unknown arch for iOS target")
+    };
+
+    let sdk = match arch {
+        ArchSpec::Device(arch) => {
+            res.push("-arch".to_string());
+            res.push(arch.to_string());
+            "iphoneos"
+        },
+        ArchSpec::Simulator(arch) => {
+            res.push(arch.to_string());
+            "iphonesimulator"
+        }
+    };
+
+    println!("Detecting iOS SDK path for {}", sdk);
+    let sdk_path = Command::new("xcrun")
+        .arg("--show-sdk-path")
+        .arg("--sdk")
+        .arg(sdk)
+        .stderr(Stdio::inherit())
+        .output()
+        .unwrap()
+        .stdout;
+
+    let sdk_path = String::from_utf8(sdk_path).unwrap();
+
+    res.push("-isysroot".to_string());
+    res.push(sdk_path.trim().to_string());
+
+    res
+}
+
+fn fail(s: &str) -> ! {
+    println!("\n\n{}\n\n", s);
+    panic!()
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/callback.rs.html b/src/irsc/callback.rs.html new file mode 100644 index 0000000..ed767cf --- /dev/null +++ b/src/irsc/callback.rs.html @@ -0,0 +1,127 @@ + + + + + + + + + + callback.rs.html -- source + + + + + + + + + + + + + + + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+
+pub struct Callback<A: Sized> {
+    items: Vec<fn(&mut A)>
+}
+
+impl<A: Sized> Callback<A> {
+    pub fn new() -> Callback<A> {
+        Callback { items: Vec::new() }
+    }
+    pub fn register(&mut self, f: fn(&mut A)) {
+        self.items.push(f)
+    }
+    pub fn fire(&self, v: &mut A) {
+        for _ in self.items.iter().map(|&c| c(v)) {}
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/client.rs.html b/src/irsc/client.rs.html new file mode 100644 index 0000000..4b8adc5 --- /dev/null +++ b/src/irsc/client.rs.html @@ -0,0 +1,657 @@ + + + + + + + + + + client.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+
+use std::io::{
+    self,
+    Write,
+    Read,
+    BufRead,
+    BufReader,
+};
+use std::net::TcpStream;
+use std::borrow::Cow::{ self, Borrowed, Owned };
+use std::sync::{ Arc, RwLock };
+use std::mem;
+use std::cell::UnsafeCell;
+
+use carboxyl::{ Stream, Sink };
+
+use message::Message;
+use command::Command;
+use command::Command::*;
+use reply::Reply;
+use event::Event;
+use ::{ DEBUG, Result, IrscError };
+
+use openssl::ssl::{ Ssl, SslContext, SslMethod, SslStream };
+
+/// Yes, I don't like the name either, but it's private, so...
+enum StreamKind {
+    Plain(TcpStream),
+    Ssl(SslStream<TcpStream>)
+}
+
+impl Write for StreamKind {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match *self {
+            StreamKind::Plain(ref mut s) => s.write(buf),
+            StreamKind::Ssl(ref mut s) => s.write(buf)
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match *self {
+            StreamKind::Plain(ref mut s) => s.flush(),
+            StreamKind::Ssl(ref mut s) => s.flush()
+        }
+    }
+}
+
+impl Read for StreamKind {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        match *self {
+            StreamKind::Plain(ref mut s) => s.read(buf),
+            StreamKind::Ssl(ref mut s) => s.read(buf)
+        }
+    }
+}
+
+pub trait Client {
+    fn send_message(&mut self, msg: Message) -> Result<()>;
+    fn join(&mut self, channel: &str, password: Option<&str>) -> Result<()> {
+        self.send_message(JOIN(vec![channel.into()], password.iter().map(|&p| p.into()).collect()).to_message())
+    }
+
+    fn msg(&mut self, to: &str, message: &str) -> Result<()> {
+        self.send_message(PRIVMSG(to.into(), message.into()).to_message())
+    }
+
+    fn msg_many(&mut self, to: &str, message: &[&str]) -> Result<()> {
+        for m in message {
+            self.msg(to, m);
+        }
+        Result(Ok(()))
+    }
+
+    fn msg_word_wrap(&mut self, to: &str, message: &str, limit: u16) -> Result<()> {
+        let mut line = String::new();
+        for word in message.split_whitespace() {
+            if line.len() + word.len() < limit as usize {
+                line.push_str(" ");
+                line.push_str(word);
+            } else {
+                debug!("Sending {}", line);
+                self.msg(to, &line);
+                line.clear();
+            }
+        }
+        self.msg(to, &line)
+    }
+
+    fn register(&mut self, nick: &str, user: &str, desc: &str, pass: Option<&str>) -> Result<()> {
+        Result(if let Some(pass) = pass {
+            self.send_message(PASS(pass.into()).to_message()).inner()
+        } else { Ok(()) }
+            .and_then(|_| self.send_message(NICK(nick.into()).to_message()).inner())
+            .and_then(|_| self.send_message(USER(user.into(), Borrowed("0"), Borrowed("*"), desc.into()).to_message()).inner())
+        )
+    }
+
+}
+
+pub struct OwnedClient {
+    stream: Option<StreamKind>,
+    sink: Sink<Message>
+}
+
+impl OwnedClient {
+    pub fn new() -> OwnedClient {
+        OwnedClient {
+            stream: None,
+            sink: Sink::new()
+        }
+    }
+
+    fn handle_event(&mut self, msg: &Message) {
+        let _ = match Command::from_message(msg) {
+            Some(PING(s1, s2)) => self.send(PONG(s1, s2)),
+            _ => Result(Ok(()))
+        };
+    }
+
+    pub fn connect(&mut self, host: &str, port: u16) -> Result<()> {
+        let s = &mut self.stream;
+        if s.is_some() { return Result(Err(IrscError::AlreadyConnected)) }
+        *s = match TcpStream::connect((host, port)) {
+            Ok(tcp) => Some(StreamKind::Plain(tcp)),
+            Err(e) => return Result(Err(IrscError::Io(e)))
+        };
+
+        Result(Ok(()))
+    }
+
+    pub fn connect_ssl(&mut self, host: &str, port: u16, ssl: Ssl) -> Result<()> {
+        let s = &mut self.stream;
+        if s.is_some() { return Result(Err(IrscError::AlreadyConnected)) };
+        let tcp_stream = match TcpStream::connect((host, port)) {
+            Ok(tcp) => Some(tcp),
+            Err(e) => return Result(Err(IrscError::Io(e)))
+        };
+
+        match tcp_stream.map(|tcp| SslStream::new_from(ssl, tcp)) {
+            Some(Ok(ssl_stream)) => {
+                *s = Some(StreamKind::Ssl(ssl_stream));
+                Result(Ok(()))
+            },
+            Some(Err(ssl_error)) => Result(Err(IrscError::Ssl(ssl_error))),
+            None => Result(Err(IrscError::NotConnected))
+        }
+    }
+
+    #[inline]
+    fn send_raw(&mut self, s: &str) -> Result<()> {
+        info!(">> {}", s);
+        if DEBUG && s.len() > 512 {
+            panic!("Message too long, kittens will die if this runs in release mode. Msg: {}", s)
+        }
+
+        Result(self.stream.as_mut()
+            .ok_or(IrscError::NotConnected)
+            .and_then(|mut stream| stream.write_all(s.as_bytes())
+                                         .and_then(|_| stream.flush())
+                                         .map_err(IrscError::Io)))
+    }
+
+
+    pub fn send(&mut self, cmd: Command) -> Result<()> {
+        self.send_message(cmd.to_message())
+    }
+
+    pub fn listen_with_callback<F>(&mut self, on_event: F) -> Result<()>
+    where F: Fn(&mut Client, &Message, Option<Event>) {
+        let reader = BufReader::new(match self.stream {
+            Some(StreamKind::Plain(ref s)) => StreamKind::Plain((*s).try_clone().unwrap()),
+            Some(StreamKind::Ssl(ref s)) => StreamKind::Ssl((*s).try_clone().unwrap()),
+            None => return Result(Err(IrscError::NotConnected))
+        });
+
+        for raw_line in reader.lines() {
+            let line = raw_line.as_ref().unwrap().parse();
+            info!("<< {}", raw_line.unwrap());
+
+            if let Ok(msg) = line {
+                self.handle_event(&msg);
+
+                // Try to parse the message into a Command or a Reply, and call back.
+                let event = match Command::from_message(&msg) {
+                    Some(m) => Some(Event::Command(m)),
+                    None => match Reply::from_message(&msg) {
+                        Some(r) => Some(Event::Reply(r)),
+                        None => None
+                    }
+                };
+                on_event(self, &msg, event);
+            }
+        }
+        Result(Ok(()))
+    }
+
+    #[allow(mutable_transmutes)]
+    fn listen_with_events(&self) -> Result<()> {
+        let mut s: &mut OwnedClient = unsafe { mem::transmute(self) };
+        let reader = BufReader::new(match self.stream {
+            Some(StreamKind::Plain(ref s)) => StreamKind::Plain((*s).try_clone().unwrap()),
+            Some(StreamKind::Ssl(ref s)) => StreamKind::Ssl((*s).try_clone().unwrap()),
+            None => return Result(Err(IrscError::NotConnected))
+        });
+
+        for raw_line in reader.lines() {
+            let line = raw_line.as_ref().unwrap().parse();
+            info!("<< {}", raw_line.unwrap());
+
+            if let Ok(msg) = line {
+                s.handle_event(&msg);
+                self.sink.send(msg);
+            }
+        }
+        Result(Ok(()))
+    }
+
+    pub fn into_shared(self) -> SharedClient {
+        SharedClient {
+            client: Arc::new(OwnedClientCell(UnsafeCell::new(self))),
+        }
+    }
+
+    pub fn messages(&self) -> Stream<Message> { self.sink.stream() }
+}
+
+struct OwnedClientCell(UnsafeCell<OwnedClient>);
+unsafe impl Sync for OwnedClientCell {}
+
+impl Client for OwnedClient {
+    fn send_message(&mut self, msg: Message) -> Result<()> {
+        self.send_raw(&msg.to_string())
+    }
+}
+
+#[derive(Clone)]
+pub struct SharedClient {
+    client: Arc<OwnedClientCell>,
+}
+
+impl SharedClient {
+    pub fn messages(&self) -> Stream<(SharedClient, Message)> {
+        let cl = SharedClient { client: self.client.clone() };
+        unsafe { &*self.client.0.get() }.messages()
+            .map(move |m| (cl.clone(), m))
+    }
+
+    pub fn events(&self) -> Stream<(SharedClient, Message, Event<'static>)> {
+        self.messages().filter_map(|(cl, msg)| match Command::from_message(&msg) {
+            Some(m) => Some((cl, msg.clone(), Event::Command(m.clone()).to_static())),
+            None => match Reply::from_message(&msg) {
+                Some(r) => Some((cl, msg.clone(), Event::Reply(r).to_static())),
+                None => None
+            }
+        })
+    }
+
+    pub fn listen_with_events(&mut self) -> Result<()> {
+        unsafe { &*self.client.0.get() }.listen_with_events()
+    }
+
+    pub fn commands(&self) -> Stream<(SharedClient, Message, Command<'static>)> {
+        self.messages().filter_map(|(cl, msg)| match Command::from_message(&msg) {
+            Some(m) => Some((cl, msg.clone(), m.to_static())),
+            None => None
+        })
+    }
+
+    pub fn replies(&self) -> Stream<(SharedClient, Message, Reply<'static>)> {
+        self.messages().filter_map(|(cl, msg)| match Reply::from_message(&msg) {
+            Some(m) => Some((cl, msg.clone(), m.to_static())),
+            None => None
+        })
+    }
+}
+
+impl Client for SharedClient {
+    fn send_message(&mut self, msg: Message) -> Result<()> {
+        unsafe { &mut *self.client.0.get() }.send_raw(&msg.to_string())
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/color.rs.html b/src/irsc/color.rs.html new file mode 100644 index 0000000..de361f2 --- /dev/null +++ b/src/irsc/color.rs.html @@ -0,0 +1,189 @@ + + + + + + + + + + color.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+pub const WHITE: &'static str = "00";
+pub const BLACK: &'static str = "01";
+pub const BLUE: &'static str = "02";
+pub const GREEN: &'static str = "03";
+pub const RED: &'static str = "04";
+pub const BROWN: &'static str = "05";
+pub const PURPLE: &'static str = "06";
+pub const ORANGE: &'static str = "07";
+pub const YELLOW: &'static str = "08";
+pub const LIME: &'static str = "09";
+pub const TEAL: &'static str = "10";
+pub const LIGHT_CYAN: &'static str = "11";
+pub const LIGHT_BLUE: &'static str = "12";
+pub const PINK: &'static str = "13";
+pub const GREY: &'static str = "14";
+pub const LIGHT_GREY: &'static str = "15";
+
+pub const TRANSPARENT: &'static str = "99";
+
+pub fn normal(s: &str) -> String {
+    format!("\x0F{}\x0F", s)
+}
+
+pub fn bold(s: &str) -> String {
+    format!("\x02{}\x02", s)
+}
+
+pub fn italic(s: &str) -> String {
+    format!("\x1D{}\x1D", s)
+}
+
+pub fn underline(s: &str) -> String {
+    format!("\x1F{}\x1F", s)
+}
+
+pub fn foreground(s: &str, foreground: &str) -> String {
+    format!("\x03{}{}\x03", foreground, s)
+}
+
+pub fn background(s: &str, background: &str) -> String {
+    format!("\x03,{}{}\x03", background, s)
+}
+
+pub fn color(s: &str, foreground: &str, background: &str) -> String {
+    format!("\x03{},{}{}\x03", foreground, background, s)
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/command.rs.html b/src/irsc/command.rs.html new file mode 100644 index 0000000..37fc316 --- /dev/null +++ b/src/irsc/command.rs.html @@ -0,0 +1,3997 @@ + + + + + + + + + + command.rs.html -- source + + + + + + + + + + + + + + + +
   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
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+
+#![allow(non_camel_case_types)]
+
+use std::borrow::{ Cow, IntoCow, Borrow, ToOwned };
+use std::borrow::Cow::*;
+use std::iter::Extend;
+
+use message::{ Message, MsgType };
+
+pub type CS<'a> = Cow<'a, str>;
+
+// If you hoped it couldn't get any uglier... I'm sorry, it does.
+// Why a giant match? API.
+//
+// I tried structuring it as a bunch of structs that impl a `Command` trait,
+// but the user would have to use Any and lots of cats. Also, extensibility isn't
+// really a goal; the IRC protocol doesn't seem to evolve very fast.
+//
+// Granted, I *could* have used a phf-map to map to functions to parse this, which
+// - while more readable - shouldn't have resulted in performance gains.
+//
+// Please don't cry.
+
+#[derive(Debug, Hash, Clone, PartialEq, Eq)]
+pub enum Command<'a> {
+    /// ```text
+    /// 3.1.1 Password message
+    ///
+    /// Command: PASS
+    /// Parameters: <password>
+    ///
+    /// The PASS command is used to set a 'connection password'.  The
+    /// optional password can and MUST be set before any attempt to register
+    /// the connection is made.  Currently this requires that user send a
+    /// PASS command before sending the NICK/USER combination.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+    ///
+    /// Example:
+    ///
+    ///    PASS secretpasswordhere
+    /// ```
+    PASS(CS<'a>),
+
+    /// ```text
+    /// 3.1.2 Nick message
+    ///
+    /// Command: NICK
+    /// Parameters: <nickname>
+    ///
+    /// NICK command is used to give user a nickname or change the existing
+    /// one.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NONICKNAMEGIVEN             ERR_ERRONEUSNICKNAME
+    ///    ERR_NICKNAMEINUSE               ERR_NICKCOLLISION
+    ///    ERR_UNAVAILRESOURCE             ERR_RESTRICTED
+    ///
+    /// Examples:
+    ///
+    ///    NICK Wiz                ; Introducing new nick "Wiz" if session is
+    ///                            still unregistered, or user changing his
+    ///                            nickname to "Wiz"
+    ///
+    ///    :WiZ!jto@tolsun.oulu.fi NICK Kilroy
+    ///                            ; Server telling that WiZ changed his
+    ///                            nickname to Kilroy.
+    /// ```
+    NICK(CS<'a>),
+
+    /// ```text
+    /// 3.1.3 User message
+    ///
+    /// Command: USER
+    /// Parameters: <user> <mode> <unused> <realname>
+    ///
+    /// The USER command is used at the beginning of connection to specify
+    /// the username, hostname and realname of a new user.
+    ///
+    /// The <mode> parameter should be a numeric, and can be used to
+    /// automatically set user modes when registering with the server.  This
+    /// parameter is a bitmask, with only 2 bits having any signification: if
+    /// the bit 2 is set, the user mode 'w' will be set and if the bit 3 is
+    /// set, the user mode 'i' will be set.  (See Section 3.1.5 "User
+    /// Modes").
+    ///
+    /// The <realname> may contain space characters.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+    ///
+    /// Example:
+    ///
+    ///    USER guest 0 * :Ronnie Reagan   ; User registering themselves with a
+    ///                                    username of "guest" and real name
+    ///                                    "Ronnie Reagan".
+    ///
+    ///    USER guest 8 * :Ronnie Reagan   ; User registering themselves with a
+    ///                                    username of "guest" and real name
+    ///                                    "Ronnie Reagan", and asking to be set
+    ///                                    invisible.
+    /// ```
+    USER(CS<'a>, CS<'a>, CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.1.4 Oper message
+    ///
+    /// Command: OPER
+    /// Parameters: <name> <password>
+    ///
+    /// A normal user uses the OPER command to obtain operator privileges.
+    /// The combination of <name> and <password> are REQUIRED to gain
+    /// Operator privileges.  Upon success, the user will receive a MODE
+    /// message (see section 3.1.5) indicating the new user modes.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              RPL_YOUREOPER
+    ///    ERR_NOOPERHOST                  ERR_PASSWDMISMATCH
+    ///
+    /// Example:
+    ///
+    ///    OPER foo bar                    ; Attempt to register as an operator
+    ///                                    using a username of "foo" and "bar"
+    ///                                    as the password.
+    /// ```
+    OPER(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.1.5 User mode message
+    ///
+    /// Command: MODE
+    /// Parameters: <nickname>
+    ///             *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
+    ///
+    /// The user MODE's are typically changes which affect either how the
+    /// client is seen by others or what 'extra' messages the client is sent.
+    ///
+    /// A user MODE command MUST only be accepted if both the sender of the
+    /// message and the nickname given as a parameter are both the same.  If
+    /// no other parameter is given, then the server will return the current
+    /// settings for the nick.
+    ///
+    /// The available modes are as follows:
+    ///
+    ///    a - user is flagged as away;
+    ///    i - marks a users as invisible;
+    ///    w - user receives wallops;
+    ///    r - restricted user connection;
+    ///    o - operator flag;
+    ///    O - local operator flag;
+    ///    s - marks a user for receipt of server notices.
+    ///
+    /// Additional modes may be available later on.
+    ///
+    /// The flag 'a' SHALL NOT be toggled by the user using the MODE command,
+    /// instead use of the AWAY command is REQUIRED.
+    ///
+    /// If a user attempts to make themselves an operator using the "+o" or
+    /// "+O" flag, the attempt SHOULD be ignored as users could bypass the
+    /// authentication mechanisms of the OPER command.  There is no
+    /// restriction, however, on anyone `deopping' themselves (using "-o" or
+    /// "-O").
+    ///
+    /// On the other hand, if a user attempts to make themselves unrestricted
+    /// using the "-r" flag, the attempt SHOULD be ignored.  There is no
+    /// restriction, however, on anyone `deopping' themselves (using "+r").
+    /// This flag is typically set by the server upon connection for
+    /// administrative reasons.  While the restrictions imposed are left up
+    /// to the implementation, it is typical that a restricted user not be
+    /// allowed to change nicknames, nor make use of the channel operator
+    /// status on channels.
+    ///
+    /// The flag 's' is obsolete but MAY still be used.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_USERSDONTMATCH
+    ///    ERR_UMODEUNKNOWNFLAG            RPL_UMODEIS
+    ///
+    /// Examples:
+    ///
+    ///    MODE WiZ -w                     ; Command by WiZ to turn off
+    ///                                    reception of WALLOPS messages.
+    ///
+    ///    MODE Angel +i                   ; Command from Angel to make herself
+    ///                                    invisible.
+    ///
+    ///    MODE WiZ -o                     ; WiZ 'deopping' (removing operator
+    ///                                    status).
+    /// ```
+    UMODE(CS<'a>),
+
+    /// ```text
+    /// 3.1.6 Service message
+    ///
+    /// Command: SERVICE
+    /// Parameters: <nickname> <reserved> <distribution> <type>
+    ///             <reserved> <info>
+    ///
+    /// The SERVICE command to register a new service.  Command parameters
+    /// specify the service nickname, distribution, type and info of a new
+    /// service.
+    ///
+    /// The <distribution> parameter is used to specify the visibility of a
+    /// service.  The service may only be known to servers which have a name
+    /// matching the distribution.  For a matching server to have knowledge
+    /// of the service, the network path between that server and the server
+    /// on which the service is connected MUST be composed of servers which
+    /// names all match the mask.
+    ///
+    /// The <type> parameter is currently reserved for future usage.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_ALREADYREGISTRED            ERR_NEEDMOREPARAMS
+    ///    ERR_ERRONEUSNICKNAME
+    ///    RPL_YOURESERVICE                RPL_YOURHOST
+    ///    RPL_MYINFO
+    ///
+    /// Example:
+    ///
+    ///    SERVICE dict * *.fr 0 0 :French Dictionary ; Service registering
+    ///                                    itself with a name of "dict".  This
+    ///                                    service will only be available on
+    ///                                    servers which name matches "*.fr".
+    /// ```
+    SERVICE(CS<'a>, CS<'a>, CS<'a>, CS<'a>, CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.1.7 Quit
+    ///
+    /// Command: QUIT
+    /// Parameters: [ <Quit Message> ]
+    ///
+    /// A client session is terminated with a quit message.  The server
+    /// acknowledges this by sending an ERROR message to the client.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    None.
+    ///
+    /// Example:
+    ///
+    ///    QUIT :Gone to have lunch        ; Preferred message format.
+    ///
+    ///    :syrk!kalt@millennium.stealth.net QUIT :Gone to have lunch ; User
+    ///                                    syrk has quit IRC to have lunch.
+    /// ```
+    QUIT(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.1.8 Squit
+    ///
+    /// Command: SQUIT
+    /// Parameters: <server> <comment>
+    ///
+    /// The SQUIT command is available only to operators.  It is used to
+    /// disconnect server links.  Also servers can generate SQUIT messages on
+    /// error conditions.  A SQUIT message may also target a remote server
+    /// connection.  In this case, the SQUIT message will simply be sent to
+    /// the remote server without affecting the servers in between the
+    /// operator and the remote server.
+    ///
+    /// The <comment> SHOULD be supplied by all operators who execute a SQUIT
+    /// for a remote server.  The server ordered to disconnect its peer
+    /// generates a WALLOPS message with <comment> included, so that other
+    /// users may be aware of the reason of this action.
+    ///
+    /// Numeric replies:
+    ///
+    ///    ERR_NOPRIVILEGES                ERR_NOSUCHSERVER
+    ///    ERR_NEEDMOREPARAMS
+    ///
+    /// Examples:
+    ///
+    ///    SQUIT tolsun.oulu.fi :Bad Link ?  ; Command to uplink of the server
+    ///                                    tolson.oulu.fi to terminate its
+    ///                                    connection with comment "Bad Link".
+    ///
+    ///    :Trillian SQUIT cm22.eng.umd.edu :Server out of control ; Command
+    ///                                    from Trillian from to disconnect
+    ///                                    "cm22.eng.umd.edu" from the net with
+    ///                                    comment "Server out of control".
+    /// ```
+    SQUIT(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.2.1 Join message
+    ///
+    /// Command: JOIN
+    /// Parameters: ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] )
+    ///             / "0"
+    ///
+    /// The JOIN command is used by a user to request to start listening to
+    /// the specific channel.  Servers MUST be able to parse arguments in the
+    /// form of a list of target, but SHOULD NOT use lists when sending JOIN
+    /// messages to clients.
+    ///
+    /// Once a user has joined a channel, he receives information about
+    /// all commands his server receives affecting the channel.  This
+    /// includes JOIN, MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.
+    /// This allows channel members to keep track of the other channel
+    /// members, as well as channel modes.
+    ///
+    /// If a JOIN is successful, the user receives a JOIN message as
+    /// confirmation and is then sent the channel's topic (using RPL_TOPIC) and
+    /// the list of users who are on the channel (using RPL_NAMREPLY), which
+    /// MUST include the user joining.
+    ///
+    /// Note that this message accepts a special argument ("0"), which is
+    /// a special request to leave all channels the user is currently a member
+    /// of.  The server will process this message as if the user had sent
+    /// a PART command (See Section 3.2.2) for each channel he is a member
+    /// of.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_BANNEDFROMCHAN
+    ///    ERR_INVITEONLYCHAN              ERR_BADCHANNELKEY
+    ///    ERR_CHANNELISFULL               ERR_BADCHANMASK
+    ///    ERR_NOSUCHCHANNEL               ERR_TOOMANYCHANNELS
+    ///    ERR_TOOMANYTARGETS              ERR_UNAVAILRESOURCE
+    ///    RPL_TOPIC
+    ///
+    /// Examples:
+    ///
+    ///    JOIN #foobar                    ; Command to join channel #foobar.
+    ///
+    ///    JOIN &foo fubar                 ; Command to join channel &foo using
+    ///                                    key "fubar".
+    ///
+    ///    JOIN #foo,&bar fubar            ; Command to join channel #foo using
+    ///                                    key "fubar" and &bar using no key.
+    ///
+    ///    JOIN #foo,#bar fubar,foobar     ; Command to join channel #foo using
+    ///                                    key "fubar", and channel #bar using
+    ///                                    key "foobar".
+    ///
+    ///    JOIN #foo,#bar                  ; Command to join channels #foo and
+    ///                                    #bar.
+    ///
+    ///    JOIN 0                          ; Leave all currently joined
+    ///                                    channels.
+    ///
+    ///    :WiZ!jto@tolsun.oulu.fi JOIN #Twilight_zone ; JOIN message from WiZ
+    ///                                    on channel #Twilight_zone
+    /// ```
+    JOIN(Vec<CS<'a>>, Vec<CS<'a>>),
+
+    /// ```text
+    /// 3.2.2 Part message
+    ///
+    /// Command: PART
+    /// Parameters: <channel> *( "," <channel> ) [ <Part Message> ]
+    ///
+    /// The PART command causes the user sending the message to be removed
+    /// from the list of active members for all given channels listed in the
+    /// parameter string.  If a "Part Message" is given, this will be sent
+    /// instead of the default message, the nickname.  This request is always
+    /// granted by the server.
+    ///
+    /// Servers MUST be able to parse arguments in the form of a list of
+    /// target, but SHOULD NOT use lists when sending PART messages to
+    /// clients.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+    ///    ERR_NOTONCHANNEL
+    ///
+    /// Examples:
+    ///
+    ///    PART #twilight_zone             ; Command to leave channel
+    ///                                    "#twilight_zone"
+    ///
+    ///    PART #oz-ops,&group5            ; Command to leave both channels
+    ///                                    "&group5" and "#oz-ops".
+    ///
+    ///    :WiZ!jto@tolsun.oulu.fi PART #playzone :I lost
+    ///                                    ; User WiZ leaving channel
+    ///                                    "#playzone" with the message "I
+    ///                                    lost".
+    /// ```
+    PART(Vec<CS<'a>>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.2.3 Channel mode message
+    ///
+    /// Command: MODE
+    /// Parameters: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
+    ///
+    /// The MODE command is provided so that users may query and change the
+    /// characteristics of a channel.  For more details on available modes
+    /// and their uses, see "Internet Relay Chat: Channel Management" [IRC-
+    /// CHAN].  Note that there is a maximum limit of three (3) changes per
+    /// command for modes that take a parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_KEYSET
+    ///    ERR_NOCHANMODES                 ERR_CHANOPRIVSNEEDED
+    ///    ERR_USERNOTINCHANNEL            ERR_UNKNOWNMODE
+    ///    RPL_CHANNELMODEIS
+    ///    RPL_BANLIST                     RPL_ENDOFBANLIST
+    ///    RPL_EXCEPTLIST                  RPL_ENDOFEXCEPTLIST
+    ///    RPL_INVITELIST                  RPL_ENDOFINVITELIST
+    ///    RPL_UNIQOPIS
+    ///
+    /// The following examples are given to help understanding the syntax of
+    /// the MODE command, but refer to modes defined in "Internet Relay Chat:
+    /// Channel Management" [IRC-CHAN].
+    ///
+    /// Examples:
+    ///
+    ///    MODE #Finnish +imI *!*@*.fi     ; Command to make #Finnish channel
+    ///                                    moderated and 'invite-only' with user
+    ///                                    with a hostname matching *.fi
+    ///                                    automatically invited.
+    ///
+    ///    MODE #Finnish +o Kilroy         ; Command to give 'chanop' privileges
+    ///                                    to Kilroy on channel #Finnish.
+    ///
+    ///    MODE #Finnish +v Wiz            ; Command to allow WiZ to speak on
+    ///                                    #Finnish.
+    ///
+    ///    MODE #Fins -s                   ; Command to remove 'secret' flag
+    ///                                    from channel #Fins.
+    ///
+    ///    MODE #42 +k oulu                ; Command to set the channel key to
+    ///                                    "oulu".
+    ///
+    ///    MODE #42 -k oulu                ; Command to remove the "oulu"
+    ///                                    channel key on channel "#42".
+    ///
+    ///    MODE #eu-opers +l 10            ; Command to set the limit for the
+    ///                                    number of users on channel
+    ///                                    "#eu-opers" to 10.
+    ///
+    ///    :WiZ!jto@tolsun.oulu.fi MODE #eu-opers -l
+    ///                                    ; User "WiZ" removing the limit for
+    ///                                    the number of users on channel "#eu-
+    ///                                    opers".
+    ///
+    ///    MODE &oulu +b                   ; Command to list ban masks set for
+    ///                                    the channel "&oulu".
+    ///
+    ///    MODE &oulu +b *!*@*             ; Command to prevent all users from
+    ///                                    joining.
+    ///
+    ///    MODE &oulu +b *!*@*.edu +e *!*@*.bu.edu
+    ///                                    ; Command to prevent any user from a
+    ///                                    hostname matching *.edu from joining,
+    ///                                    except if matching *.bu.edu
+    ///
+    ///    MODE #bu +be *!*@*.edu *!*@*.bu.edu
+    ///                                    ; Comment to prevent any user from a
+    ///                                    hostname matching *.edu from joining,
+    ///                                    except if matching *.bu.edu
+    ///
+    ///    MODE #meditation e              ; Command to list exception masks set
+    ///                                    for the channel "#meditation".
+    ///
+    ///    MODE #meditation I              ; Command to list invitations masks
+    ///                                    set for the channel "#meditation".
+    ///
+    ///    MODE !12345ircd O               ; Command to ask who the channel
+    ///                                    creator for "!12345ircd" is
+    /// ```
+    MODE(CS<'a>, Vec<(CS<'a>, CS<'a>)>),
+
+    /// ```text```
+    /// 3.2.4 Topic message
+    ///
+    /// Command: TOPIC
+    /// Parameters: <channel> [ <topic> ]
+    ///
+    /// The TOPIC command is used to change or view the topic of a channel.
+    /// The topic for channel <channel> is returned if there is no <topic>
+    /// given.  If the <topic> parameter is present, the topic for that
+    /// channel will be changed, if this action is allowed for the user
+    /// requesting it.  If the <topic> parameter is an empty string, the
+    /// topic for that channel will be removed.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL
+    ///    RPL_NOTOPIC                     RPL_TOPIC
+    ///    ERR_CHANOPRIVSNEEDED            ERR_NOCHANMODES
+    ///
+    /// Examples:
+    ///
+    ///    :WiZ!jto@tolsun.oulu.fi TOPIC #test :New topic ; User Wiz setting the
+    ///                                    topic.
+    ///
+    ///    TOPIC #test :another topic      ; Command to set the topic on #test
+    ///                                    to "another topic".
+    ///
+    ///    TOPIC #test :                   ; Command to clear the topic on
+    ///                                    #test.
+    ///
+    ///    TOPIC #test                     ; Command to check the topic for
+    ///                                    #test.
+    /// ```
+    TOPIC(CS<'a>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.2.5 Names message
+    ///
+    /// Command: NAMES
+    /// Parameters: [ <channel> *( "," <channel> ) [ <target> ] ]
+    ///
+    /// By using the NAMES command, a user can list all nicknames that are
+    /// visible to him. For more details on what is visible and what is not,
+    /// see "Internet Relay Chat: Channel Management" [IRC-CHAN].  The
+    /// <channel> parameter specifies which channel(s) to return information
+    /// about.  There is no error reply for bad channel names.
+    ///
+    /// If no <channel> parameter is given, a list of all channels and their
+    /// occupants is returned.  At the end of this list, a list of users who
+    /// are visible but either not on any channel or not on a visible channel
+    /// are listed as being on `channel' "*".
+    ///
+    /// If the <target> parameter is specified, the request is forwarded to
+    /// that server which will generate the reply.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numerics:
+    ///
+    ///    ERR_TOOMANYMATCHES              ERR_NOSUCHSERVER
+    ///    RPL_NAMREPLY                    RPL_ENDOFNAMES
+    ///
+    /// Examples:
+    ///
+    ///    NAMES #twilight_zone,#42        ; Command to list visible users on
+    ///                                    #twilight_zone and #42
+    ///
+    ///    NAMES                           ; Command to list all visible
+    ///                                    channels and users
+    /// ```
+    NAMES(Vec<CS<'a>>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.2.6 List message
+    ///
+    /// Command: LIST
+    /// Parameters: [ <channel> *( "," <channel> ) [ <target> ] ]
+    ///
+    /// The list command is used to list channels and their topics.  If the
+    /// <channel> parameter is used, only the status of that channel is
+    /// displayed.
+    ///
+    /// If the <target> parameter is specified, the request is forwarded to
+    /// that server which will generate the reply.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_TOOMANYMATCHES              ERR_NOSUCHSERVER
+    ///    RPL_LIST                        RPL_LISTEND
+    ///
+    /// Examples:
+    ///
+    ///    LIST                            ; Command to list all channels.
+    ///
+    ///    LIST #twilight_zone,#42         ; Command to list channels
+    ///                                    #twilight_zone and #42
+    /// ```
+    LIST(Vec<CS<'a>>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.2.7 Invite message
+    ///
+    /// Command: INVITE
+    /// Parameters: <nickname> <channel>
+    ///
+    /// The INVITE command is used to invite a user to a channel.  The
+    /// parameter <nickname> is the nickname of the person to be invited to
+    /// the target channel <channel>.  There is no requirement that the
+    /// channel the target user is being invited to must exist or be a valid
+    /// channel.  However, if the channel exists, only members of the channel
+    /// are allowed to invite other users.  When the channel has invite-only
+    /// flag set, only channel operators may issue INVITE command.
+    ///
+    /// Only the user inviting and the user being invited will receive
+    /// notification of the invitation.  Other channel members are not
+    /// notified.  (This is unlike the MODE changes, and is occasionally the
+    /// source of trouble for users.)
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_NOSUCHNICK
+    ///    ERR_NOTONCHANNEL                ERR_USERONCHANNEL
+    ///    ERR_CHANOPRIVSNEEDED
+    ///    RPL_INVITING                    RPL_AWAY
+    ///
+    /// Examples:
+    ///
+    ///    :Angel!wings@irc.org INVITE Wiz #Dust
+    ///                                    ; Message to WiZ when he has been
+    ///                                    invited by user Angel to channel
+    ///                                    #Dust
+    ///
+    ///    INVITE Wiz #Twilight_Zone       ; Command to invite WiZ to
+    ///                                    #Twilight_zone
+    /// ```
+    INVITE(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.2.8 Kick command
+    ///
+    /// Command: KICK
+    /// Parameters: <channel> *( "," <channel> ) <user> *( "," <user> )
+    ///             [<comment>]
+    ///
+    /// The KICK command can be used to request the forced removal of a user
+    /// from a channel.  It causes the <user> to PART from the <channel> by
+    /// force.  For the message to be syntactically correct, there MUST be
+    /// either one channel parameter and multiple user parameter, or as many
+    /// channel parameters as there are user parameters.  If a "comment" is
+    /// given, this will be sent instead of the default message, the nickname
+    /// of the user issuing the KICK.
+    ///
+    /// The server MUST NOT send KICK messages with multiple channels or
+    /// users to clients.  This is necessarily to maintain backward
+    /// compatibility with old client software.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+    ///    ERR_BADCHANMASK                 ERR_CHANOPRIVSNEEDED
+    ///    ERR_USERNOTINCHANNEL            ERR_NOTONCHANNEL
+    ///
+    /// Examples:
+    ///
+    ///    KICK &Melbourne Matthew         ; Command to kick Matthew from
+    ///                                    &Melbourne
+    ///
+    ///    KICK #Finnish John :Speaking English
+    ///                                    ; Command to kick John from #Finnish
+    ///                                    using "Speaking English" as the
+    ///                                    reason (comment).
+    ///
+    ///    :WiZ!jto@tolsun.oulu.fi KICK #Finnish John
+    ///                                    ; KICK message on channel #Finnish
+    ///                                    from WiZ to remove John from channel
+    /// ```
+    KICK(Vec<CS<'a>>, Vec<CS<'a>>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.3.1 Private messages
+    ///
+    /// Command: PRIVMSG
+    /// Parameters: <msgtarget> <text to be sent>
+    ///
+    /// PRIVMSG is used to send private messages between users, as well as to
+    /// send messages to channels.  <msgtarget> is usually the nickname of
+    /// the recipient of the message, or a channel name.
+    ///
+    /// The <msgtarget> parameter may also be a host mask (#<mask>) or server
+    /// mask ($<mask>).  In both cases the server will only send the PRIVMSG
+    /// to those who have a server or host matching the mask.  The mask MUST
+    /// have at least 1 (one) "." in it and no wildcards following the last
+    /// ".".  This requirement exists to prevent people sending messages to
+    /// "#*" or "$*", which would broadcast to all users.  Wildcards are the
+    /// '*' and '?'  characters.  This extension to the PRIVMSG command is
+    /// only available to operators.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NORECIPIENT                 ERR_NOTEXTTOSEND
+    ///    ERR_CANNOTSENDTOCHAN            ERR_NOTOPLEVEL
+    ///    ERR_WILDTOPLEVEL                ERR_TOOMANYTARGETS
+    ///    ERR_NOSUCHNICK
+    ///    RPL_AWAY
+    ///
+    /// Examples:
+    ///
+    ///    :Angel!wings@irc.org PRIVMSG Wiz :Are you receiving this message ?
+    ///                                    ; Message from Angel to Wiz.
+    ///
+    ///    PRIVMSG Angel :yes I'm receiving it !
+    ///                                    ; Command to send a message to Angel.
+    ///
+    ///    PRIVMSG jto@tolsun.oulu.fi :Hello !
+    ///                                    ; Command to send a message to a user
+    ///                                    on server tolsun.oulu.fi with
+    ///                                    username of "jto".
+    ///
+    ///    PRIVMSG kalt%millennium.stealth.net@irc.stealth.net :Are you a frog?
+    ///                                    ; Message to a user on server
+    ///                                    irc.stealth.net with username of
+    ///                                    "kalt", and connected from the host
+    ///                                    millennium.stealth.net.
+    ///
+    ///    PRIVMSG kalt%millennium.stealth.net :Do you like cheese?
+    ///                                    ; Message to a user on the local
+    ///                                    server with username of "kalt", and
+    ///                                    connected from the host
+    ///                                    millennium.stealth.net.
+    ///
+    ///    PRIVMSG Wiz!jto@tolsun.oulu.fi :Hello !
+    ///                                    ; Message to the user with nickname
+    ///                                    Wiz who is connected from the host
+    ///                                    tolsun.oulu.fi and has the username
+    ///                                    "jto".
+    ///
+    ///    PRIVMSG $*.fi :Server tolsun.oulu.fi rebooting.
+    ///                                    ; Message to everyone on a server
+    ///                                    which has a name matching *.fi.
+    ///
+    ///    PRIVMSG #*.edu :NSFNet is undergoing work, expect interruptions
+    ///                                    ; Message to all users who come from
+    ///                                    a host which has a name matching
+    ///                                    *.edu.
+    /// ```
+    PRIVMSG(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.3.2 Notice
+    ///
+    /// Command: NOTICE
+    /// Parameters: <msgtarget> <text>
+    ///
+    /// The NOTICE command is used similarly to PRIVMSG.  The difference
+    /// between NOTICE and PRIVMSG is that automatic replies MUST NEVER be
+    /// sent in response to a NOTICE message.  This rule applies to servers
+    /// too - they MUST NOT send any error reply back to the client on
+    /// receipt of a notice.  The object of this rule is to avoid loops
+    /// between clients automatically sending something in response to
+    /// something it received.
+    ///
+    /// This command is available to services as well as users.
+    ///
+    /// This is typically used by services, and automatons (clients with
+    /// either an AI or other interactive program controlling their actions).
+    ///
+    /// See PRIVMSG for more details on replies and examples.
+    /// ```
+    NOTICE(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.4.1 Motd message
+    ///
+    /// Command: MOTD
+    /// Parameters: [ <target> ]
+    ///
+    /// The MOTD command is used to get the "Message Of The Day" of the given
+    /// server, or current server if <target> is omitted.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///    RPL_MOTDSTART                   RPL_MOTD
+    ///    RPL_ENDOFMOTD                   ERR_NOMOTD
+    /// ```
+    MOTD(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.4.2 Lusers message
+    ///
+    /// Command: LUSERS
+    /// Parameters: [ <mask> [ <target> ] ]
+    ///
+    /// The LUSERS command is used to get statistics about the size of the
+    /// IRC network.  If no parameter is given, the reply will be about the
+    /// whole net.  If a <mask> is specified, then the reply will only
+    /// concern the part of the network formed by the servers matching the
+    /// mask.  Finally, if the <target> parameter is specified, the request
+    /// is forwarded to that server which will generate the reply.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    RPL_LUSERCLIENT                 RPL_LUSEROP
+    ///    RPL_LUSERUNKOWN                 RPL_LUSERCHANNELS
+    ///    RPL_LUSERME                     ERR_NOSUCHSERVER
+    /// ```
+    LUSERS(Option<(CS<'a>, Option<CS<'a>>)>),
+
+    /// ```text
+    /// 3.4.3 Version message
+    ///
+    /// Command: VERSION
+    /// Parameters: [ <target> ]
+    ///
+    /// The VERSION command is used to query the version of the server
+    /// program.  An optional parameter <target> is used to query the version
+    /// of the server program which a client is not directly connected to.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER                RPL_VERSION
+    ///
+    /// Examples:
+    ///
+    ///    VERSION tolsun.oulu.fi          ; Command to check the version of
+    ///                                    server "tolsun.oulu.fi".
+    /// ```
+    VERSION(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.4.4 Stats message
+    ///
+    /// Command: STATS
+    /// Parameters: [ <query> [ <target> ] ]
+    ///
+    /// The stats command is used to query statistics of certain server.  If
+    /// <query> parameter is omitted, only the end of stats reply is sent
+    /// back.
+    ///
+    /// A query may be given for any single letter which is only checked by
+    /// the destination server and is otherwise passed on by intermediate
+    /// servers, ignored and unaltered.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Except for the ones below, the list of valid queries is
+    /// implementation dependent.  The standard queries below SHOULD be
+    /// supported by the server:
+    ///
+    ///    l - returns a list of the server's connections, showing how
+    ///        long each connection has been established and the
+    ///        traffic over that connection in Kbytes and messages for
+    ///        each direction;
+    ///    m - returns the usage count for each of commands supported
+    ///        by the server; commands for which the usage count is
+    ///        zero MAY be omitted;
+    ///    o - returns a list of configured privileged users,
+    ///        operators;
+    ///    u - returns a string showing how long the server has been
+    ///        up.
+    ///
+    /// It is also RECOMMENDED that client and server access configuration be
+    /// published this way.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER
+    ///    RPL_STATSLINKINFO                RPL_STATSUPTIME
+    ///    RPL_STATSCOMMANDS                RPL_STATSOLINE
+    ///    RPL_ENDOFSTATS
+    ///
+    /// Examples:
+    ///
+    ///    STATS m      ; Command to check the command usage
+    ///                   for the server you are connected to
+    /// ```
+    STATS(Option<(CS<'a>, Option<CS<'a>>)>),
+
+    /// ```text
+    /// 3.4.5 Links message
+    ///
+    /// Command: LINKS
+    /// Parameters: [ [ <remote server> ] <server mask> ]
+    ///
+    /// With LINKS, a user can list all servernames, which are known by the
+    /// server answering the query.  The returned list of servers MUST match
+    /// the mask, or if no mask is given, the full list is returned.
+    ///
+    /// If <remote server> is given in addition to <server mask>, the LINKS
+    /// command is forwarded to the first server found that matches that name
+    /// (if any), and that server is then required to answer the query.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER
+    ///    RPL_LINKS                        RPL_ENDOFLINKS
+    ///
+    /// Examples:
+    ///
+    ///    LINKS *.au                      ; Command to list all servers which
+    ///                                    have a name that matches *.au;
+    ///
+    ///    LINKS *.edu *.bu.edu            ; Command to list servers matching
+    ///                                    *.bu.edu as seen by the first server
+    ///                                    matching *.edu.
+    /// ```
+    LINKS(Option<(Option<CS<'a>>, CS<'a>)>),
+
+    /// ```text
+    /// 3.4.6 Time message
+    ///
+    /// Command: TIME
+    /// Parameters: [ <target> ]
+    ///
+    /// The time command is used to query local time from the specified
+    /// server. If the <target> parameter is not given, the server receiving
+    /// the command must reply to the query.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER              RPL_TIME
+    ///
+    /// Examples:
+    ///    TIME tolsun.oulu.fi             ; check the time on the server
+    ///                                    "tolson.oulu.fi"
+    /// ```
+    TIME(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.4.7 Connect message
+    ///
+    /// Command: CONNECT
+    /// Parameters: <target server> <port> [ <remote server> ]
+    ///
+    /// The CONNECT command can be used to request a server to try to
+    /// establish a new connection to another server immediately.  CONNECT is
+    /// a privileged command and SHOULD be available only to IRC Operators.
+    /// If a <remote server> is given and its mask doesn't match name of the
+    /// parsing server, the CONNECT attempt is sent to the first match of
+    /// remote server. Otherwise the CONNECT attempt is made by the server
+    /// processing the request.
+    ///
+    /// The server receiving a remote CONNECT command SHOULD generate a
+    /// WALLOPS message describing the source and target of the request.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER              ERR_NOPRIVILEGES
+    ///    ERR_NEEDMOREPARAMS
+    ///
+    /// Examples:
+    ///
+    ///    CONNECT tolsun.oulu.fi 6667     ; Command to attempt to connect local
+    ///                                    server to tolsun.oulu.fi on port 6667
+    ///
+    CONNECT(CS<'a>, i16, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.4.8 Trace message
+    ///
+    /// Command: TRACE
+    /// Parameters: [ <target> ]
+    ///
+    /// TRACE command is used to find the route to specific server and
+    /// information about its peers.  Each server that processes this command
+    /// MUST report to the sender about it.  The replies from pass-through
+    /// links form a chain, which shows route to destination.  After sending
+    /// this reply back, the query MUST be sent to the next server until
+    /// given <target> server is reached.
+    ///
+    /// TRACE command is used to find the route to specific server.  Each
+    /// server that processes this message MUST tell the sender about it by
+    /// sending a reply indicating it is a pass-through link, forming a chain
+    /// of replies.  After sending this reply back, it MUST then send the
+    /// TRACE message to the next server until given server is reached.  If
+    /// the <target> parameter is omitted, it is RECOMMENDED that TRACE
+    /// command sends a message to the sender telling which servers the local
+    /// server has direct connection to.
+    ///
+    /// If the destination given by <target> is an actual server, the
+    /// destination server is REQUIRED to report all servers, services and
+    /// operators which are connected to it; if the command was issued by an
+    /// operator, the server MAY also report all users which are connected to
+    /// it.  If the destination given by <target> is a nickname, then only a
+    /// reply for that nickname is given.  If the <target> parameter is
+    /// omitted, it is RECOMMENDED that the TRACE command is parsed as
+    /// targeted to the processing server.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER
+    ///
+    /// If the TRACE message is destined for another server, all
+    /// intermediate servers must return a RPL_TRACELINK reply to indicate
+    /// that the TRACE passed through it and where it is going next.
+    ///
+    ///    RPL_TRACELINK
+    ///
+    /// A TRACE reply may be composed of any number of the following
+    /// numeric replies.
+    ///
+    ///    RPL_TRACECONNECTING           RPL_TRACEHANDSHAKE
+    ///    RPL_TRACEUNKNOWN              RPL_TRACEOPERATOR
+    ///    RPL_TRACEUSER                 RPL_TRACESERVER
+    ///    RPL_TRACESERVICE              RPL_TRACENEWTYPE
+    ///    RPL_TRACECLASS                RPL_TRACELOG
+    ///    RPL_TRACEEND
+    ///
+    /// Examples:
+    ///
+    ///    TRACE *.oulu.fi                 ; TRACE to a server matching
+    ///                                    *.oulu.fi
+    /// ```
+    TRACE(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.4.9 Admin command
+    ///
+    /// Command: ADMIN
+    /// Parameters: [ <target> ]
+    ///
+    /// The admin command is used to find information about the administrator
+    /// of the given server, or current server if <target> parameter is
+    /// omitted.  Each server MUST have the ability to forward ADMIN messages
+    /// to other servers.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER
+    ///    RPL_ADMINME                   RPL_ADMINLOC1
+    ///    RPL_ADMINLOC2                 RPL_ADMINEMAIL
+    ///
+    /// Examples:
+    ///
+    ///    ADMIN tolsun.oulu.fi            ; request an ADMIN reply from
+    ///                                    tolsun.oulu.fi
+    ///
+    ///    ADMIN syrk                      ; ADMIN request for the server to
+    ///                                    which the user syrk is connected
+    /// ```
+    ADMIN(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.4.10 Info command
+    ///
+    /// Command: INFO
+    /// Parameters: [ <target> ]
+    ///
+    /// The INFO command is REQUIRED to return information describing the
+    /// server: its version, when it was compiled, the patchlevel, when it
+    /// was started, and any other miscellaneous information which may be
+    /// considered to be relevant.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER
+    ///    RPL_INFO                      RPL_ENDOFINFO
+    ///
+    /// Examples:
+    ///
+    ///    INFO csd.bu.edu                 ; request an INFO reply from
+    ///                                    csd.bu.edu
+    ///
+    ///    INFO Angel                      ; request info from the server that
+    ///                                    Angel is connected to.
+    /// ```
+    INFO(Option<CS<'a>>),
+
+    /// ```text
+    /// 3.5.1 Servlist message
+    ///
+    /// Command: SERVLIST
+    /// Parameters: [ <mask> [ <type> ] ]
+    ///
+    /// The SERVLIST command is used to list services currently connected to
+    /// the network and visible to the user issuing the command.  The
+    /// optional parameters may be used to restrict the result of the query
+    /// (to matching services names, and services type).
+    ///
+    /// Numeric Replies:
+    ///
+    ///    RPL_SERVLIST                  RPL_SERVLISTEND
+    /// ```
+    SERVLIST(Option<(CS<'a>, Option<CS<'a>>)>),
+
+    /// ```text
+    /// 3.5.2 Squery
+    ///
+    /// Command: SQUERY
+    /// Parameters: <servicename> <text>
+    ///
+    /// The SQUERY command is used similarly to PRIVMSG.  The only difference
+    /// is that the recipient MUST be a service.  This is the only way for a
+    /// text message to be delivered to a service.
+    ///
+    /// See PRIVMSG for more details on replies and example.
+    ///
+    /// Examples:
+    ///
+    ///    SQUERY irchelp :HELP privmsg
+    ///                                    ; Message to the service with
+    ///                                    nickname irchelp.
+    ///
+    ///    SQUERY dict@irc.fr :fr2en blaireau
+    ///                                    ; Message to the service with name
+    ///                                    dict@irc.fr.
+    /// ```
+    SQUERY(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.6.1 Who query
+    ///
+    /// Command: WHO
+    /// Parameters: [ <mask> [ "o" ] ]
+    ///
+    /// The WHO command is used by a client to generate a query which returns
+    /// a list of information which 'matches' the <mask> parameter given by
+    /// the client.  In the absence of the <mask> parameter, all visible
+    /// (users who aren't invisible (user mode +i) and who don't have a
+    /// common channel with the requesting client) are listed.  The same
+    /// result can be achieved by using a <mask> of "0" or any wildcard which
+    /// will end up matching every visible user.
+    ///
+    /// The <mask> passed to WHO is matched against users' host, server, real
+    /// name and nickname if the channel <mask> cannot be found.
+    ///
+    /// If the "o" parameter is passed only operators are returned according
+    /// to the <mask> supplied.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER
+    ///    RPL_WHOREPLY                  RPL_ENDOFWHO
+    ///
+    /// Examples:
+    ///
+    ///    WHO *.fi                        ; Command to list all users who match
+    ///                                    against "*.fi".
+    ///
+    ///    WHO jto* o                      ; Command to list all users with a
+    ///                                    match against "jto*" if they are an
+    ///                                    operator.
+    /// ```
+    WHO(Option<CS<'a>>, bool),
+
+    /// ```text
+    /// 3.6.2 Whois query
+    ///
+    /// Command: WHOIS
+    /// Parameters: [ <target> ] <mask> *( "," <mask> )
+    ///
+    /// This command is used to query information about particular user.
+    /// The server will answer this command with several numeric messages
+    /// indicating different statuses of each user which matches the mask (if
+    /// you are entitled to see them).  If no wildcard is present in the
+    /// <mask>, any information about that nick which you are allowed to see
+    /// is presented.
+    ///
+    /// If the <target> parameter is specified, it sends the query to a
+    /// specific server.  It is useful if you want to know how long the user
+    /// in question has been idle as only local server (i.e., the server the
+    /// user is directly connected to) knows that information, while
+    /// everything else is globally known.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER              ERR_NONICKNAMEGIVEN
+    ///    RPL_WHOISUSER                 RPL_WHOISCHANNELS
+    ///    RPL_WHOISCHANNELS             RPL_WHOISSERVER
+    ///    RPL_AWAY                      RPL_WHOISOPERATOR
+    ///    RPL_WHOISIDLE                 ERR_NOSUCHNICK
+    ///    RPL_ENDOFWHOIS
+    ///
+    ///  Examples:
+    ///
+    ///    WHOIS wiz                       ; return available user information
+    ///                                    about nick WiZ
+    ///
+    ///    WHOIS eff.org trillian          ; ask server eff.org for user
+    ///                                    information  about trillian
+    /// ```
+    WHOIS(Option<CS<'a>>, Vec<CS<'a>>),
+
+    /// ```text
+    /// 3.6.3 Whowas
+    ///
+    /// Command: WHOWAS
+    /// Parameters: <nickname> *( "," <nickname> ) [ <count> [ <target> ] ]
+    ///
+    /// Whowas asks for information about a nickname which no longer exists.
+    /// This may either be due to a nickname change or the user leaving IRC.
+    /// In response to this query, the server searches through its nickname
+    /// history, looking for any nicks which are lexically the same (no wild
+    /// card matching here).  The history is searched backward, returning the
+    /// most recent entry first.  If there are multiple entries, up to
+    /// <count> replies will be returned (or all of them if no <count>
+    /// parameter is given).  If a non-positive number is passed as being
+    /// <count>, then a full search is done.
+    ///
+    /// Wildcards are allowed in the <target> parameter.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NONICKNAMEGIVEN           ERR_WASNOSUCHNICK
+    ///    RPL_WHOWASUSER                RPL_WHOISSERVER
+    ///    RPL_ENDOFWHOWAS
+    ///
+    /// Examples:
+    ///
+    ///    WHOWAS Wiz                      ; return all information in the nick
+    ///                                    history about nick "WiZ";
+    ///
+    ///    WHOWAS Mermaid 9                ; return at most, the 9 most recent
+    ///                                    entries in the nick history for
+    ///                                    "Mermaid";
+    ///
+    ///    WHOWAS Trillian 1 *.edu         ; return the most recent history for
+    ///                                    "Trillian" from the first server
+    ///                                    found to match "*.edu".
+    /// ```
+    WHOWAS(Vec<CS<'a>>, Option<(CS<'a>, Option<CS<'a>>)>),
+
+    /// ```text
+    /// 3.7.1 Kill message
+    ///
+    /// Command: KILL
+    /// Parameters: <nickname> <comment>
+    ///
+    /// The KILL command is used to cause a client-server connection to be
+    /// closed by the server which has the actual connection.  Servers
+    /// generate KILL messages on nickname collisions.  It MAY also be
+    /// available available to users who have the operator status.
+    ///
+    /// Clients which have automatic reconnect algorithms effectively make
+    /// this command useless since the disconnection is only brief.  It does
+    /// however break the flow of data and can be used to stop large amounts
+    /// of 'flooding' from abusive users or accidents.  Abusive users usually
+    /// don't care as they will reconnect promptly and resume their abusive
+    /// behaviour.  To prevent this command from being abused, any user may
+    /// elect to receive KILL messages generated for others to keep an 'eye'
+    /// on would be trouble spots.
+    ///
+    /// In an arena where nicknames are REQUIRED to be globally unique at all
+    /// times, KILL messages are sent whenever 'duplicates' are detected
+    /// (that is an attempt to register two users with the same nickname) in
+    /// the hope that both of them will disappear and only 1 reappear.
+    ///
+    /// When a client is removed as the result of a KILL message, the server
+    /// SHOULD add the nickname to the list of unavailable nicknames in an
+    /// attempt to avoid clients to reuse this name immediately which is
+    /// usually the pattern of abusive behaviour often leading to useless
+    /// "KILL loops".  See the "IRC Server Protocol" document [IRC-SERVER]
+    /// for more information on this procedure.
+    ///
+    /// The comment given MUST reflect the actual reason for the KILL.  For
+    /// server-generated KILLs it usually is made up of details concerning
+    /// the origins of the two conflicting nicknames.  For users it is left
+    /// up to them to provide an adequate reason to satisfy others who see
+    /// it.  To prevent/discourage fake KILLs from being generated to hide
+    /// the identify of the KILLer, the comment also shows a 'kill-path'
+    /// which is updated by each server it passes through, each prepending
+    /// its name to the path.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOPRIVILEGES              ERR_NEEDMOREPARAMS
+    ///    ERR_NOSUCHNICK                ERR_CANTKILLSERVER
+    ///
+    /// NOTE:
+    ///    It is RECOMMENDED that only Operators be allowed to kill other users
+    ///    with KILL command.  This command has been the subject of many
+    ///    controversies over the years, and along with the above
+    ///    recommendation, it is also widely recognized that not even operators
+    ///    should be allowed to kill users on remote servers.
+    /// ```
+    KILL(CS<'a>, CS<'a>),
+
+    /// ```text
+    /// 3.7.2 Ping message
+    ///
+    /// Command: PING
+    /// Parameters: <server1> [ <server2> ]
+    ///
+    /// The PING command is used to test the presence of an active client or
+    /// server at the other end of the connection.  Servers send a PING
+    /// message at regular intervals if no other activity detected coming
+    /// from a connection.  If a connection fails to respond to a PING
+    /// message within a set amount of time, that connection is closed.  A
+    /// PING message MAY be sent even if the connection is active.
+    ///
+    /// When a PING message is received, the appropriate PONG message MUST be
+    /// sent as reply to <server1> (server which sent the PING message out)
+    /// as soon as possible.  If the <server2> parameter is specified, it
+    /// represents the target of the ping, and the message gets forwarded
+    /// there.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOORIGIN                  ERR_NOSUCHSERVER
+    ///
+    /// Examples:
+    ///
+    ///    PING tolsun.oulu.fi             ; Command to send a PING message to
+    ///                                    server
+    ///
+    ///    PING WiZ tolsun.oulu.fi         ; Command from WiZ to send a PING
+    ///                                    message to server "tolsun.oulu.fi"
+    ///
+    ///    PING :irc.funet.fi              ; Ping message sent by server
+    ///                                    "irc.funet.fi"
+    /// ```
+    PING(CS<'a>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.7.3 Pong message
+    ///
+    /// Command: PONG
+    /// Parameters: <server> [ <server2> ]
+    ///
+    /// PONG message is a reply to ping message.  If parameter <server2> is
+    /// given, this message MUST be forwarded to given target.  The <server>
+    /// parameter is the name of the entity who has responded to PING message
+    /// and generated this message.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOORIGIN                  ERR_NOSUCHSERVER
+    ///
+    /// Example:
+    ///
+    ///    PONG csd.bu.edu tolsun.oulu.fi  ; PONG message from csd.bu.edu to
+    ///                                    tolsun.oulu.fi
+    /// ```
+    PONG(CS<'a>, Option<CS<'a>>),
+
+    /// ```text
+    /// 3.7.4 Error
+    ///
+    /// Command: ERROR
+    /// Parameters: <error message>
+    ///
+    /// The ERROR command is for use by servers when reporting a serious or
+    /// fatal error to its peers.  It may also be sent from one server to
+    /// another but MUST NOT be accepted from any normal unknown clients.
+    ///
+    /// Only an ERROR message SHOULD be used for reporting errors which occur
+    /// with a server-to-server link.  An ERROR message is sent to the server
+    /// at the other end (which reports it to appropriate local users and
+    /// logs) and to appropriate local users and logs.  It is not to be
+    /// passed onto any other servers by a server if it is received from a
+    /// server.
+    ///
+    /// The ERROR message is also used before terminating a client
+    /// connection.
+    ///
+    /// When a server sends a received ERROR message to its operators, the
+    /// message SHOULD be encapsulated inside a NOTICE message, indicating
+    /// that the client was not responsible for the error.
+    ///
+    /// Numerics:
+    ///
+    ///    None.
+    ///
+    /// Examples:
+    ///
+    ///    ERROR :Server *.fi already exists ; ERROR message to the other server
+    ///                                    which caused this error.
+    ///
+    ///    NOTICE WiZ :ERROR from csd.bu.edu -- Server *.fi already exists
+    ///                                    ; Same ERROR message as above but
+    ///                                    sent to user WiZ on the other server.
+    /// ```
+    ERROR(CS<'a>),
+
+    /// ```text
+    /// 4.1 Away
+    ///
+    /// Command: AWAY
+    /// Parameters: [ <text> ]
+    ///
+    /// With the AWAY command, clients can set an automatic reply string for
+    /// any PRIVMSG commands directed at them (not to a channel they are on).
+    /// The server sends an automatic reply to the client sending the PRIVMSG
+    /// command.  The only replying server is the one to which the sending
+    /// client is connected to.
+    ///
+    /// The AWAY command is used either with one parameter, to set an AWAY
+    /// message, or with no parameters, to remove the AWAY message.
+    ///
+    /// Because of its high cost (memory and bandwidth wise), the AWAY
+    /// message SHOULD only be used for client-server communication.  A
+    /// server MAY choose to silently ignore AWAY messages received from
+    /// other servers.  To update the away status of a client across servers,
+    /// the user mode 'a' SHOULD be used instead.  (See Section 3.1.5)
+    ///
+    /// Numeric Replies:
+    ///
+    ///    RPL_UNAWAY                    RPL_NOWAWAY
+    ///
+    /// Example:
+    ///
+    ///    AWAY :Gone to lunch.  Back in 5 ; Command to set away message to
+    ///                                    "Gone to lunch.  Back in 5".
+    /// ```
+    AWAY(Option<CS<'a>>),
+
+    /// ```text
+    /// 4.2 Rehash message
+    ///
+    /// Command: REHASH
+    /// Parameters: None
+    ///
+    /// The rehash command is an administrative command which can be used by
+    /// an operator to force the server to re-read and process its
+    /// configuration file.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    RPL_REHASHING                 ERR_NOPRIVILEGES
+    ///
+    /// Example:
+    ///
+    ///    REHASH                          ; message from user with operator
+    ///                                    status to server asking it to reread
+    ///                                    its configuration file.
+    /// ```
+    REHASH,
+
+    /// ```text
+    /// 4.3 Die message
+    ///
+    /// Command: DIE
+    /// Parameters: None
+    ///
+    /// An operator can use the DIE command to shutdown the server.  This
+    /// message is optional since it may be viewed as a risk to allow
+    /// arbitrary people to connect to a server as an operator and execute
+    /// this command.
+    ///
+    /// The DIE command MUST always be fully processed by the server to which
+    /// the sending client is connected and MUST NOT be passed onto other
+    /// connected servers.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOPRIVILEGES
+    ///
+    /// Example:
+    ///
+    ///    DIE                             ; no parameters required.
+    /// ```
+    DIE,
+
+    /// ```text
+    /// 4.4 Restart message
+    ///
+    /// Command: RESTART
+    /// Parameters: None
+    ///
+    /// An operator can use the restart command to force the server to
+    /// restart itself.  This message is optional since it may be viewed as a
+    /// risk to allow arbitrary people to connect to a server as an operator
+    /// and execute this command, causing (at least) a disruption to service.
+    ///
+    /// The RESTART command MUST always be fully processed by the server to
+    /// which the sending client is connected and MUST NOT be passed onto
+    /// other connected servers.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOPRIVILEGES
+    ///
+    /// Example:
+    ///
+    ///    RESTART                         ; no parameters required.
+    /// ```
+    RESTART,
+
+    /// ```text
+    /// 4.5 Summon message
+    ///
+    /// Command: SUMMON
+    /// Parameters: <user> [ <target> [ <channel> ] ]
+    ///
+    /// The SUMMON command can be used to give users who are on a host
+    /// running an IRC server a message asking them to please join IRC.  This
+    /// message is only sent if the target server (a) has SUMMON enabled, (b)
+    /// the user is logged in and (c) the server process can write to the
+    /// user's tty (or similar).
+    ///
+    /// If no <server> parameter is given it tries to summon <user> from the
+    /// server the client is connected to is assumed as the target.
+    ///
+    /// If summon is not enabled in a server, it MUST return the
+    /// ERR_SUMMONDISABLED numeric.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NORECIPIENT               ERR_FILEERROR
+    ///    ERR_NOLOGIN                   ERR_NOSUCHSERVER
+    ///    ERR_SUMMONDISABLED            RPL_SUMMONING
+    ///
+    /// Examples:
+    ///
+    ///    SUMMON jto                      ; summon user jto on the server's
+    ///                                    host
+    ///
+    ///    SUMMON jto tolsun.oulu.fi       ; summon user jto on the host which a
+    ///                                    server named "tolsun.oulu.fi" is
+    ///                                    running.
+    /// ```
+    SUMMON(CS<'a>, Option<(CS<'a>, Option<CS<'a>>)>),
+
+    /// ```text
+    /// 4.6 Users
+    ///
+    /// Command: USERS
+    /// Parameters: [ <target> ]
+    ///
+    /// The USERS command returns a list of users logged into the server in a
+    /// format similar to the UNIX commands who(1), rusers(1) and finger(1).
+    /// If disabled, the correct numeric MUST be returned to indicate this.
+    ///
+    /// Because of the security implications of such a command, it SHOULD be
+    /// disabled by default in server implementations.  Enabling it SHOULD
+    /// require recompiling the server or some equivalent change rather than
+    /// simply toggling an option and restarting the server.  The procedure
+    /// to enable this command SHOULD also include suitable large comments.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NOSUCHSERVER              ERR_FILEERROR
+    ///    RPL_USERSSTART                RPL_USERS
+    ///    RPL_NOUSERS                   RPL_ENDOFUSERS
+    ///    ERR_USERSDISABLED
+    ///
+    /// Disabled Reply:
+    ///
+    ///    ERR_USERSDISABLED
+    ///
+    /// Example:
+    ///
+    ///    USERS eff.org                   ; request a list of users logged in
+    ///                                    on server eff.org
+    /// ```
+    USERS(Option<CS<'a>>),
+
+    /// ```text
+    /// 4.7 Operwall message
+    ///
+    /// Command: WALLOPS
+    /// Parameters: <Text to be sent>
+    ///
+    /// The WALLOPS command is used to send a message to all currently
+    /// connected users who have set the 'w' user mode for themselves.  (See
+    /// Section 3.1.5 "User modes").
+    ///
+    /// After implementing WALLOPS as a user command it was found that it was
+    /// often and commonly abused as a means of sending a message to a lot of
+    /// people.  Due to this, it is RECOMMENDED that the implementation of
+    /// WALLOPS allows and recognizes only servers as the originators of
+    /// WALLOPS.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    ERR_NEEDMOREPARAMS
+    ///
+    /// Example:
+    ///
+    ///    :csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua ; WALLOPS
+    ///                                    message from csd.bu.edu announcing a
+    ///                                    CONNECT message it received from
+    ///                                    Joshua and acted upon.
+    /// ```
+    WALLOPS(CS<'a>),
+
+    /// ```text
+    /// 4.8 Userhost message
+    ///
+    /// Command: USERHOST
+    /// Parameters: <nickname> *( SPACE <nickname> )
+    ///
+    /// The USERHOST command takes a list of up to 5 nicknames, each
+    /// separated by a space character and returns a list of information
+    /// about each nickname that it found.  The returned list has each reply
+    /// separated by a space.
+    ///
+    /// Numeric Replies:
+    ///
+    ///    RPL_USERHOST                  ERR_NEEDMOREPARAMS
+    ///
+    /// Example:
+    ///
+    ///    USERHOST Wiz Michael syrk       ; USERHOST request for information on
+    ///                                    nicks "Wiz", "Michael", and "syrk"
+    ///
+    ///    :ircd.stealth.net 302 yournick :syrk=+syrk@millennium.stealth.net
+    ///                                    ; Reply for user syrk
+    /// ```
+    USERHOST(Vec<CS<'a>>),
+}
+
+/*impl<'a> Clone for Command<'a> {
+    fn clone(&self) -> Command<'a> {
+        use self::Command::*;
+        match self {
+            &PASS(ref pw) => PASS(pw.to_owned().clone()),
+            /*&NICK(ref nick) =>
+                Message::format(None, Borrowed("NICK"), vec![], Some(nick.clone()), MsgType::Irc),
+            &USER(ref user, ref mode, ref unused, ref realname) =>
+                Message::format(None, Borrowed("USER"),
+                    vec![user.clone(), mode.clone(), unused.clone()],
+                    Some(realname.clone()), MsgType::Irc),
+            &OPER(ref name, ref pw) =>
+                Message::format(None, Borrowed("OPER"),
+                    vec![name.clone(), pw.clone()], None, MsgType::Irc),
+            &UMODE(ref mode) =>
+                Message::format(None, Borrowed("MODE"), vec![], Some(mode.clone()), MsgType::Irc),
+            &SERVICE(ref nick, ref reserved, ref distribution, ref type_, ref reserved2, ref info) =>
+                Message::format(None, Borrowed("SERVICE"),
+                    vec![nick.clone(), reserved.clone(), distribution.clone(),
+                    type_.clone(), reserved2.clone()], Some(info.clone()), MsgType::Irc),
+            &QUIT(ref msg) =>
+                Message::format(None, Borrowed("QUIT"), vec![], msg.clone(), MsgType::Irc),
+            &SQUIT(ref server, ref comment) =>
+                Message::format(None, Borrowed("SQUIT"),
+                    vec![server.clone()], Some(comment.clone()), MsgType::Irc),
+            &JOIN(ref ch, ref pw) =>
+                Message::format(None, Borrowed("JOIN"),
+                    vec![Owned(ch.connect(",")), Owned(pw.connect(","))], None, MsgType::Irc),
+            &PART(ref ch, ref reason) =>
+                Message::format(None, Borrowed("PART"),
+                    vec![Owned(ch.connect(","))], reason.clone(), MsgType::Irc),
+            &MODE(ref channel, ref modes) =>
+                // Screw this, folding will have to do.
+                Message::format(None, Borrowed("MODE"),
+                    modes.iter().fold(vec![channel.clone()], |mut v, &(ref a, ref b)| {
+                        v.push(a.clone());
+                        v.push(b.clone());
+                        v
+                    }), None, MsgType::Irc),
+            &TOPIC(ref channel, ref topic) =>
+                Message::format(None, Borrowed("TOPIC"),
+                    vec![channel.clone()], topic.clone(), MsgType::Irc),
+            &NAMES(ref ch, ref target) =>
+                Message::format(None, Borrowed("NAMES"),
+                    vec![Owned(ch.connect(","))], target.clone(), MsgType::Irc),
+            &LIST(ref ch, ref target) =>
+                Message::format(None, Borrowed("LIST"),
+                    vec![Owned(ch.connect(","))], target.clone(), MsgType::Irc),
+            &INVITE(ref nick, ref channel) =>
+                Message::format(None, Borrowed("INVITE"),
+                    vec![nick.clone()], Some(channel.clone()), MsgType::Irc),
+            &KICK(ref ch, ref users, ref comment) =>
+                Message::format(None, Borrowed("KICK"),
+                    vec![Owned(ch.connect(",")), Owned(users.connect(","))],
+                    comment.clone(), MsgType::Irc),
+            &PRIVMSG(ref target, ref msg) =>
+                Message::format(None, Borrowed("PRIVMSG"),
+                    vec![target.clone()], Some(msg.clone()), MsgType::Irc),
+            &NOTICE(ref target, ref text) =>
+                Message::format(None, Borrowed("NOTICE"),
+                    vec![target.clone()], Some(text.clone()), MsgType::Irc),
+            &MOTD(ref target) =>
+                Message::format(None, Borrowed("MOTD"), vec![], target.clone(), MsgType::Irc),
+            &LUSERS(ref lu) =>
+                Message::format(None, Borrowed("LUSERS"),
+                    lu.as_ref().map(|&(ref mask, _)| vec![mask.clone()]).unwrap_or(vec![]),
+                    lu.as_ref().and_then(|&(_, ref target)| target.clone()), MsgType::Irc),
+            &VERSION(ref target) =>
+                Message::format(None, Borrowed("VERSION"), vec![], target.clone(), MsgType::Irc),
+            &STATS(ref st) =>
+                Message::format(None, Borrowed("STATS"),
+                    st.as_ref().map(|&(ref query, _)| vec![query.clone()]).unwrap_or(vec![]),
+                    st.as_ref().and_then(|&(_, ref target)| target.clone()), MsgType::Irc),
+            &LINKS(ref l) =>
+                Message::format(None, Borrowed("LINKS"),
+                    l.as_ref().map(|&(ref remote, ref mask)| if remote.is_some() {
+                    vec![remote.clone().unwrap(), mask.clone()] } else { vec![mask.clone()] }).unwrap_or(vec![]),
+                    None, MsgType::Irc),
+            &TIME(ref target) =>
+                Message::format(None, Borrowed("TIME"), vec![], target.clone(), MsgType::Irc),
+            &CONNECT(ref server, ref port, ref remote) =>
+                Message::format(None, Borrowed("CONNECT"),
+                    vec![server.clone(), Owned(format!("{}", port))], remote.clone(), MsgType::Irc),
+            &TRACE(ref target) =>
+                Message::format(None, Borrowed("TRACE"), vec![], target.clone(), MsgType::Irc),
+            &ADMIN(ref target) =>
+                Message::format(None, Borrowed("ADMIN"), vec![], target.clone(), MsgType::Irc),
+            &INFO(ref target) =>
+                Message::format(None, Borrowed("INFO"), vec![], target.clone(), MsgType::Irc),
+            &SERVLIST(ref sl) =>
+                Message::format(None, Borrowed("SERVLIST"),
+                    sl.as_ref().map(|&(ref mask, ref target)| target.as_ref()
+                    .map(|t| vec![mask.clone(), t.clone()])
+                    .unwrap_or_else(|| vec![mask.clone()]))
+                    .unwrap_or(vec![]), None, MsgType::Irc),
+            &SQUERY(ref name, ref text) =>
+                Message::format(None, Borrowed("SQUERY"),
+                    vec![name.clone()], Some(text.clone()), MsgType::Irc),
+            &WHO(ref mask, o) =>
+                Message::format(None, Borrowed("WHO"),
+                    match (mask, o) {
+                        (&Some(ref m), true) => vec![m.clone(), Borrowed("o")],
+                        (&Some(ref m), false) => vec![m.clone()],
+                        (&None, _) => vec![]
+                    }, None, MsgType::Irc),
+            &WHOIS(ref target,  ref masks) =>
+                Message::format(None, Borrowed("WHOIS"),
+                    target.as_ref().map(|t| vec![t.clone(), Owned(masks.connect(","))])
+                    .unwrap_or_else(|| vec![Owned(masks.connect(","))]), None, MsgType::Irc),
+            &WHOWAS(ref nick, ref count) =>
+                Message::format(None, Borrowed("WHOWAS"), match count {
+                        &Some((ref c, Some(ref t))) => vec![Owned(nick.connect(",")), c.clone(), t.clone()],
+                        &Some((ref c, None)) => vec![Owned(nick.connect(",")), c.clone()],
+                        &None => vec![Owned(nick.connect(","))]
+                    }, None, MsgType::Irc),
+            &PING(ref s1, ref s2) =>
+                Message::format(None, Borrowed("PING"), vec![s1.clone()], s2.clone(), MsgType::Irc),
+            &PONG(ref s1, ref s2) =>
+                Message::format(None, Borrowed("PONG"), vec![s1.clone()], s2.clone(), MsgType::Irc),
+             */           /*&Command::PING(ref server1, ref server2) => {
+                let mut c = Vec::new();
+                c.push(server1.clone());
+                if let &Some(ref s) = server2 { c.push(s.clone()) }
+                Message::format(None, "PING", c, None, MsgType::Irc)
+            },
+            &Command::PONG(ref server1, ref server2) => {
+                let mut c = Vec::new();
+                c.push(server1.clone());
+                if let &Some(ref s) = server2 { c.push(s.clone()) }
+                Message::format(None, "PONG", c, None, MsgType::Irc)
+            },*/
+            _ => unimplemented!()
+        }
+
+    }
+}*/
+
+impl<'a> Command<'a> {
+    pub fn from_message(msg: &'a Message) -> Option<Command<'a>> {
+        use self::Command::*;
+        match msg.command() {
+            "PASS" => msg.elements().last().map(|&m| m).map(Borrowed).map(PASS),
+            "NICK" => msg.suffix().or_else(|| msg.content().last().map(|&m| m))
+                .map(Borrowed).map(NICK),
+            "USER" => if let [user, mode, unused, realname, ..] = msg.elements().as_ref() {
+                    Some(USER(Borrowed(user), Borrowed(mode),
+                              Borrowed(unused), Borrowed(realname)))
+            } else { None },
+            "OPER" => if let [name, pw, ..] = msg.elements().as_ref() {
+                Some(OPER(Borrowed(name), Borrowed(pw)))
+            } else { None },
+            "PING" => {
+                let e = msg.elements();
+                e.first().map(|s1| PING(Borrowed(s1), e.get(1).map(|&m| m).map(Borrowed)))
+            },
+            "PONG" => {
+                let e = msg.elements();
+                e.first().map(|s1| PONG(Borrowed(s1), e.get(1).map(|&m| m).map(Borrowed)))
+            },
+            "JOIN" => if let [ch, pw, ..] = msg.elements().as_ref() {
+                Some(JOIN(ch.split(",").map(Borrowed).collect(),
+                          pw.split(",").map(Borrowed).collect()))
+            } else { None },
+            "PART" => if let [ch, reason..] = msg.elements().as_ref() {
+                Some(PART(ch.split(",").map(Borrowed).collect(),
+                          reason.first().map(|&m| m).map(Borrowed)))
+            } else { None },
+            "PRIVMSG" => if let [target, msg, ..] = msg.elements().as_ref() {
+                Some(PRIVMSG(Borrowed(target), Borrowed(msg)))
+            } else { None },
+            "NOTICE" => if let [target, msg, ..] = msg.elements().as_ref() {
+                Some(NOTICE(Borrowed(target), Borrowed(msg)))
+            } else { None },
+            _ => None
+        }
+    }
+
+    /// It started out pretty, but was quickly infested with `ref` and cloning.
+    /// I'm sorry, this one might not make it.
+    pub fn to_message(&'a self) -> Message {
+        use self::Command::*;
+        match self {
+            &PASS(ref pw) =>
+                Message::format(None, Borrowed("PASS"), vec![], Some(pw.clone()), MsgType::Irc),
+            &NICK(ref nick) =>
+                Message::format(None, Borrowed("NICK"), vec![], Some(nick.clone()), MsgType::Irc),
+            &USER(ref user, ref mode, ref unused, ref realname) =>
+                Message::format(None, Borrowed("USER"),
+                    vec![user.clone(), mode.clone(), unused.clone()],
+                    Some(realname.clone()), MsgType::Irc),
+            &OPER(ref name, ref pw) =>
+                Message::format(None, Borrowed("OPER"),
+                    vec![name.clone(), pw.clone()], None, MsgType::Irc),
+            &UMODE(ref mode) =>
+                Message::format(None, Borrowed("MODE"), vec![], Some(mode.clone()), MsgType::Irc),
+            &SERVICE(ref nick, ref reserved, ref distribution, ref type_, ref reserved2, ref info) =>
+                Message::format(None, Borrowed("SERVICE"),
+                    vec![nick.clone(), reserved.clone(), distribution.clone(),
+                    type_.clone(), reserved2.clone()], Some(info.clone()), MsgType::Irc),
+            &QUIT(ref msg) =>
+                Message::format(None, Borrowed("QUIT"), vec![], msg.clone(), MsgType::Irc),
+            &SQUIT(ref server, ref comment) =>
+                Message::format(None, Borrowed("SQUIT"),
+                    vec![server.clone()], Some(comment.clone()), MsgType::Irc),
+            &JOIN(ref ch, ref pw) =>
+                Message::format(None, Borrowed("JOIN"),
+                    vec![Owned(ch.connect(",")), Owned(pw.connect(","))], None, MsgType::Irc),
+            &PART(ref ch, ref reason) =>
+                Message::format(None, Borrowed("PART"),
+                    vec![Owned(ch.connect(","))], reason.clone(), MsgType::Irc),
+            &MODE(ref channel, ref modes) =>
+                // Screw this, folding will have to do.
+                Message::format(None, Borrowed("MODE"),
+                    modes.iter().fold(vec![channel.clone()], |mut v, &(ref a, ref b)| {
+                        v.push(a.clone());
+                        v.push(b.clone());
+                        v
+                    }), None, MsgType::Irc),
+            &TOPIC(ref channel, ref topic) =>
+                Message::format(None, Borrowed("TOPIC"),
+                    vec![channel.clone()], topic.clone(), MsgType::Irc),
+            &NAMES(ref ch, ref target) =>
+                Message::format(None, Borrowed("NAMES"),
+                    vec![Owned(ch.connect(","))], target.clone(), MsgType::Irc),
+            &LIST(ref ch, ref target) =>
+                Message::format(None, Borrowed("LIST"),
+                    vec![Owned(ch.connect(","))], target.clone(), MsgType::Irc),
+            &INVITE(ref nick, ref channel) =>
+                Message::format(None, Borrowed("INVITE"),
+                    vec![nick.clone()], Some(channel.clone()), MsgType::Irc),
+            &KICK(ref ch, ref users, ref comment) =>
+                Message::format(None, Borrowed("KICK"),
+                    vec![Owned(ch.connect(",")), Owned(users.connect(","))],
+                    comment.clone(), MsgType::Irc),
+            &PRIVMSG(ref target, ref msg) =>
+                Message::format(None, Borrowed("PRIVMSG"),
+                    vec![target.clone()], Some(msg.clone()), MsgType::Irc),
+            &NOTICE(ref target, ref text) =>
+                Message::format(None, Borrowed("NOTICE"),
+                    vec![target.clone()], Some(text.clone()), MsgType::Irc),
+            &MOTD(ref target) =>
+                Message::format(None, Borrowed("MOTD"), vec![], target.clone(), MsgType::Irc),
+            &LUSERS(ref lu) =>
+                Message::format(None, Borrowed("LUSERS"),
+                    lu.as_ref().map(|&(ref mask, _)| vec![mask.clone()]).unwrap_or(vec![]),
+                    lu.as_ref().and_then(|&(_, ref target)| target.clone()), MsgType::Irc),
+            &VERSION(ref target) =>
+                Message::format(None, Borrowed("VERSION"), vec![], target.clone(), MsgType::Irc),
+            &STATS(ref st) =>
+                Message::format(None, Borrowed("STATS"),
+                    st.as_ref().map(|&(ref query, _)| vec![query.clone()]).unwrap_or(vec![]),
+                    st.as_ref().and_then(|&(_, ref target)| target.clone()), MsgType::Irc),
+            &LINKS(ref l) =>
+                Message::format(None, Borrowed("LINKS"),
+                    l.as_ref().map(|&(ref remote, ref mask)| if remote.is_some() {
+                    vec![remote.clone().unwrap(), mask.clone()] } else { vec![mask.clone()] }).unwrap_or(vec![]),
+                    None, MsgType::Irc),
+            &TIME(ref target) =>
+                Message::format(None, Borrowed("TIME"), vec![], target.clone(), MsgType::Irc),
+            &CONNECT(ref server, ref port, ref remote) =>
+                Message::format(None, Borrowed("CONNECT"),
+                    vec![server.clone(), Owned(format!("{}", port))], remote.clone(), MsgType::Irc),
+            &TRACE(ref target) =>
+                Message::format(None, Borrowed("TRACE"), vec![], target.clone(), MsgType::Irc),
+            &ADMIN(ref target) =>
+                Message::format(None, Borrowed("ADMIN"), vec![], target.clone(), MsgType::Irc),
+            &INFO(ref target) =>
+                Message::format(None, Borrowed("INFO"), vec![], target.clone(), MsgType::Irc),
+            &SERVLIST(ref sl) =>
+                Message::format(None, Borrowed("SERVLIST"),
+                    sl.as_ref().map(|&(ref mask, ref target)| target.as_ref()
+                    .map(|t| vec![mask.clone(), t.clone()])
+                    .unwrap_or_else(|| vec![mask.clone()]))
+                    .unwrap_or(vec![]), None, MsgType::Irc),
+            &SQUERY(ref name, ref text) =>
+                Message::format(None, Borrowed("SQUERY"),
+                    vec![name.clone()], Some(text.clone()), MsgType::Irc),
+            &WHO(ref mask, o) =>
+                Message::format(None, Borrowed("WHO"),
+                    match (mask, o) {
+                        (&Some(ref m), true) => vec![m.clone(), Borrowed("o")],
+                        (&Some(ref m), false) => vec![m.clone()],
+                        (&None, _) => vec![]
+                    }, None, MsgType::Irc),
+            &WHOIS(ref target,  ref masks) =>
+                Message::format(None, Borrowed("WHOIS"),
+                    target.as_ref().map(|t| vec![t.clone(), Owned(masks.connect(","))])
+                    .unwrap_or_else(|| vec![Owned(masks.connect(","))]), None, MsgType::Irc),
+            &WHOWAS(ref nick, ref count) =>
+                Message::format(None, Borrowed("WHOWAS"), match count {
+                        &Some((ref c, Some(ref t))) => vec![Owned(nick.connect(",")), c.clone(), t.clone()],
+                        &Some((ref c, None)) => vec![Owned(nick.connect(",")), c.clone()],
+                        &None => vec![Owned(nick.connect(","))]
+                    }, None, MsgType::Irc),
+            &PING(ref s1, ref s2) =>
+                Message::format(None, Borrowed("PING"), vec![s1.clone()], s2.clone(), MsgType::Irc),
+            &PONG(ref s1, ref s2) =>
+                Message::format(None, Borrowed("PONG"), vec![s1.clone()], s2.clone(), MsgType::Irc),
+            _ => unimplemented!()
+        }
+    }
+
+    pub fn to_static(&self) -> Command<'static> {
+        fn s(c: &Cow<str>) -> Cow<'static, str> {
+            Cow::Owned(c.clone().into_owned())
+        }
+        fn so(c: &Option<Cow<str>>) -> Option<Cow<'static, str>> {
+            c.as_ref().map(s)
+        }
+        fn sv(c: &Vec<Cow<str>>) -> Vec<Cow<'static, str>> {
+            c.iter().map(s).collect()
+        }
+        use self::Command::*;
+        match self {
+            &PASS(ref pw) => PASS(s(pw)),
+            &NICK(ref nick) => NICK(s(nick)),
+            &USER(ref user, ref mode, ref unused, ref realname) =>
+                USER(s(user), s(mode), s(unused), s(realname)),
+            &OPER(ref name, ref pw) => OPER(s(name), s(pw)),
+            &UMODE(ref mode) => UMODE(s(mode)),
+            &SERVICE(ref nick, ref reserved, ref distribution, ref type_, ref reserved2, ref info) =>
+                SERVICE(s(nick), s(reserved), s(distribution), s(type_), s(reserved2), s(info)),
+            &QUIT(ref msg) => QUIT(so(msg)),
+            &SQUIT(ref server, ref comment) => SQUIT(s(server), s(comment)),
+            &JOIN(ref ch, ref pw) => JOIN(sv(ch), sv(pw)),
+            &PART(ref ch, ref reason) => PART(sv(ch), so(reason)),
+            &MODE(ref channel, ref modes) =>
+                MODE(s(channel), modes.iter().map(|&(ref a, ref b)| (s(a), s(b))).collect()),
+            &TOPIC(ref channel, ref topic) => TOPIC(s(channel), so(topic)),
+            &NAMES(ref ch, ref target) => NAMES(sv(ch), so(target)),
+            &LIST(ref ch, ref target) => LIST(sv(ch), so(target)),
+            &INVITE(ref nick, ref channel) => INVITE(s(nick), s(channel)),
+            &KICK(ref ch, ref users, ref comment) => KICK(sv(ch), sv(users), so(comment)),
+            &PRIVMSG(ref target, ref msg) => PRIVMSG(s(target), s(msg)),
+            &NOTICE(ref target, ref text) => NOTICE(s(target), s(text)),
+            &MOTD(ref target) => MOTD(so(target)),
+            &LUSERS(ref lu) => LUSERS(lu.as_ref().map(|&(ref a, ref b)| (s(a), so(b)))),
+            &VERSION(ref target) => VERSION(so(target)),
+            &STATS(ref st) => STATS(st.as_ref().map(|&(ref a, ref b)| (s(a), so(b)))),
+            &LINKS(ref l) => LINKS(l.as_ref().map(|&(ref a, ref b)| (so(a), s(b)))),
+            &TIME(ref target) => TIME(so(target)),
+            &CONNECT(ref server, port, ref remote) => CONNECT(s(server), port, so(remote)),
+            &TRACE(ref target) => TRACE(so(target)),
+            &ADMIN(ref target) => ADMIN(so(target)),
+            &INFO(ref target) => INFO(so(target)),
+            &SERVLIST(ref sl) => SERVLIST(sl.as_ref().map(|&(ref a, ref b)| (s(a), so(b)))),
+            &SQUERY(ref name, ref text) => SQUERY(s(name), s(text)),
+            &WHO(ref mask, o) => WHO(so(mask), o),
+            &WHOIS(ref target,  ref masks) => WHOIS(so(target), sv(masks)),
+            &WHOWAS(ref nick, ref count) =>
+                WHOWAS(sv(nick), count.as_ref().map(|&(ref a, ref b)| (s(a), so(b)))),
+            &PING(ref s1, ref s2) => PING(s(s1), so(s2)),
+            &PONG(ref s1, ref s2) => PONG(s(s1), so(s2)),
+            _ => unimplemented!()
+        }
+    }
+}
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/event.rs.html b/src/irsc/event.rs.html new file mode 100644 index 0000000..c2e6ef1 --- /dev/null +++ b/src/irsc/event.rs.html @@ -0,0 +1,145 @@ + + + + + + + + + + event.rs.html -- source + + + + + + + + + + + + + + + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+
+use std::borrow::{ Borrow, ToOwned };
+
+use command;
+use reply;
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Event<'a> {
+    Command(command::Command<'a>),
+    Reply(reply::Reply<'a>),
+    Connected,
+    Disconnected
+}
+
+impl<'a> Event<'a> {
+    pub fn to_static(&self) -> Event<'static> {
+        use Event::*;
+        match self {
+            &Command(ref c) => Command(c.to_static()),
+            &Reply(ref r) => Reply(r.to_static()),
+            &Connected => Connected,
+            &Disconnected => Disconnected
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/ident.rs.html b/src/irsc/ident.rs.html new file mode 100644 index 0000000..6fea734 --- /dev/null +++ b/src/irsc/ident.rs.html @@ -0,0 +1,147 @@ + + + + + + + + + + ident.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+use regex::Regex;
+use std::borrow::ToOwned;
+
+static PATTERN: Regex = regex!("(.*)!(.*)@(.*)");
+
+#[derive(Debug, Clone)]
+pub struct Ident {
+    pub nickname: String,
+    pub user: String,
+    pub host: String
+}
+
+impl Ident {
+    pub fn parse(s: &str) -> Option<Ident> {
+        let c = match PATTERN.captures(s) {
+            Some(c) => c,
+            None => return None
+        };
+        Some(Ident {
+            nickname: c.at(1).unwrap().to_owned(),
+            user: c.at(2).unwrap().to_owned(),
+            host: c.at(3).unwrap().to_owned()
+        })
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/lib.rs.html b/src/irsc/lib.rs.html new file mode 100644 index 0000000..9571fda --- /dev/null +++ b/src/irsc/lib.rs.html @@ -0,0 +1,221 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+#![feature(plugin, custom_derive, slice_patterns)]
+#![plugin(regex_macros)]
+#![cfg_attr(feature = "lints", plugin(clippy))]
+
+#![deny(warnings)]
+#![allow(unused_imports)]
+
+extern crate regex;
+#[macro_use]
+extern crate log;
+extern crate openssl;
+extern crate carboxyl;
+
+pub mod client;
+pub mod color;
+pub mod ident;
+pub mod callback;
+pub mod message;
+pub mod command;
+pub mod reply;
+pub mod event;
+
+use std::io;
+use std::result;
+use std::ops::{ Deref, DerefMut };
+
+use openssl::ssl::error::SslError;
+
+pub use ident::Ident;
+pub use message::{ Message, MsgType };
+pub use command::Command;
+pub use reply::Reply;
+pub use event::Event;
+pub use client::{ Client, OwnedClient, SharedClient };
+
+#[derive(Debug)]
+pub enum IrscError {
+    Io(io::Error),
+    AlreadyConnected,
+    NotConnected,
+    NotFound,
+    Ssl(SslError)
+}
+
+impl From<SslError> for IrscError {
+    fn from(e: SslError) -> IrscError { IrscError::Ssl(e) }
+}
+
+pub struct Result<T>(result::Result<T, IrscError>);
+
+impl<T> Deref for Result<T> {
+    type Target = result::Result<T, IrscError>;
+    fn deref(&self) -> &result::Result<T, IrscError> { &self.0 }
+}
+
+impl<T> DerefMut for Result<T> {
+    fn deref_mut(&mut self) -> &mut result::Result<T, IrscError> { &mut self.0 }
+}
+
+impl<T> Result<T> { fn inner(self) -> result::Result<T, IrscError> { self.0 } }
+
+pub const DEBUG: bool = cfg!(debug_assertions);
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/message.rs.html b/src/irsc/message.rs.html new file mode 100644 index 0000000..cdc6033 --- /dev/null +++ b/src/irsc/message.rs.html @@ -0,0 +1,567 @@ + + + + + + + + + + message.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+
+#![allow(non_camel_case_types)]
+
+use std::str::FromStr;
+use std::string::{ ToString };
+use std::borrow::{ ToOwned };
+use std::ops::{ Deref, Range };
+
+use ::IrscError;
+use ident::Ident;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum MsgType {
+    /// Plain old IRC messages, as defined in [rfc2812][rfc]
+    /// rfc: http://tools.ietf.org/html/rfc2812
+    Irc,
+    /// Ctcp messages, wrapped in \u{1}
+    Ctcp
+}
+
+/// Byte indices, be careful.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct Message {
+    pub source: String,
+    prefix: Option<Range<u16>>,
+    command: Range<u16>,
+    content: Vec<Range<u16>>,
+    suffix: Option<Range<u16>>,
+    pub msg_type: MsgType
+}
+
+impl Message {
+    pub fn new(source: String, prefix: Option<Range<u16>>, command: Range<u16>, content: Vec<Range<u16>>, suffix: Option<Range<u16>>, msg_type: MsgType) -> Message {
+        Message {
+            source: source,
+            prefix: prefix,
+            command: command,
+            content: content,
+            suffix: suffix,
+            msg_type: msg_type
+        }
+    }
+
+    #[allow(unused_assignments)]
+    pub fn format<T: Deref<Target=str>>(prefix: Option<T>, command: T, content: Vec<T>, suffix: Option<T>, msg_type: MsgType) -> Message {
+        let mut s = String::with_capacity(512);
+        let mut i = 0;
+
+        let mut i_prefix = None;
+        if let Some(ref p) = prefix {
+            i_prefix = Some((i + 1) as u16..(i + 2 + p.len()) as u16);
+            s.push(':');
+            s.push_str(p);
+            s.push(' ');
+            i += 2 + p.len();
+        }
+
+        let i_command = i as u16..(i + command.len()) as u16;
+        s.push_str(&*command);
+        s.push(' ');
+        i += 1 + command.len();
+
+        let mut i_content = Vec::new();
+        for part in content.iter() {
+            i_content.push(i as u16..(i + part.len()) as u16);
+            s.push_str(part);
+            s.push(' ');
+            i += 1 + part.len();
+        }
+
+        let mut i_suffix = None;
+        if let Some(ref p) = suffix {
+            s.push(':');
+            if let MsgType::Ctcp = msg_type { s.push('\u{1}'); i += 1; }
+            let n = i;
+            s.push_str(p);
+            if let MsgType::Ctcp = msg_type { s.push('\u{1}'); i += 1; }
+            i_suffix = Some(n as u16..(n + p.len()) as u16);
+            i += 1 + p.len();
+        }
+
+        s.push_str("\r\n");
+        i += 2;
+
+        Message::new(s, i_prefix, i_command, i_content, i_suffix, msg_type)
+    }
+
+    pub fn range(&self, r: &Range<u16>) -> &str {
+        &self.source[r.start as usize..r.end as usize]
+    }
+
+    pub fn prefix(&self) -> Option<&str> { self.prefix.as_ref().map(|r| self.range(r)) }
+    pub fn command(&self) -> &str { self.range(&self.command) }
+    pub fn content(&self) -> Vec<&str> { self.content.iter().map(|r| self.range(&r)).collect() }
+    pub fn suffix(&self) -> Option<&str> { self.suffix.as_ref().map(|r| self.range(r)) }
+    pub fn elements(&self) -> Vec<&str> { let mut s = self.content(); self.suffix().map(|f| s.push(f)); s }
+    pub fn ident(&self) -> Option<Ident> { self.prefix().and_then(Ident::parse) }
+}
+
+impl FromStr for Message {
+    type Err = IrscError;
+    fn from_str(i: &str) -> Result<Message, IrscError> {
+        let len = i.len();
+        // remember, bytes, not chars
+        let mut s = 0;
+
+        let prefix = if len >= 1 && i[s..].as_bytes()[0] == ':' as u8 {
+            i[s..].find(' ').map(|i| { let n = 1u16..(s + i) as u16; s += i + 1; n })
+        } else { None };
+
+        let command = i[s..].find(' ').map(|n| {
+            let p = s as u16..(s + n) as u16;
+            s += n;
+            p
+        });
+
+        let mut content = Vec::with_capacity(15);
+        let mut suffix = None;
+        while s < len - 3 {
+            if i[s..].as_bytes()[0] == ':' as u8 {
+                suffix = Some(s as u16 + 1 as u16..i.len() as u16);
+                break
+            }
+            i[s..].find(' ').map(|i| {
+                if i > 0 {
+                    content.push(s as u16..(s + i) as u16);
+                    s += i;
+                }
+            });
+            // if s.chars().next() == Some(' ') { s = &s[1..] };
+            s += 1;
+        }
+
+        let msg_type = if suffix.as_ref().map(|s| i[s.start as usize..].as_bytes()[0] == 1
+                                               && i[(s.end - 3) as usize..].as_bytes()[0] == 1)
+            == Some(true) { MsgType::Ctcp } else { MsgType::Irc };
+
+        command.map(move |c|
+            Ok(Message::new(
+                i.to_owned(),
+                prefix,
+                c,
+                content,
+                // strip \{1} if CTCP message
+                // strip \r\n for each line, relying on their existence
+                match msg_type {
+                    MsgType::Irc => suffix.map(|s| s.start..s.end - 1),
+                    MsgType::Ctcp => suffix.map(|s| s.start + 1..s.end - 2)
+                },
+                msg_type
+            ))
+        ).unwrap()
+
+    }
+}
+
+impl ToString for Message {
+    fn to_string(&self) -> String {
+        self.source.clone()
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub enum Mode {
+    Away,
+    Invisible,
+    Wallops,
+    Restricted,
+    Operator,
+    LocalOperator,
+    ServerNotices,
+    Custom(String)
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub enum SetMode {
+    Plus,
+    Minus
+}
+
+/// If you hoped it couldn't get any uglier... I'm sorry, it does.
+/// Why a giant match? API.
+///
+/// I tried structuring it as a bunch of structs that impl a `Command` trait,
+/// but the user would have to use Any and lots of cats. Also, extensibility isn't
+/// really a goal; the IRC protocol doesn't seem to evolve very fast.
+///
+/// Granted, I *could* have used a phf-map to map to functions to parse this, which
+/// - while more readable - shouldn't have resulted in performance gains.
+///
+/// Please don't cry.
+
+#[cfg(test)]
+mod test {
+    use std::borrow::{ ToOwned };
+    use message::{ Message, MsgType };
+
+    #[test]
+    fn parse_message1() {
+        let b = ":d PRIVMSG You :\u{1}ACTION sends you funny pictures of cats!\u{1}\r\n";
+        let b2 = Message::new(
+            b.to_owned(),
+            Some(1..2),
+            3..10,
+            vec![11..14],
+            Some(17..58),
+            MsgType::Ctcp
+        );
+
+        assert_eq!(b.parse::<Message>().unwrap(), b2.clone());
+        assert_eq!(b2.to_string(), b);
+    }
+
+    #[test]
+    fn parse_message2() {
+        let a = ":a.b.c NOTICE AUTH :*** Looking up your hostname...\r\n";
+        // I'm not even kidding...
+        let a2 = Message::new(
+            a.to_owned(),
+            Some(1..6),
+            7..13,
+            vec![14..18],
+            Some(20..52),
+            MsgType::Irc
+        );
+        assert_eq!(a.parse::<Message>().unwrap(), a2.clone());
+        assert_eq!(a2.to_string(), a);
+    }
+
+    #[test]
+    fn format_message() {
+        let a = Message::format(Some("a.b.c"), "NOTICE", vec!["AUTH"], Some("*** Looking up your hostname..."), MsgType::Irc);
+        let a2 = ":a.b.c NOTICE AUTH :*** Looking up your hostname...\r\n";
+        assert_eq!(a.to_string(), a2);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/irsc/reply.rs.html b/src/irsc/reply.rs.html new file mode 100644 index 0000000..5d77d38 --- /dev/null +++ b/src/irsc/reply.rs.html @@ -0,0 +1,3053 @@ + + + + + + + + + + reply.rs.html -- source + + + + + + + + + + + + + + + +
   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
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+
+use std::str::FromStr;
+use std::borrow::{ Cow, ToOwned };
+use std::borrow::Cow::*;
+
+use ::{ Result, IrscError };
+use ::message::{ MsgType, Message };
+
+pub type CS<'a> = Cow<'a, str>;
+
+#[allow(non_camel_case_types)]
+#[derive(Debug, Hash, Clone, PartialEq, Eq)]
+pub enum Reply<'a> {
+    /// 001    RPL_WELCOME
+    ///       "Welcome to the Internet Relay Network
+    ///        <nick>!<user>@<host>"
+    RPL_WELCOME(CS<'a>),
+
+    /// 002    RPL_YOURHOST
+    ///       "Your host is <servername>, running version <ver>"
+    RPL_YOURHOST(CS<'a>),
+
+    /// 003    RPL_CREATED
+    ///       "This server was created <date>"
+    RPL_CREATED(CS<'a>),
+
+    /// 004    RPL_MYINFO
+    ///       "<servername> <version> <available user modes>
+    ///        <available channel modes>"
+    ///
+    ///  - The server sends Replies 001 to 004 to a user upon
+    ///    successful registration.
+    ///
+    RPL_MYINFO(CS<'a>),
+
+    /// 005    RPL_BOUNCE
+    ///       "Try server <server name>, port <port number>"
+    ///
+    ///  - Sent by the server to a user to suggest an alternative
+    ///    server.  This is often used when the connection is
+    ///    refused because the server is already full.
+    ///
+    RPL_BOUNCE(CS<'a>),
+
+    /// 302    RPL_USERHOST
+    ///       ":*1<reply> *( " " <reply> )"
+    ///
+    ///  - Reply format used by USERHOST to list replies to
+    ///    the query list.  The reply string is composed as
+    ///    follows:
+    ///
+    ///    reply = nickname [ "*" ] "=" ( "+" / "-" ) hostname
+    ///
+    ///    The '*' indicates whether the client has registered
+    ///    as an Operator.  The '-' or '+' characters represent
+    ///    whether the client has set an AWAY message or not
+    ///    respectively.
+    ///
+    RPL_USERHOST(CS<'a>),
+
+    /// 303    RPL_ISON
+    ///       ":*1<nick> *( " " <nick> )"
+    ///
+    ///  - Reply format used by ISON to list replies to the
+    ///    query list.
+    ///
+    RPL_ISON(CS<'a>),
+
+    /// 301    RPL_AWAY
+    ///       "<nick> :<away message>"
+    RPL_AWAY(CS<'a>),
+
+    /// 305    RPL_UNAWAY
+    ///       ":You are no longer marked as being away"
+    RPL_UNAWAY(CS<'a>),
+
+    /// 306    RPL_NOWAWAY
+    ///       ":You have been marked as being away"
+    ///
+    ///  - These replies are used with the AWAY command (if
+    ///    allowed).  RPL_AWAY is sent to any client sending a
+    ///    PRIVMSG to a client which is away.  RPL_AWAY is only
+    ///    sent by the server to which the client is connected.
+    ///    Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
+    ///    client removes and sets an AWAY message.
+    ///
+    RPL_NOWAWAY(CS<'a>),
+
+    /// 311    RPL_WHOISUSER
+    ///       "<nick> <user> <host> * :<real name>"
+    RPL_WHOISUSER(CS<'a>),
+
+    /// 312    RPL_WHOISSERVER
+    ///       "<nick> <server> :<server info>"
+    RPL_WHOISSERVER(CS<'a>),
+
+    /// 313    RPL_WHOISOPERATOR
+    ///       "<nick> :is an IRC operator"
+    RPL_WHOISOPERATOR(CS<'a>),
+
+    /// 317    RPL_WHOISIDLE
+    ///       "<nick> <integer> :seconds idle"
+    RPL_WHOISIDLE(CS<'a>),
+
+    /// 318    RPL_ENDOFWHOIS
+    ///       "<nick> :End of WHOIS list"
+    RPL_ENDOFWHOIS(CS<'a>),
+
+    /// 319    RPL_WHOISCHANNELS
+    ///       "<nick> :*( ( "@" / "+" ) <channel> " " )"
+    ///
+    ///  - Replies 311 - 313, 317 - 319 are all replies
+    ///    generated in response to a WHOIS message.  Given that
+    ///    there are enough parameters present, the answering
+    ///    server MUST either formulate a reply out of the above
+    ///    numerics (if the query nick is found) or return an
+    ///    error reply.  The '*' in RPL_WHOISUSER is there as
+    ///    the literal character and not as a wild card.  For
+    ///    each reply set, only RPL_WHOISCHANNELS may appear
+    ///    more than once (for long lists of channel names).
+    ///    The '@' and '+' characters next to the channel name
+    ///    indicate whether a client is a channel operator or
+    ///    has been granted permission to speak on a moderated
+    ///    channel.  The RPL_ENDOFWHOIS reply is used to mark
+    ///    the end of processing a WHOIS message.
+    ///
+    RPL_WHOISCHANNELS(CS<'a>),
+
+    /// 314    RPL_WHOWASUSER
+    ///       "<nick> <user> <host> * :<real name>"
+    RPL_WHOWASUSER(CS<'a>),
+
+    /// 369    RPL_ENDOFWHOWAS
+    ///       "<nick> :End of WHOWAS"
+    ///
+    ///  - When replying to a WHOWAS message, a server MUST use
+    ///    the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
+    ///    ERR_WASNOSUCHNICK for each nickname in the presented
+    ///    list.  At the end of all reply batches, there MUST
+    ///    be RPL_ENDOFWHOWAS (even if there was only one reply
+    ///    and it was an error).
+    ///
+    RPL_ENDOFWHOWAS(CS<'a>),
+
+    /// 321    RPL_LISTSTART
+    ///       Obsolete. Not used.
+    ///
+    RPL_LISTSTART,
+
+    /// 322    RPL_LIST
+    ///       "<channel> <# visible> :<topic>"
+    RPL_LIST(CS<'a>),
+
+    /// 323    RPL_LISTEND
+    ///       ":End of LIST"
+    ///
+    ///  - Replies RPL_LIST, RPL_LISTEND mark the actual replies
+    ///    with data and end of the server's response to a LIST
+    ///    command.  If there are no channels available to return,
+    ///    only the end reply MUST be sent.
+    ///
+    RPL_LISTEND(CS<'a>),
+
+    /// 325    RPL_UNIQOPIS
+    ///       "<channel> <nickname>"
+    ///
+    RPL_UNIQOPIS(CS<'a>),
+
+    /// 324    RPL_CHANNELMODEIS
+    ///       "<channel> <mode> <mode params>"
+    ///
+    RPL_CHANNELMODEIS(CS<'a>),
+
+    /// 331    RPL_NOTOPIC
+    ///       "<channel> :No topic is set"
+    RPL_NOTOPIC(CS<'a>),
+
+    /// 332    RPL_TOPIC
+    ///       "<channel> :<topic>"
+    ///
+    ///  - When sending a TOPIC message to determine the
+    ///    channel topic, one of two replies is sent.  If
+    ///    the topic is set, RPL_TOPIC is sent back else
+    ///    RPL_NOTOPIC.
+    ///
+    RPL_TOPIC(CS<'a>),
+
+    /// 341    RPL_INVITING
+    ///       "<channel> <nick>"
+    ///
+    ///  - Returned by the server to indicate that the
+    ///    attempted INVITE message was successful and is
+    ///    being passed onto the end client.
+    ///
+    RPL_INVITING(CS<'a>),
+
+    /// 342    RPL_SUMMONING
+    ///       "<user> :Summoning user to IRC"
+    ///
+    ///  - Returned by a server answering a SUMMON message to
+    ///    indicate that it is summoning that user.
+    ///
+    RPL_SUMMONING(CS<'a>),
+
+    /// 346    RPL_INVITELIST
+    ///       "<channel> <invitemask>"
+    RPL_INVITELIST(CS<'a>),
+
+    /// 347    RPL_ENDOFINVITELIST
+    ///       "<channel> :End of channel invite list"
+    ///
+    ///  - When listing the 'invitations masks' for a given channel,
+    ///    a server is required to send the list back using the
+    ///    RPL_INVITELIST and RPL_ENDOFINVITELIST messages.  A
+    ///    separate RPL_INVITELIST is sent for each active mask.
+    ///    After the masks have been listed (or if none present) a
+    ///    RPL_ENDOFINVITELIST MUST be sent.
+    ///
+    RPL_ENDOFINVITELIST(CS<'a>),
+
+    /// 348    RPL_EXCEPTLIST
+    ///       "<channel> <exceptionmask>"
+    RPL_EXCEPTLIST(CS<'a>),
+
+    /// 349    RPL_ENDOFEXCEPTLIST
+    ///       "<channel> :End of channel exception list"
+    ///
+    ///  - When listing the 'exception masks' for a given channel,
+    ///    a server is required to send the list back using the
+    ///    RPL_EXCEPTLIST and RPL_ENDOFEXCEPTLIST messages.  A
+    ///    separate RPL_EXCEPTLIST is sent for each active mask.
+    ///    After the masks have been listed (or if none present)
+    ///    a RPL_ENDOFEXCEPTLIST MUST be sent.
+    ///
+    RPL_ENDOFEXCEPTLIST(CS<'a>),
+
+    /// 351    RPL_VERSION
+    ///       "<version>.<debuglevel> <server> :<comments>"
+    ///
+    ///  - Reply by the server showing its version details.
+    ///    The <version> is the version of the software being
+    ///    used (including any patchlevel revisions) and the
+    ///    <debuglevel> is used to indicate if the server is
+    ///    running in "debug mode".
+    ///
+    ///    The "comments" field may contain any comments about
+    ///    the version or further version details.
+    ///
+    RPL_VERSION(CS<'a>),
+
+    /// 352    RPL_WHOREPLY
+    ///       "<channel> <user> <host> <server> <nick>
+    ///       ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
+    ///       :<hopcount> <real name>"
+    ///
+    RPL_WHOREPLY(CS<'a>),
+
+    /// 315    RPL_ENDOFWHO
+    ///       "<name> :End of WHO list"
+    ///
+    ///  - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
+    ///    to answer a WHO message.  The RPL_WHOREPLY is only
+    ///    sent if there is an appropriate match to the WHO
+    ///    query.  If there is a list of parameters supplied
+    ///    with a WHO message, a RPL_ENDOFWHO MUST be sent
+    ///    after processing each list item with <name> being
+    ///    the item.
+    ///
+    RPL_ENDOFWHO(CS<'a>),
+
+    /// 353    RPL_NAMREPLY
+    ///       "( "=" / "*" / "@" ) <channel>
+    ///        :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
+    ///  - "@" is used for secret channels, "*" for private
+    ///    channels, and "=" for others (public channels).
+    ///
+    RPL_NAMREPLY(CS<'a>),
+
+    /// 366    RPL_ENDOFNAMES
+    ///       "<channel> :End of NAMES list"
+    ///
+    ///  - To reply to a NAMES message, a reply pair consisting
+    ///    of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
+    ///    server back to the client.  If there is no channel
+    ///    found as in the query, then only RPL_ENDOFNAMES is
+    ///    returned.  The exception to this is when a NAMES
+    ///    message is sent with no parameters and all visible
+    ///    channels and contents are sent back in a series of
+    ///    RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
+    ///    the end.
+    ///
+    RPL_ENDOFNAMES(CS<'a>),
+
+    /// 364    RPL_LINKS
+    ///       "<mask> <server> :<hopcount> <server info>"
+    RPL_LINKS(CS<'a>),
+
+    /// 365    RPL_ENDOFLINKS
+    ///       "<mask> :End of LINKS list"
+    ///
+    ///  - In replying to the LINKS message, a server MUST send
+    ///    replies back using the RPL_LINKS numeric and mark the
+    ///    end of the list using an RPL_ENDOFLINKS reply.
+    ///
+    RPL_ENDOFLINKS(CS<'a>),
+
+    /// 367    RPL_BANLIST
+    ///       "<channel> <banmask>"
+    RPL_BANLIST(CS<'a>),
+
+    /// 368    RPL_ENDOFBANLIST
+    ///       "<channel> :End of channel ban list"
+    ///
+    ///  - When listing the active 'bans' for a given channel,
+    ///    a server is required to send the list back using the
+    ///    RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate
+    ///    RPL_BANLIST is sent for each active banmask.  After the
+    ///    banmasks have been listed (or if none present) a
+    ///    RPL_ENDOFBANLIST MUST be sent.
+    ///
+    RPL_ENDOFBANLIST(CS<'a>),
+
+    /// 371    RPL_INFO
+    ///       ":<string>"
+    RPL_INFO(CS<'a>),
+
+    /// 374    RPL_ENDOFINFO
+    ///       ":End of INFO list"
+    ///
+    ///  - A server responding to an INFO message is required to
+    ///    send all its 'info' in a series of RPL_INFO messages
+    ///    with a RPL_ENDOFINFO reply to indicate the end of the
+    ///    replies.
+    ///
+    RPL_ENDOFINFO(CS<'a>),
+
+    /// 375    RPL_MOTDSTART
+    ///       ":- <server> Message of the day - "
+    RPL_MOTDSTART(CS<'a>),
+
+    /// 372    RPL_MOTD
+    ///       ":- <text>"
+    RPL_MOTD(CS<'a>),
+
+    /// 376    RPL_ENDOFMOTD
+    ///       ":End of MOTD command"
+    ///
+    ///  - When responding to the MOTD message and the MOTD file
+    ///    is found, the file is displayed line by line, with
+    ///    each line no longer than 80 characters, using
+    ///    RPL_MOTD format replies.  These MUST be surrounded
+    ///    by a RPL_MOTDSTART (before the RPL_MOTDs) and an
+    ///    RPL_ENDOFMOTD (after).
+    ///
+    RPL_ENDOFMOTD(CS<'a>),
+
+    /// 381    RPL_YOUREOPER
+    ///       ":You are now an IRC operator"
+    ///
+    ///  - RPL_YOUREOPER is sent back to a client which has
+    ///    just successfully issued an OPER message and gained
+    ///    operator status.
+    ///
+    RPL_YOUREOPER(CS<'a>),
+
+    /// 382    RPL_REHASHING
+    ///       "<config file> :Rehashing"
+    ///
+    ///  - If the REHASH option is used and an operator sends
+    ///    a REHASH message, an RPL_REHASHING is sent back to
+    ///    the operator.
+    ///
+    RPL_REHASHING(CS<'a>),
+
+    /// 383    RPL_YOURESERVICE
+    ///       "You are service <servicename>"
+    ///
+    ///  - Sent by the server to a service upon successful
+    ///    registration.
+    ///
+    RPL_YOURESERVICE(CS<'a>),
+
+    /// 391    RPL_TIME
+    ///       "<server> :<string showing server's local time>"
+    ///
+    ///  - When replying to the TIME message, a server MUST send
+    ///    the reply using the RPL_TIME format above.  The string
+    ///    showing the time need only contain the correct day and
+    ///    time there.  There is no further requirement for the
+    ///    time string.
+    ///
+    RPL_TIME(CS<'a>),
+
+    /// 392    RPL_USERSSTART
+    ///       ":UserID   Terminal  Host"
+    RPL_USERSSTART(CS<'a>),
+
+    /// 393    RPL_USERS
+    ///       ":<username> <ttyline> <hostname>"
+    RPL_USERS(CS<'a>),
+
+    /// 394    RPL_ENDOFUSERS
+    ///       ":End of users"
+    RPL_ENDOFUSERS(CS<'a>),
+
+    /// 395    RPL_NOUSERS
+    ///       ":Nobody logged in"
+    ///
+    ///  - If the USERS message is handled by a server, the
+    ///    replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
+    ///    RPL_NOUSERS are used.  RPL_USERSSTART MUST be sent
+    ///    first, following by either a sequence of RPL_USERS
+    ///    or a single RPL_NOUSER.  Following this is
+    ///    RPL_ENDOFUSERS.
+    ///
+    RPL_NOUSERS(CS<'a>),
+
+    /// 200    RPL_TRACELINK
+    ///       "Link <version & debug level> <destination>
+    ///        <next server> V<protocol version>
+    ///        <link uptime in seconds> <backstream sendq>
+    ///        <upstream sendq>"
+    RPL_TRACELINK(CS<'a>),
+
+    /// 201    RPL_TRACECONNECTING
+    ///       "Try. <class> <server>"
+    RPL_TRACECONNECTING(CS<'a>),
+
+    /// 202    RPL_TRACEHANDSHAKE
+    ///       "H.S. <class> <server>"
+    RPL_TRACEHANDSHAKE(CS<'a>),
+
+    /// 203    RPL_TRACEUNKNOWN
+    ///       "???? <class> [<client IP address in dot form>]"
+    RPL_TRACEUNKNOWN(CS<'a>),
+
+    /// 204    RPL_TRACEOPERATOR
+    ///       "Oper <class> <nick>"
+    RPL_TRACEOPERATOR(CS<'a>),
+
+    /// 205    RPL_TRACEUSER
+    ///       "User <class> <nick>"
+    RPL_TRACEUSER(CS<'a>),
+
+    /// 206    RPL_TRACESERVER
+    ///       "Serv <class> <int>S <int>C <server>
+    ///        <nick!user|*!*>@<host|server> V<protocol version>"
+    RPL_TRACESERVER(CS<'a>),
+
+    /// 207    RPL_TRACESERVICE
+    ///       "Service <class> <name> <type> <active type>"
+    RPL_TRACESERVICE(CS<'a>),
+
+    /// 208    RPL_TRACENEWTYPE
+    ///       "<newtype> 0 <client name>"
+    RPL_TRACENEWTYPE(CS<'a>),
+
+    /// 209    RPL_TRACECLASS
+    ///       "Class <class> <count>"
+    RPL_TRACECLASS(CS<'a>),
+
+    /// 210    RPL_TRACERECONNECT
+    ///       Unused.
+    RPL_TRACERECONNECT(CS<'a>),
+
+    /// 261    RPL_TRACELOG
+    ///       "File <logfile> <debug level>"
+    RPL_TRACELOG(CS<'a>),
+
+    /// 262    RPL_TRACEEND
+    ///       "<server name> <version & debug level> :End of TRACE"
+    ///
+    ///  - The RPL_TRACE* are all returned by the server in
+    ///    response to the TRACE message.  How many are
+    ///    returned is dependent on the TRACE message and
+    ///    whether it was sent by an operator or not.  There
+    ///    is no predefined order for which occurs first.
+    ///    Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
+    ///    RPL_TRACEHANDSHAKE are all used for connections
+    ///    which have not been fully established and are either
+    ///    unknown, still attempting to connect or in the
+    ///    process of completing the 'server handshake'.
+    ///    RPL_TRACELINK is sent by any server which handles
+    ///    a TRACE message and has to pass it on to another
+    ///    server.  The list of RPL_TRACELINKs sent in
+    ///    response to a TRACE command traversing the IRC
+    ///    network should reflect the actual connectivity of
+    ///    the servers themselves along that path.
+    ///
+    ///    RPL_TRACENEWTYPE is to be used for any connection
+    ///    which does not fit in the other categories but is
+    ///    being displayed anyway.
+    ///    RPL_TRACEEND is sent to indicate the end of the list.
+    ///
+    RPL_TRACEEND(CS<'a>),
+
+    /// 211    RPL_STATSLINKINFO
+    ///       "<linkname> <sendq> <sent messages>
+    ///        <sent Kbytes> <received messages>
+    ///        <received Kbytes> <time open>"
+    ///
+    ///  - reports statistics on a connection.  <linkname>
+    ///    identifies the particular connection, <sendq> is
+    ///    the amount of data that is queued and waiting to be
+    ///    sent <sent messages> the number of messages sent,
+    ///    and <sent Kbytes> the amount of data sent, in
+    ///    Kbytes. <received messages> and <received Kbytes>
+    ///    are the equivalent of <sent messages> and <sent
+    ///    Kbytes> for received data, respectively.  <time
+    ///    open> indicates how long ago the connection was
+    ///    opened, in seconds.
+    ///
+    RPL_STATSLINKINFO(CS<'a>),
+
+    /// 212    RPL_STATSCOMMANDS
+    ///       "<command> <count> <byte count> <remote count>"
+    ///
+    ///  - reports statistics on commands usage.
+    ///
+    RPL_STATSCOMMANDS(CS<'a>),
+
+    /// 219    RPL_ENDOFSTATS
+    ///       "<stats letter> :End of STATS report"
+    ///
+    RPL_ENDOFSTATS(CS<'a>),
+
+    /// 242    RPL_STATSUPTIME
+    ///       ":Server Up %d days %d:%02d:%02d"
+    ///
+    ///  - reports the server uptime.
+    ///
+    RPL_STATSUPTIME(CS<'a>),
+
+    /// 243    RPL_STATSOLINE
+    ///       "O <hostmask> * <name>"
+    ///
+    ///  - reports the allowed hosts from where user may become IRC
+    ///    operators.
+    ///
+    RPL_STATSOLINE(CS<'a>),
+
+    /// 221    RPL_UMODEIS
+    ///       "<user mode string>"
+    ///
+    ///  - To answer a query about a client's own mode,
+    ///    RPL_UMODEIS is sent back.
+    ///
+    RPL_UMODEIS(CS<'a>),
+
+    /// 234    RPL_SERVLIST
+    ///       "<name> <server> <mask> <type> <hopcount> <info>"
+    ///
+    RPL_SERVLIST(CS<'a>),
+
+    /// 235    RPL_SERVLISTEND
+    ///       "<mask> <type> :End of service listing"
+    ///
+    ///  - When listing services in reply to a SERVLIST message,
+    ///    a server is required to send the list back using the
+    ///    RPL_SERVLIST and RPL_SERVLISTEND messages.  A separate
+    ///    RPL_SERVLIST is sent for each service.  After the
+    ///    services have been listed (or if none present) a
+    ///    RPL_SERVLISTEND MUST be sent.
+    ///
+    RPL_SERVLISTEND(CS<'a>),
+
+    /// 251    RPL_LUSERCLIENT
+    ///       ":There are <integer> users and <integer>
+    ///        services on <integer> servers"
+    RPL_LUSERCLIENT(CS<'a>),
+
+    /// 252    RPL_LUSEROP
+    ///       "<integer> :operator(s) online"
+    RPL_LUSEROP(CS<'a>),
+
+    /// 253    RPL_LUSERUNKNOWN
+    ///       "<integer> :unknown connection(s)"
+    RPL_LUSERUNKNOWN(CS<'a>),
+
+    /// 254    RPL_LUSERCHANNELS
+    ///       "<integer> :channels formed"
+    RPL_LUSERCHANNELS(CS<'a>),
+
+    /// 255    RPL_LUSERME
+    ///       ":I have <integer> clients and <integer>
+    ///         servers"
+    ///
+    ///  - In processing an LUSERS message, the server
+    ///    sends a set of replies from RPL_LUSERCLIENT,
+    ///    RPL_LUSEROP, RPL_USERUNKNOWN,
+    ///    RPL_LUSERCHANNELS and RPL_LUSERME.  When
+    ///    replying, a server MUST send back
+    ///    RPL_LUSERCLIENT and RPL_LUSERME.  The other
+    ///    replies are only sent back if a non-zero count
+    ///    is found for them.
+    ///
+    RPL_LUSERME(CS<'a>),
+
+    /// 256    RPL_ADMINME
+    ///       "<server> :Administrative info"
+    RPL_ADMINME(CS<'a>),
+
+    /// 257    RPL_ADMINLOC1
+    ///       ":<admin info>"
+    RPL_ADMINLOC1(CS<'a>),
+
+    /// 258    RPL_ADMINLOC2
+    ///       ":<admin info>"
+    RPL_ADMINLOC2(CS<'a>),
+
+    /// 259    RPL_ADMINEMAIL
+    ///       ":<admin info>"
+    ///
+    ///  - When replying to an ADMIN message, a server
+    ///    is expected to use replies RPL_ADMINME
+    ///    through to RPL_ADMINEMAIL and provide a text
+    ///    message with each.  For RPL_ADMINLOC1 a
+    ///    description of what city, state and country
+    ///    the server is in is expected, followed by
+    ///    details of the institution (RPL_ADMINLOC2)
+    ///
+    ///    and finally the administrative contact for the
+    ///    server (an email address here is REQUIRED)
+    ///    in RPL_ADMINEMAIL.
+    ///
+    RPL_ADMINEMAIL(CS<'a>),
+
+    /// 263    RPL_TRYAGAIN
+    ///       "<command> :Please wait a while and try again."
+    ///
+    ///  - When a server drops a command without processing it,
+    ///    it MUST use the reply RPL_TRYAGAIN to inform the
+    ///    originating client.
+    ///
+    RPL_TRYAGAIN(CS<'a>),
+
+    /// 401    ERR_NOSUCHNICK
+    ///       "<nickname> :No such nick/channel"
+    ///
+    ///   - Used to indicate the nickname parameter supplied to a
+    ///     command is currently unused.
+    ///
+    ERR_NOSUCHNICK(CS<'a>),
+
+    /// 402    ERR_NOSUCHSERVER
+    ///       "<server name> :No such server"
+    ///
+    ///  - Used to indicate the server name given currently
+    ///    does not exist.
+    ///
+    ERR_NOSUCHSERVER(CS<'a>),
+
+    /// 403    ERR_NOSUCHCHANNEL
+    ///       "<channel name> :No such channel"
+    ///
+    ///  - Used to indicate the given channel name is invalid.
+    ///
+    ERR_NOSUCHCHANNEL(CS<'a>),
+
+    /// 404    ERR_CANNOTSENDTOCHAN
+    ///       "<channel name> :Cannot send to channel"
+    ///
+    ///  - Sent to a user who is either (a) not on a channel
+    ///    which is mode +n or (b) not a chanop (or mode +v) on
+    ///    a channel which has mode +m set or where the user is
+    ///    banned and is trying to send a PRIVMSG message to
+    ///    that channel.
+    ///
+    ERR_CANNOTSENDTOCHAN(CS<'a>),
+
+    /// 405    ERR_TOOMANYCHANNELS
+    ///       "<channel name> :You have joined too many channels"
+    ///
+    ///  - Sent to a user when they have joined the maximum
+    ///    number of allowed channels and they try to join
+    ///    another channel.
+    ///
+    ERR_TOOMANYCHANNELS(CS<'a>),
+
+    /// 406    ERR_WASNOSUCHNICK
+    ///       "<nickname> :There was no such nickname"
+    ///
+    ///  - Returned by WHOWAS to indicate there is no history
+    ///    information for that nickname.
+    ///
+    ERR_WASNOSUCHNICK(CS<'a>),
+
+    /// 407    ERR_TOOMANYTARGETS
+    ///       "<target> :<error code> recipients. <abort message>"
+    ///
+    ///  - Returned to a client which is attempting to send a
+    ///    PRIVMSG/NOTICE using the user@host destination format
+    ///    and for a user@host which has several occurrences.
+    ///
+    ///  - Returned to a client which trying to send a
+    ///    PRIVMSG/NOTICE to too many recipients.
+    ///
+    ///  - Returned to a client which is attempting to JOIN a safe
+    ///    channel using the shortname when there are more than one
+    ///    such channel.
+    ///
+    ERR_TOOMANYTARGETS(CS<'a>),
+
+    /// 408    ERR_NOSUCHSERVICE
+    ///       "<service name> :No such service"
+    ///
+    ///  - Returned to a client which is attempting to send a SQUERY
+    ///    to a service which does not exist.
+    ///
+    ERR_NOSUCHSERVICE(CS<'a>),
+
+    /// 409    ERR_NOORIGIN
+    ///       ":No origin specified"
+    ///
+    ///  - PING or PONG message missing the originator parameter.
+    ///
+    ERR_NOORIGIN(CS<'a>),
+
+    /// 411    ERR_NORECIPIENT
+    ///       ":No recipient given (<command>)"
+    ERR_NORECIPIENT(CS<'a>),
+
+    /// 412    ERR_NOTEXTTOSEND
+    ///       ":No text to send"
+    ERR_NOTEXTTOSEND(CS<'a>),
+
+    /// 413    ERR_NOTOPLEVEL
+    ///       "<mask> :No toplevel domain specified"
+    ERR_NOTOPLEVEL(CS<'a>),
+
+    /// 414    ERR_WILDTOPLEVEL
+    ///       "<mask> :Wildcard in toplevel domain"
+    ERR_WILDTOPLEVEL(CS<'a>),
+
+    /// 415    ERR_BADMASK
+    ///       "<mask> :Bad Server/host mask"
+    ///
+    ///  - 412 - 415 are returned by PRIVMSG to indicate that
+    ///    the message wasn't delivered for some reason.
+    ///    ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
+    ///    are returned when an invalid use of
+    ///    "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
+    ///
+    ERR_BADMASK(CS<'a>),
+
+    /// 421    ERR_UNKNOWNCOMMAND
+    ///       "<command> :Unknown command"
+    ///
+    ///  - Returned to a registered client to indicate that the
+    ///    command sent is unknown by the server.
+    ///
+    ERR_UNKNOWNCOMMAND(CS<'a>),
+
+    /// 422    ERR_NOMOTD
+    ///       ":MOTD File is missing"
+    ///
+    ///  - Server's MOTD file could not be opened by the server.
+    ///
+    ERR_NOMOTD(CS<'a>),
+
+    /// 423    ERR_NOADMININFO
+    ///       "<server> :No administrative info available"
+    ///
+    ///  - Returned by a server in response to an ADMIN message
+    ///    when there is an error in finding the appropriate
+    ///    information.
+    ///
+    ERR_NOADMININFO(CS<'a>),
+
+    /// 424    ERR_FILEERROR
+    ///       ":File error doing <file op> on <file>"
+    ///
+    ///  - Generic error message used to report a failed file
+    ///    operation during the processing of a message.
+    ///
+    ERR_FILEERROR(CS<'a>),
+
+    /// 431    ERR_NONICKNAMEGIVEN
+    ///       ":No nickname given"
+    ///
+    ///  - Returned when a nickname parameter expected for a
+    ///    command and isn't found.
+    ///
+    ERR_NONICKNAMEGIVEN(CS<'a>),
+
+    /// 432    ERR_ERRONEUSNICKNAME
+    ///       "<nick> :Erroneous nickname"
+    ///
+    ///  - Returned after receiving a NICK message which contains
+    ///    characters which do not fall in the defined set.  See
+    ///    section 2.3.1 for details on valid nicknames.
+    ///
+    ERR_ERRONEUSNICKNAME(CS<'a>),
+
+    /// 433    ERR_NICKNAMEINUSE
+    ///       "<nick> :Nickname is already in use"
+    ///
+    ///  - Returned when a NICK message is processed that results
+    ///    in an attempt to change to a currently existing
+    ///    nickname.
+    ///
+    ERR_NICKNAMEINUSE(CS<'a>),
+
+    /// 436    ERR_NICKCOLLISION
+    ///       "<nick> :Nickname collision KILL from <user>@<host>"
+    ///
+    ///  - Returned by a server to a client when it detects a
+    ///    nickname collision (registered of a NICK that
+    ///    already exists by another server).
+    ///
+    ERR_NICKCOLLISION(CS<'a>),
+
+    /// 437    ERR_UNAVAILRESOURCE
+    ///       "<nick/channel> :Nick/channel is temporarily unavailable"
+    ///
+    ///  - Returned by a server to a user trying to join a channel
+    ///    currently blocked by the channel delay mechanism.
+    ///
+    ///  - Returned by a server to a user trying to change nickname
+    ///    when the desired nickname is blocked by the nick delay
+    ///    mechanism.
+    ///
+    ERR_UNAVAILRESOURCE(CS<'a>),
+
+    /// 441    ERR_USERNOTINCHANNEL
+    ///       "<nick> <channel> :They aren't on that channel"
+    ///
+    ///  - Returned by the server to indicate that the target
+    ///    user of the command is not on the given channel.
+    ///
+    ERR_USERNOTINCHANNEL(CS<'a>),
+
+    /// 442    ERR_NOTONCHANNEL
+    ///       "<channel> :You're not on that channel"
+    ///
+    ///  - Returned by the server whenever a client tries to
+    ///    perform a channel affecting command for which the
+    ///    client isn't a member.
+    ///
+    ERR_NOTONCHANNEL(CS<'a>),
+
+    /// 443    ERR_USERONCHANNEL
+    ///       "<user> <channel> :is already on channel"
+    ///
+    ///  - Returned when a client tries to invite a user to a
+    ///    channel they are already on.
+    ///
+    ERR_USERONCHANNEL(CS<'a>),
+
+    /// 444    ERR_NOLOGIN
+    ///       "<user> :User not logged in"
+    ///
+    ///  - Returned by the summon after a SUMMON command for a
+    ///    user was unable to be performed since they were not
+    ///    logged in.
+    ///
+    ERR_NOLOGIN(CS<'a>),
+
+    /// 445    ERR_SUMMONDISABLED
+    ///       ":SUMMON has been disabled"
+    ///
+    ///  - Returned as a response to the SUMMON command.  MUST be
+    ///    returned by any server which doesn't implement it.
+    ///
+    ERR_SUMMONDISABLED(CS<'a>),
+
+    /// 446    ERR_USERSDISABLED
+    ///       ":USERS has been disabled"
+    ///
+    ///  - Returned as a response to the USERS command.  MUST be
+    ///    returned by any server which does not implement it.
+    ///
+    ERR_USERSDISABLED(CS<'a>),
+
+    /// 451    ERR_NOTREGISTERED
+    ///       ":You have not registered"
+    ///
+    ///  - Returned by the server to indicate that the client
+    ///    MUST be registered before the server will allow it
+    ///    to be parsed in detail.
+    ///
+    ERR_NOTREGISTERED(CS<'a>),
+
+    /// 461    ERR_NEEDMOREPARAMS
+    ///       "<command> :Not enough parameters"
+    ///
+    ///  - Returned by the server by numerous commands to
+    ///    indicate to the client that it didn't supply enough
+    ///    parameters.
+    ///
+    ERR_NEEDMOREPARAMS(CS<'a>),
+
+    /// 462    ERR_ALREADYREGISTRED
+    ///       ":Unauthorized command (already registered)"
+    ///
+    ///  - Returned by the server to any link which tries to
+    ///    change part of the registered details (such as
+    ///    password or user details from second USER message).
+    ///
+    ERR_ALREADYREGISTRED(CS<'a>),
+
+    /// 463    ERR_NOPERMFORHOST
+    ///       ":Your host isn't among the privileged"
+    ///
+    ///  - Returned to a client which attempts to register with
+    ///    a server which does not been setup to allow
+    ///    connections from the host the attempted connection
+    ///    is tried.
+    ///
+    ERR_NOPERMFORHOST(CS<'a>),
+
+    /// 464    ERR_PASSWDMISMATCH
+    ///       ":Password incorrect"
+    ///
+    ///  - Returned to indicate a failed attempt at registering
+    ///    a connection for which a password was required and
+    ///    was either not given or incorrect.
+    ///
+    ERR_PASSWDMISMATCH(CS<'a>),
+
+    /// 465    ERR_YOUREBANNEDCREEP
+    ///       ":You are banned from this server"
+    ///
+    ///  - Returned after an attempt to connect and register
+    ///    yourself with a server which has been setup to
+    ///    explicitly deny connections to you.
+    ///
+    ERR_YOUREBANNEDCREEP(CS<'a>),
+
+    /// 466    ERR_YOUWILLBEBANNED
+    ///
+    ///  - Sent by a server to a user to inform that access to the
+    ///    server will soon be denied.
+    ///
+    ERR_YOUWILLBEBANNED(CS<'a>),
+
+    /// 467    ERR_KEYSET
+    ///       "<channel> :Channel key already set"
+    ERR_KEYSET(CS<'a>),
+
+    /// 471    ERR_CHANNELISFULL
+    ///       "<channel> :Cannot join channel (+l)"
+    ERR_CHANNELISFULL(CS<'a>),
+
+    /// 472    ERR_UNKNOWNMODE
+    ///       "<char> :is unknown mode char to me for <channel>"
+    ERR_UNKNOWNMODE(CS<'a>),
+
+    /// 473    ERR_INVITEONLYCHAN
+    ///       "<channel> :Cannot join channel (+i)"
+    ERR_INVITEONLYCHAN(CS<'a>),
+
+    /// 474    ERR_BANNEDFROMCHAN
+    ///       "<channel> :Cannot join channel (+b)"
+    ERR_BANNEDFROMCHAN(CS<'a>),
+
+    /// 475    ERR_BADCHANNELKEY
+    ///       "<channel> :Cannot join channel (+k)"
+    ERR_BADCHANNELKEY(CS<'a>),
+
+    /// 476    ERR_BADCHANMASK
+    ///       "<channel> :Bad Channel Mask"
+    ERR_BADCHANMASK(CS<'a>),
+
+    /// 477    ERR_NOCHANMODES
+    ///       "<channel> :Channel doesn't support modes"
+    ERR_NOCHANMODES(CS<'a>),
+
+    /// 478    ERR_BANLISTFULL
+    ///       "<channel> <char> :Channel list is full"
+    ///
+    ERR_BANLISTFULL(CS<'a>),
+
+    /// 481    ERR_NOPRIVILEGES
+    ///       ":Permission Denied- You're not an IRC operator"
+    ///
+    ///  - Any command requiring operator privileges to operate
+    ///    MUST return this error to indicate the attempt was
+    ///    unsuccessful.
+    ///
+    ERR_NOPRIVILEGES(CS<'a>),
+
+    /// 482    ERR_CHANOPRIVSNEEDED
+    ///       "<channel> :You're not channel operator"
+    ///
+    ///  - Any command requiring 'chanop' privileges (such as
+    ///    MODE messages) MUST return this error if the client
+    ///    making the attempt is not a chanop on the specified
+    ///    channel.
+    ///
+    ERR_CHANOPRIVSNEEDED(CS<'a>),
+
+    /// 483    ERR_CANTKILLSERVER
+    ///       ":You can't kill a server!"
+    ///
+    ///  - Any attempts to use the KILL command on a server
+    ///    are to be refused and this error returned directly
+    ///    to the client.
+    ///
+    ERR_CANTKILLSERVER(CS<'a>),
+
+    /// 484    ERR_RESTRICTED
+    ///       ":Your connection is restricted!"
+    ///
+    ///  - Sent by the server to a user upon connection to indicate
+    ///    the restricted nature of the connection (user mode "+r").
+    ///
+    ERR_RESTRICTED(CS<'a>),
+
+    /// 485    ERR_UNIQOPPRIVSNEEDED
+    ///       ":You're not the original channel operator"
+    ///
+    ///  - Any MODE requiring "channel creator" privileges MUST
+    ///    return this error if the client making the attempt is not
+    ///    a chanop on the specified channel.
+    ///
+    ERR_UNIQOPPRIVSNEEDED(CS<'a>),
+
+    /// 491    ERR_NOOPERHOST
+    ///       ":No O-lines for your host"
+    ///
+    ///  - If a client sends an OPER message and the server has
+    ///    not been configured to allow connections from the
+    ///    client's host as an operator, this error MUST be
+    ///    returned.
+    ///
+    ERR_NOOPERHOST(CS<'a>),
+
+    /// 501    ERR_UMODEUNKNOWNFLAG
+    ///       ":Unknown MODE flag"
+    ///
+    ///  - Returned by the server to indicate that a MODE
+    ///    message was sent with a nickname parameter and that
+    ///    the a mode flag sent was not recognized.
+    ///
+    ERR_UMODEUNKNOWNFLAG(CS<'a>),
+
+    /// 502    ERR_USERSDONTMATCH
+    ///       ":Cannot change mode for other users"
+    ///
+    ///  - Error sent to any user trying to view or change the
+    ///    user mode for a user other than themselves.
+    ///
+    ERR_USERSDONTMATCH(CS<'a>),
+
+}
+
+impl<'a> Reply<'a> {
+    pub fn from_message(msg: &'a Message) -> Option<Reply<'a>> {
+        use self::Reply::*;
+        match msg.command() {
+            "001" => msg.elements().last().map(|&e| RPL_WELCOME(Borrowed(e))),
+            "002" => msg.elements().last().map(|&e| RPL_YOURHOST(Borrowed(e))),
+            "003" => msg.elements().last().map(|&e| RPL_CREATED(Borrowed(e))),
+            "004" => msg.elements().last().map(|&e| RPL_MYINFO(Borrowed(e))),
+            "005" => msg.elements().last().map(|&e| RPL_BOUNCE(Borrowed(e))),
+            "302" => msg.elements().last().map(|&e| RPL_USERHOST(Borrowed(e))),
+            "303" => msg.elements().last().map(|&e| RPL_ISON(Borrowed(e))),
+            "301" => msg.elements().last().map(|&e| RPL_AWAY(Borrowed(e))),
+            "305" => msg.elements().last().map(|&e| RPL_UNAWAY(Borrowed(e))),
+            "306" => msg.elements().last().map(|&e| RPL_NOWAWAY(Borrowed(e))),
+            "311" => msg.elements().last().map(|&e| RPL_WHOISUSER(Borrowed(e))),
+            "312" => msg.elements().last().map(|&e| RPL_WHOISSERVER(Borrowed(e))),
+            "313" => msg.elements().last().map(|&e| RPL_WHOISOPERATOR(Borrowed(e))),
+            "317" => msg.elements().last().map(|&e| RPL_WHOISIDLE(Borrowed(e))),
+            "318" => msg.elements().last().map(|&e| RPL_ENDOFWHOIS(Borrowed(e))),
+            "319" => msg.elements().last().map(|&e| RPL_WHOISCHANNELS(Borrowed(e))),
+            "314" => msg.elements().last().map(|&e| RPL_WHOWASUSER(Borrowed(e))),
+            "369" => msg.elements().last().map(|&e| RPL_ENDOFWHOWAS(Borrowed(e))),
+            "321" => Some(RPL_LISTSTART),
+            "322" => msg.elements().last().map(|&e| RPL_LIST(Borrowed(e))),
+            "323" => msg.elements().last().map(|&e| RPL_LISTEND(Borrowed(e))),
+            "325" => msg.elements().last().map(|&e| RPL_UNIQOPIS(Borrowed(e))),
+            "324" => msg.elements().last().map(|&e| RPL_CHANNELMODEIS(Borrowed(e))),
+            "331" => msg.elements().last().map(|&e| RPL_NOTOPIC(Borrowed(e))),
+            "332" => msg.elements().last().map(|&e| RPL_TOPIC(Borrowed(e))),
+            "341" => msg.elements().last().map(|&e| RPL_INVITING(Borrowed(e))),
+            "342" => msg.elements().last().map(|&e| RPL_SUMMONING(Borrowed(e))),
+            "346" => msg.elements().last().map(|&e| RPL_INVITELIST(Borrowed(e))),
+            "347" => msg.elements().last().map(|&e| RPL_ENDOFINVITELIST(Borrowed(e))),
+            "348" => msg.elements().last().map(|&e| RPL_EXCEPTLIST(Borrowed(e))),
+            "349" => msg.elements().last().map(|&e| RPL_ENDOFEXCEPTLIST(Borrowed(e))),
+            "351" => msg.elements().last().map(|&e| RPL_VERSION(Borrowed(e))),
+            "352" => msg.elements().last().map(|&e| RPL_WHOREPLY(Borrowed(e))),
+            "315" => msg.elements().last().map(|&e| RPL_ENDOFWHO(Borrowed(e))),
+            "353" => msg.elements().last().map(|&e| RPL_NAMREPLY(Borrowed(e))),
+            "366" => msg.elements().last().map(|&e| RPL_ENDOFNAMES(Borrowed(e))),
+            "364" => msg.elements().last().map(|&e| RPL_LINKS(Borrowed(e))),
+            "365" => msg.elements().last().map(|&e| RPL_ENDOFLINKS(Borrowed(e))),
+            "367" => msg.elements().last().map(|&e| RPL_BANLIST(Borrowed(e))),
+            "368" => msg.elements().last().map(|&e| RPL_ENDOFBANLIST(Borrowed(e))),
+            "371" => msg.elements().last().map(|&e| RPL_INFO(Borrowed(e))),
+            "374" => msg.elements().last().map(|&e| RPL_ENDOFINFO(Borrowed(e))),
+            "375" => msg.elements().last().map(|&e| RPL_MOTDSTART(Borrowed(e))),
+            "372" => msg.elements().last().map(|&e| RPL_MOTD(Borrowed(e))),
+            "376" => msg.elements().last().map(|&e| RPL_ENDOFMOTD(Borrowed(e))),
+            "381" => msg.elements().last().map(|&e| RPL_YOUREOPER(Borrowed(e))),
+            "382" => msg.elements().last().map(|&e| RPL_REHASHING(Borrowed(e))),
+            "383" => msg.elements().last().map(|&e| RPL_YOURESERVICE(Borrowed(e))),
+            "391" => msg.elements().last().map(|&e| RPL_TIME(Borrowed(e))),
+            "392" => msg.elements().last().map(|&e| RPL_USERSSTART(Borrowed(e))),
+            "393" => msg.elements().last().map(|&e| RPL_USERS(Borrowed(e))),
+            "394" => msg.elements().last().map(|&e| RPL_ENDOFUSERS(Borrowed(e))),
+            "395" => msg.elements().last().map(|&e| RPL_NOUSERS(Borrowed(e))),
+            "200" => msg.elements().last().map(|&e| RPL_TRACELINK(Borrowed(e))),
+            "201" => msg.elements().last().map(|&e| RPL_TRACECONNECTING(Borrowed(e))),
+            "202" => msg.elements().last().map(|&e| RPL_TRACEHANDSHAKE(Borrowed(e))),
+            "203" => msg.elements().last().map(|&e| RPL_TRACEUNKNOWN(Borrowed(e))),
+            "204" => msg.elements().last().map(|&e| RPL_TRACEOPERATOR(Borrowed(e))),
+            "205" => msg.elements().last().map(|&e| RPL_TRACEUSER(Borrowed(e))),
+            "206" => msg.elements().last().map(|&e| RPL_TRACESERVER(Borrowed(e))),
+            "207" => msg.elements().last().map(|&e| RPL_TRACESERVICE(Borrowed(e))),
+            "208" => msg.elements().last().map(|&e| RPL_TRACENEWTYPE(Borrowed(e))),
+            "209" => msg.elements().last().map(|&e| RPL_TRACECLASS(Borrowed(e))),
+            "210" => msg.elements().last().map(|&e| RPL_TRACERECONNECT(Borrowed(e))),
+            "261" => msg.elements().last().map(|&e| RPL_TRACELOG(Borrowed(e))),
+            "262" => msg.elements().last().map(|&e| RPL_TRACEEND(Borrowed(e))),
+            "211" => msg.elements().last().map(|&e| RPL_STATSLINKINFO(Borrowed(e))),
+            "212" => msg.elements().last().map(|&e| RPL_STATSCOMMANDS(Borrowed(e))),
+            "219" => msg.elements().last().map(|&e| RPL_ENDOFSTATS(Borrowed(e))),
+            "242" => msg.elements().last().map(|&e| RPL_STATSUPTIME(Borrowed(e))),
+            "243" => msg.elements().last().map(|&e| RPL_STATSOLINE(Borrowed(e))),
+            "221" => msg.elements().last().map(|&e| RPL_UMODEIS(Borrowed(e))),
+            "234" => msg.elements().last().map(|&e| RPL_SERVLIST(Borrowed(e))),
+            "235" => msg.elements().last().map(|&e| RPL_SERVLISTEND(Borrowed(e))),
+            "251" => msg.elements().last().map(|&e| RPL_LUSERCLIENT(Borrowed(e))),
+            "252" => msg.elements().last().map(|&e| RPL_LUSEROP(Borrowed(e))),
+            "253" => msg.elements().last().map(|&e| RPL_LUSERUNKNOWN(Borrowed(e))),
+            "254" => msg.elements().last().map(|&e| RPL_LUSERCHANNELS(Borrowed(e))),
+            "255" => msg.elements().last().map(|&e| RPL_LUSERME(Borrowed(e))),
+            "256" => msg.elements().last().map(|&e| RPL_ADMINME(Borrowed(e))),
+            "257" => msg.elements().last().map(|&e| RPL_ADMINLOC1(Borrowed(e))),
+            "258" => msg.elements().last().map(|&e| RPL_ADMINLOC2(Borrowed(e))),
+            "259" => msg.elements().last().map(|&e| RPL_ADMINEMAIL(Borrowed(e))),
+            "263" => msg.elements().last().map(|&e| RPL_TRYAGAIN(Borrowed(e))),
+            "401" => msg.elements().last().map(|&e| ERR_NOSUCHNICK(Borrowed(e))),
+            "402" => msg.elements().last().map(|&e| ERR_NOSUCHSERVER(Borrowed(e))),
+            "403" => msg.elements().last().map(|&e| ERR_NOSUCHCHANNEL(Borrowed(e))),
+            "404" => msg.elements().last().map(|&e| ERR_CANNOTSENDTOCHAN(Borrowed(e))),
+            "405" => msg.elements().last().map(|&e| ERR_TOOMANYCHANNELS(Borrowed(e))),
+            "406" => msg.elements().last().map(|&e| ERR_WASNOSUCHNICK(Borrowed(e))),
+            "407" => msg.elements().last().map(|&e| ERR_TOOMANYTARGETS(Borrowed(e))),
+            "408" => msg.elements().last().map(|&e| ERR_NOSUCHSERVICE(Borrowed(e))),
+            "409" => msg.elements().last().map(|&e| ERR_NOORIGIN(Borrowed(e))),
+            "411" => msg.elements().last().map(|&e| ERR_NORECIPIENT(Borrowed(e))),
+            "412" => msg.elements().last().map(|&e| ERR_NOTEXTTOSEND(Borrowed(e))),
+            "413" => msg.elements().last().map(|&e| ERR_NOTOPLEVEL(Borrowed(e))),
+            "414" => msg.elements().last().map(|&e| ERR_WILDTOPLEVEL(Borrowed(e))),
+            "415" => msg.elements().last().map(|&e| ERR_BADMASK(Borrowed(e))),
+            "421" => msg.elements().last().map(|&e| ERR_UNKNOWNCOMMAND(Borrowed(e))),
+            "422" => msg.elements().last().map(|&e| ERR_NOMOTD(Borrowed(e))),
+            "423" => msg.elements().last().map(|&e| ERR_NOADMININFO(Borrowed(e))),
+            "424" => msg.elements().last().map(|&e| ERR_FILEERROR(Borrowed(e))),
+            "431" => msg.elements().last().map(|&e| ERR_NONICKNAMEGIVEN(Borrowed(e))),
+            "432" => msg.elements().last().map(|&e| ERR_ERRONEUSNICKNAME(Borrowed(e))),
+            "433" => msg.elements().last().map(|&e| ERR_NICKNAMEINUSE(Borrowed(e))),
+            "436" => msg.elements().last().map(|&e| ERR_NICKCOLLISION(Borrowed(e))),
+            "437" => msg.elements().last().map(|&e| ERR_UNAVAILRESOURCE(Borrowed(e))),
+            "441" => msg.elements().last().map(|&e| ERR_USERNOTINCHANNEL(Borrowed(e))),
+            "442" => msg.elements().last().map(|&e| ERR_NOTONCHANNEL(Borrowed(e))),
+            "443" => msg.elements().last().map(|&e| ERR_USERONCHANNEL(Borrowed(e))),
+            "444" => msg.elements().last().map(|&e| ERR_NOLOGIN(Borrowed(e))),
+            "445" => msg.elements().last().map(|&e| ERR_SUMMONDISABLED(Borrowed(e))),
+            "446" => msg.elements().last().map(|&e| ERR_USERSDISABLED(Borrowed(e))),
+            "451" => msg.elements().last().map(|&e| ERR_NOTREGISTERED(Borrowed(e))),
+            "461" => msg.elements().last().map(|&e| ERR_NEEDMOREPARAMS(Borrowed(e))),
+            "462" => msg.elements().last().map(|&e| ERR_ALREADYREGISTRED(Borrowed(e))),
+            "463" => msg.elements().last().map(|&e| ERR_NOPERMFORHOST(Borrowed(e))),
+            "464" => msg.elements().last().map(|&e| ERR_PASSWDMISMATCH(Borrowed(e))),
+            "465" => msg.elements().last().map(|&e| ERR_YOUREBANNEDCREEP(Borrowed(e))),
+            "466" => msg.elements().last().map(|&e| ERR_YOUWILLBEBANNED(Borrowed(e))),
+            "467" => msg.elements().last().map(|&e| ERR_KEYSET(Borrowed(e))),
+            "471" => msg.elements().last().map(|&e| ERR_CHANNELISFULL(Borrowed(e))),
+            "472" => msg.elements().last().map(|&e| ERR_UNKNOWNMODE(Borrowed(e))),
+            "473" => msg.elements().last().map(|&e| ERR_INVITEONLYCHAN(Borrowed(e))),
+            "474" => msg.elements().last().map(|&e| ERR_BANNEDFROMCHAN(Borrowed(e))),
+            "475" => msg.elements().last().map(|&e| ERR_BADCHANNELKEY(Borrowed(e))),
+            "476" => msg.elements().last().map(|&e| ERR_BADCHANMASK(Borrowed(e))),
+            "477" => msg.elements().last().map(|&e| ERR_NOCHANMODES(Borrowed(e))),
+            "478" => msg.elements().last().map(|&e| ERR_BANLISTFULL(Borrowed(e))),
+            "481" => msg.elements().last().map(|&e| ERR_NOPRIVILEGES(Borrowed(e))),
+            "482" => msg.elements().last().map(|&e| ERR_CHANOPRIVSNEEDED(Borrowed(e))),
+            "483" => msg.elements().last().map(|&e| ERR_CANTKILLSERVER(Borrowed(e))),
+            "484" => msg.elements().last().map(|&e| ERR_RESTRICTED(Borrowed(e))),
+            "485" => msg.elements().last().map(|&e| ERR_UNIQOPPRIVSNEEDED(Borrowed(e))),
+            "491" => msg.elements().last().map(|&e| ERR_NOOPERHOST(Borrowed(e))),
+            "501" => msg.elements().last().map(|&e| ERR_UMODEUNKNOWNFLAG(Borrowed(e))),
+            "502" => msg.elements().last().map(|&e| ERR_USERSDONTMATCH(Borrowed(e))),
+            _ => None
+        }
+     }
+
+    pub fn to_message(&'a self) -> Message {
+        use self::Reply::*;
+        match self {
+            &RPL_WELCOME(ref s) => Message::format(None, Borrowed("001"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_YOURHOST(ref s) => Message::format(None, Borrowed("002"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_CREATED(ref s) => Message::format(None, Borrowed("003"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_MYINFO(ref s) => Message::format(None, Borrowed("004"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_BOUNCE(ref s) => Message::format(None, Borrowed("005"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_USERHOST(ref s) => Message::format(None, Borrowed("302"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ISON(ref s) => Message::format(None, Borrowed("303"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_AWAY(ref s) => Message::format(None, Borrowed("301"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_UNAWAY(ref s) => Message::format(None, Borrowed("305"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_NOWAWAY(ref s) => Message::format(None, Borrowed("306"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOISUSER(ref s) => Message::format(None, Borrowed("311"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOISSERVER(ref s) => Message::format(None, Borrowed("312"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOISOPERATOR(ref s) => Message::format(None, Borrowed("313"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOISIDLE(ref s) => Message::format(None, Borrowed("317"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFWHOIS(ref s) => Message::format(None, Borrowed("318"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOISCHANNELS(ref s) => Message::format(None, Borrowed("319"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOWASUSER(ref s) => Message::format(None, Borrowed("314"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFWHOWAS(ref s) => Message::format(None, Borrowed("369"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LISTSTART => Message::format(None, Borrowed("321"), vec![], None, MsgType::Irc),
+            &RPL_LIST(ref s) => Message::format(None, Borrowed("322"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LISTEND(ref s) => Message::format(None, Borrowed("323"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_UNIQOPIS(ref s) => Message::format(None, Borrowed("325"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_CHANNELMODEIS(ref s) => Message::format(None, Borrowed("324"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_NOTOPIC(ref s) => Message::format(None, Borrowed("331"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TOPIC(ref s) => Message::format(None, Borrowed("332"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_INVITING(ref s) => Message::format(None, Borrowed("341"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_SUMMONING(ref s) => Message::format(None, Borrowed("342"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_INVITELIST(ref s) => Message::format(None, Borrowed("346"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFINVITELIST(ref s) => Message::format(None, Borrowed("347"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_EXCEPTLIST(ref s) => Message::format(None, Borrowed("348"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFEXCEPTLIST(ref s) => Message::format(None, Borrowed("349"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_VERSION(ref s) => Message::format(None, Borrowed("351"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_WHOREPLY(ref s) => Message::format(None, Borrowed("352"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFWHO(ref s) => Message::format(None, Borrowed("315"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_NAMREPLY(ref s) => Message::format(None, Borrowed("353"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFNAMES(ref s) => Message::format(None, Borrowed("366"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LINKS(ref s) => Message::format(None, Borrowed("364"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFLINKS(ref s) => Message::format(None, Borrowed("365"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_BANLIST(ref s) => Message::format(None, Borrowed("367"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFBANLIST(ref s) => Message::format(None, Borrowed("368"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_INFO(ref s) => Message::format(None, Borrowed("371"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFINFO(ref s) => Message::format(None, Borrowed("374"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_MOTDSTART(ref s) => Message::format(None, Borrowed("375"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_MOTD(ref s) => Message::format(None, Borrowed("372"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFMOTD(ref s) => Message::format(None, Borrowed("376"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_YOUREOPER(ref s) => Message::format(None, Borrowed("381"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_REHASHING(ref s) => Message::format(None, Borrowed("382"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_YOURESERVICE(ref s) => Message::format(None, Borrowed("383"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TIME(ref s) => Message::format(None, Borrowed("391"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_USERSSTART(ref s) => Message::format(None, Borrowed("392"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_USERS(ref s) => Message::format(None, Borrowed("393"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFUSERS(ref s) => Message::format(None, Borrowed("394"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_NOUSERS(ref s) => Message::format(None, Borrowed("395"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACELINK(ref s) => Message::format(None, Borrowed("200"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACECONNECTING(ref s) => Message::format(None, Borrowed("201"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACEHANDSHAKE(ref s) => Message::format(None, Borrowed("202"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACEUNKNOWN(ref s) => Message::format(None, Borrowed("203"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACEOPERATOR(ref s) => Message::format(None, Borrowed("204"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACEUSER(ref s) => Message::format(None, Borrowed("205"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACESERVER(ref s) => Message::format(None, Borrowed("206"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACESERVICE(ref s) => Message::format(None, Borrowed("207"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACENEWTYPE(ref s) => Message::format(None, Borrowed("208"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACECLASS(ref s) => Message::format(None, Borrowed("209"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACERECONNECT(ref s) => Message::format(None, Borrowed("210"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACELOG(ref s) => Message::format(None, Borrowed("261"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRACEEND(ref s) => Message::format(None, Borrowed("262"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_STATSLINKINFO(ref s) => Message::format(None, Borrowed("211"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_STATSCOMMANDS(ref s) => Message::format(None, Borrowed("212"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ENDOFSTATS(ref s) => Message::format(None, Borrowed("219"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_STATSUPTIME(ref s) => Message::format(None, Borrowed("242"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_STATSOLINE(ref s) => Message::format(None, Borrowed("243"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_UMODEIS(ref s) => Message::format(None, Borrowed("221"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_SERVLIST(ref s) => Message::format(None, Borrowed("234"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_SERVLISTEND(ref s) => Message::format(None, Borrowed("235"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LUSERCLIENT(ref s) => Message::format(None, Borrowed("251"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LUSEROP(ref s) => Message::format(None, Borrowed("252"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LUSERUNKNOWN(ref s) => Message::format(None, Borrowed("253"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LUSERCHANNELS(ref s) => Message::format(None, Borrowed("254"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_LUSERME(ref s) => Message::format(None, Borrowed("255"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ADMINME(ref s) => Message::format(None, Borrowed("256"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ADMINLOC1(ref s) => Message::format(None, Borrowed("257"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ADMINLOC2(ref s) => Message::format(None, Borrowed("258"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_ADMINEMAIL(ref s) => Message::format(None, Borrowed("259"), vec![], Some(s.clone()), MsgType::Irc),
+            &RPL_TRYAGAIN(ref s) => Message::format(None, Borrowed("263"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOSUCHNICK(ref s) => Message::format(None, Borrowed("401"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOSUCHSERVER(ref s) => Message::format(None, Borrowed("402"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOSUCHCHANNEL(ref s) => Message::format(None, Borrowed("403"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_CANNOTSENDTOCHAN(ref s) => Message::format(None, Borrowed("404"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_TOOMANYCHANNELS(ref s) => Message::format(None, Borrowed("405"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_WASNOSUCHNICK(ref s) => Message::format(None, Borrowed("406"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_TOOMANYTARGETS(ref s) => Message::format(None, Borrowed("407"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOSUCHSERVICE(ref s) => Message::format(None, Borrowed("408"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOORIGIN(ref s) => Message::format(None, Borrowed("409"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NORECIPIENT(ref s) => Message::format(None, Borrowed("411"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOTEXTTOSEND(ref s) => Message::format(None, Borrowed("412"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOTOPLEVEL(ref s) => Message::format(None, Borrowed("413"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_WILDTOPLEVEL(ref s) => Message::format(None, Borrowed("414"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_BADMASK(ref s) => Message::format(None, Borrowed("415"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_UNKNOWNCOMMAND(ref s) => Message::format(None, Borrowed("421"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOMOTD(ref s) => Message::format(None, Borrowed("422"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOADMININFO(ref s) => Message::format(None, Borrowed("423"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_FILEERROR(ref s) => Message::format(None, Borrowed("424"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NONICKNAMEGIVEN(ref s) => Message::format(None, Borrowed("431"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_ERRONEUSNICKNAME(ref s) => Message::format(None, Borrowed("432"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NICKNAMEINUSE(ref s) => Message::format(None, Borrowed("433"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NICKCOLLISION(ref s) => Message::format(None, Borrowed("436"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_UNAVAILRESOURCE(ref s) => Message::format(None, Borrowed("437"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_USERNOTINCHANNEL(ref s) => Message::format(None, Borrowed("441"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOTONCHANNEL(ref s) => Message::format(None, Borrowed("442"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_USERONCHANNEL(ref s) => Message::format(None, Borrowed("443"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOLOGIN(ref s) => Message::format(None, Borrowed("444"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_SUMMONDISABLED(ref s) => Message::format(None, Borrowed("445"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_USERSDISABLED(ref s) => Message::format(None, Borrowed("446"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOTREGISTERED(ref s) => Message::format(None, Borrowed("451"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NEEDMOREPARAMS(ref s) => Message::format(None, Borrowed("461"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_ALREADYREGISTRED(ref s) => Message::format(None, Borrowed("462"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOPERMFORHOST(ref s) => Message::format(None, Borrowed("463"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_PASSWDMISMATCH(ref s) => Message::format(None, Borrowed("464"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_YOUREBANNEDCREEP(ref s) => Message::format(None, Borrowed("465"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_YOUWILLBEBANNED(ref s) => Message::format(None, Borrowed("466"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_KEYSET(ref s) => Message::format(None, Borrowed("467"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_CHANNELISFULL(ref s) => Message::format(None, Borrowed("471"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_UNKNOWNMODE(ref s) => Message::format(None, Borrowed("472"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_INVITEONLYCHAN(ref s) => Message::format(None, Borrowed("473"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_BANNEDFROMCHAN(ref s) => Message::format(None, Borrowed("474"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_BADCHANNELKEY(ref s) => Message::format(None, Borrowed("475"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_BADCHANMASK(ref s) => Message::format(None, Borrowed("476"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOCHANMODES(ref s) => Message::format(None, Borrowed("477"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_BANLISTFULL(ref s) => Message::format(None, Borrowed("478"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOPRIVILEGES(ref s) => Message::format(None, Borrowed("481"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_CHANOPRIVSNEEDED(ref s) => Message::format(None, Borrowed("482"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_CANTKILLSERVER(ref s) => Message::format(None, Borrowed("483"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_RESTRICTED(ref s) => Message::format(None, Borrowed("484"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_UNIQOPPRIVSNEEDED(ref s) => Message::format(None, Borrowed("485"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_NOOPERHOST(ref s) => Message::format(None, Borrowed("491"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_UMODEUNKNOWNFLAG(ref s) => Message::format(None, Borrowed("501"), vec![], Some(s.clone()), MsgType::Irc),
+            &ERR_USERSDONTMATCH(ref s) => Message::format(None, Borrowed("502"), vec![], Some(s.clone()), MsgType::Irc),
+        }
+     }
+
+    pub fn to_static(&self) -> Reply<'static> {
+        use self::Reply::*;
+        match self {
+            &RPL_WELCOME(ref s) => RPL_WELCOME(Cow::Owned(s.clone().into_owned())),
+            &RPL_YOURHOST(ref s) => RPL_YOURHOST(Cow::Owned(s.clone().into_owned())),
+            &RPL_CREATED(ref s) => RPL_CREATED(Cow::Owned(s.clone().into_owned())),
+            &RPL_MYINFO(ref s) => RPL_MYINFO(Cow::Owned(s.clone().into_owned())),
+            &RPL_BOUNCE(ref s) => RPL_BOUNCE(Cow::Owned(s.clone().into_owned())),
+            &RPL_USERHOST(ref s) => RPL_USERHOST(Cow::Owned(s.clone().into_owned())),
+            &RPL_ISON(ref s) => RPL_ISON(Cow::Owned(s.clone().into_owned())),
+            &RPL_AWAY(ref s) => RPL_AWAY(Cow::Owned(s.clone().into_owned())),
+            &RPL_UNAWAY(ref s) => RPL_UNAWAY(Cow::Owned(s.clone().into_owned())),
+            &RPL_NOWAWAY(ref s) => RPL_NOWAWAY(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOISUSER(ref s) => RPL_WHOISUSER(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOISSERVER(ref s) => RPL_WHOISSERVER(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOISOPERATOR(ref s) => RPL_WHOISOPERATOR(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOISIDLE(ref s) => RPL_WHOISIDLE(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFWHOIS(ref s) => RPL_ENDOFWHOIS(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOISCHANNELS(ref s) => RPL_WHOISCHANNELS(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOWASUSER(ref s) => RPL_WHOWASUSER(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFWHOWAS(ref s) => RPL_ENDOFWHOWAS(Cow::Owned(s.clone().into_owned())),
+            &RPL_LISTSTART => RPL_LISTSTART,
+            &RPL_LIST(ref s) => RPL_LIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_LISTEND(ref s) => RPL_LISTEND(Cow::Owned(s.clone().into_owned())),
+            &RPL_UNIQOPIS(ref s) => RPL_UNIQOPIS(Cow::Owned(s.clone().into_owned())),
+            &RPL_CHANNELMODEIS(ref s) => RPL_CHANNELMODEIS(Cow::Owned(s.clone().into_owned())),
+            &RPL_NOTOPIC(ref s) => RPL_NOTOPIC(Cow::Owned(s.clone().into_owned())),
+            &RPL_TOPIC(ref s) => RPL_TOPIC(Cow::Owned(s.clone().into_owned())),
+            &RPL_INVITING(ref s) => RPL_INVITING(Cow::Owned(s.clone().into_owned())),
+            &RPL_SUMMONING(ref s) => RPL_SUMMONING(Cow::Owned(s.clone().into_owned())),
+            &RPL_INVITELIST(ref s) => RPL_INVITELIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFINVITELIST(ref s) => RPL_ENDOFINVITELIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_EXCEPTLIST(ref s) => RPL_EXCEPTLIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFEXCEPTLIST(ref s) => RPL_ENDOFEXCEPTLIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_VERSION(ref s) => RPL_VERSION(Cow::Owned(s.clone().into_owned())),
+            &RPL_WHOREPLY(ref s) => RPL_WHOREPLY(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFWHO(ref s) => RPL_ENDOFWHO(Cow::Owned(s.clone().into_owned())),
+            &RPL_NAMREPLY(ref s) => RPL_NAMREPLY(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFNAMES(ref s) => RPL_ENDOFNAMES(Cow::Owned(s.clone().into_owned())),
+            &RPL_LINKS(ref s) => RPL_LINKS(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFLINKS(ref s) => RPL_ENDOFLINKS(Cow::Owned(s.clone().into_owned())),
+            &RPL_BANLIST(ref s) => RPL_BANLIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFBANLIST(ref s) => RPL_ENDOFBANLIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_INFO(ref s) => RPL_INFO(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFINFO(ref s) => RPL_ENDOFINFO(Cow::Owned(s.clone().into_owned())),
+            &RPL_MOTDSTART(ref s) => RPL_MOTDSTART(Cow::Owned(s.clone().into_owned())),
+            &RPL_MOTD(ref s) => RPL_MOTD(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFMOTD(ref s) => RPL_ENDOFMOTD(Cow::Owned(s.clone().into_owned())),
+            &RPL_YOUREOPER(ref s) => RPL_YOUREOPER(Cow::Owned(s.clone().into_owned())),
+            &RPL_REHASHING(ref s) => RPL_REHASHING(Cow::Owned(s.clone().into_owned())),
+            &RPL_YOURESERVICE(ref s) => RPL_YOURESERVICE(Cow::Owned(s.clone().into_owned())),
+            &RPL_TIME(ref s) => RPL_TIME(Cow::Owned(s.clone().into_owned())),
+            &RPL_USERSSTART(ref s) => RPL_USERSSTART(Cow::Owned(s.clone().into_owned())),
+            &RPL_USERS(ref s) => RPL_USERS(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFUSERS(ref s) => RPL_ENDOFUSERS(Cow::Owned(s.clone().into_owned())),
+            &RPL_NOUSERS(ref s) => RPL_NOUSERS(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACELINK(ref s) => RPL_TRACELINK(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACECONNECTING(ref s) => RPL_TRACECONNECTING(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACEHANDSHAKE(ref s) => RPL_TRACEHANDSHAKE(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACEUNKNOWN(ref s) => RPL_TRACEUNKNOWN(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACEOPERATOR(ref s) => RPL_TRACEOPERATOR(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACEUSER(ref s) => RPL_TRACEUSER(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACESERVER(ref s) => RPL_TRACESERVER(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACESERVICE(ref s) => RPL_TRACESERVICE(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACENEWTYPE(ref s) => RPL_TRACENEWTYPE(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACECLASS(ref s) => RPL_TRACECLASS(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACERECONNECT(ref s) => RPL_TRACERECONNECT(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACELOG(ref s) => RPL_TRACELOG(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRACEEND(ref s) => RPL_TRACEEND(Cow::Owned(s.clone().into_owned())),
+            &RPL_STATSLINKINFO(ref s) => RPL_STATSLINKINFO(Cow::Owned(s.clone().into_owned())),
+            &RPL_STATSCOMMANDS(ref s) => RPL_STATSCOMMANDS(Cow::Owned(s.clone().into_owned())),
+            &RPL_ENDOFSTATS(ref s) => RPL_ENDOFSTATS(Cow::Owned(s.clone().into_owned())),
+            &RPL_STATSUPTIME(ref s) => RPL_STATSUPTIME(Cow::Owned(s.clone().into_owned())),
+            &RPL_STATSOLINE(ref s) => RPL_STATSOLINE(Cow::Owned(s.clone().into_owned())),
+            &RPL_UMODEIS(ref s) => RPL_UMODEIS(Cow::Owned(s.clone().into_owned())),
+            &RPL_SERVLIST(ref s) => RPL_SERVLIST(Cow::Owned(s.clone().into_owned())),
+            &RPL_SERVLISTEND(ref s) => RPL_SERVLISTEND(Cow::Owned(s.clone().into_owned())),
+            &RPL_LUSERCLIENT(ref s) => RPL_LUSERCLIENT(Cow::Owned(s.clone().into_owned())),
+            &RPL_LUSEROP(ref s) => RPL_LUSEROP(Cow::Owned(s.clone().into_owned())),
+            &RPL_LUSERUNKNOWN(ref s) => RPL_LUSERUNKNOWN(Cow::Owned(s.clone().into_owned())),
+            &RPL_LUSERCHANNELS(ref s) => RPL_LUSERCHANNELS(Cow::Owned(s.clone().into_owned())),
+            &RPL_LUSERME(ref s) => RPL_LUSERME(Cow::Owned(s.clone().into_owned())),
+            &RPL_ADMINME(ref s) => RPL_ADMINME(Cow::Owned(s.clone().into_owned())),
+            &RPL_ADMINLOC1(ref s) => RPL_ADMINLOC1(Cow::Owned(s.clone().into_owned())),
+            &RPL_ADMINLOC2(ref s) => RPL_ADMINLOC2(Cow::Owned(s.clone().into_owned())),
+            &RPL_ADMINEMAIL(ref s) => RPL_ADMINEMAIL(Cow::Owned(s.clone().into_owned())),
+            &RPL_TRYAGAIN(ref s) => RPL_TRYAGAIN(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOSUCHNICK(ref s) => ERR_NOSUCHNICK(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOSUCHSERVER(ref s) => ERR_NOSUCHSERVER(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOSUCHCHANNEL(ref s) => ERR_NOSUCHCHANNEL(Cow::Owned(s.clone().into_owned())),
+            &ERR_CANNOTSENDTOCHAN(ref s) => ERR_CANNOTSENDTOCHAN(Cow::Owned(s.clone().into_owned())),
+            &ERR_TOOMANYCHANNELS(ref s) => ERR_TOOMANYCHANNELS(Cow::Owned(s.clone().into_owned())),
+            &ERR_WASNOSUCHNICK(ref s) => ERR_WASNOSUCHNICK(Cow::Owned(s.clone().into_owned())),
+            &ERR_TOOMANYTARGETS(ref s) => ERR_TOOMANYTARGETS(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOSUCHSERVICE(ref s) => ERR_NOSUCHSERVICE(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOORIGIN(ref s) => ERR_NOORIGIN(Cow::Owned(s.clone().into_owned())),
+            &ERR_NORECIPIENT(ref s) => ERR_NORECIPIENT(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOTEXTTOSEND(ref s) => ERR_NOTEXTTOSEND(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOTOPLEVEL(ref s) => ERR_NOTOPLEVEL(Cow::Owned(s.clone().into_owned())),
+            &ERR_WILDTOPLEVEL(ref s) => ERR_WILDTOPLEVEL(Cow::Owned(s.clone().into_owned())),
+            &ERR_BADMASK(ref s) => ERR_BADMASK(Cow::Owned(s.clone().into_owned())),
+            &ERR_UNKNOWNCOMMAND(ref s) => ERR_UNKNOWNCOMMAND(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOMOTD(ref s) => ERR_NOMOTD(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOADMININFO(ref s) => ERR_NOADMININFO(Cow::Owned(s.clone().into_owned())),
+            &ERR_FILEERROR(ref s) => ERR_FILEERROR(Cow::Owned(s.clone().into_owned())),
+            &ERR_NONICKNAMEGIVEN(ref s) => ERR_NONICKNAMEGIVEN(Cow::Owned(s.clone().into_owned())),
+            &ERR_ERRONEUSNICKNAME(ref s) => ERR_ERRONEUSNICKNAME(Cow::Owned(s.clone().into_owned())),
+            &ERR_NICKNAMEINUSE(ref s) => ERR_NICKNAMEINUSE(Cow::Owned(s.clone().into_owned())),
+            &ERR_NICKCOLLISION(ref s) => ERR_NICKCOLLISION(Cow::Owned(s.clone().into_owned())),
+            &ERR_UNAVAILRESOURCE(ref s) => ERR_UNAVAILRESOURCE(Cow::Owned(s.clone().into_owned())),
+            &ERR_USERNOTINCHANNEL(ref s) => ERR_USERNOTINCHANNEL(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOTONCHANNEL(ref s) => ERR_NOTONCHANNEL(Cow::Owned(s.clone().into_owned())),
+            &ERR_USERONCHANNEL(ref s) => ERR_USERONCHANNEL(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOLOGIN(ref s) => ERR_NOLOGIN(Cow::Owned(s.clone().into_owned())),
+            &ERR_SUMMONDISABLED(ref s) => ERR_SUMMONDISABLED(Cow::Owned(s.clone().into_owned())),
+            &ERR_USERSDISABLED(ref s) => ERR_USERSDISABLED(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOTREGISTERED(ref s) => ERR_NOTREGISTERED(Cow::Owned(s.clone().into_owned())),
+            &ERR_NEEDMOREPARAMS(ref s) => ERR_NEEDMOREPARAMS(Cow::Owned(s.clone().into_owned())),
+            &ERR_ALREADYREGISTRED(ref s) => ERR_ALREADYREGISTRED(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOPERMFORHOST(ref s) => ERR_NOPERMFORHOST(Cow::Owned(s.clone().into_owned())),
+            &ERR_PASSWDMISMATCH(ref s) => ERR_PASSWDMISMATCH(Cow::Owned(s.clone().into_owned())),
+            &ERR_YOUREBANNEDCREEP(ref s) => ERR_YOUREBANNEDCREEP(Cow::Owned(s.clone().into_owned())),
+            &ERR_YOUWILLBEBANNED(ref s) => ERR_YOUWILLBEBANNED(Cow::Owned(s.clone().into_owned())),
+            &ERR_KEYSET(ref s) => ERR_KEYSET(Cow::Owned(s.clone().into_owned())),
+            &ERR_CHANNELISFULL(ref s) => ERR_CHANNELISFULL(Cow::Owned(s.clone().into_owned())),
+            &ERR_UNKNOWNMODE(ref s) => ERR_UNKNOWNMODE(Cow::Owned(s.clone().into_owned())),
+            &ERR_INVITEONLYCHAN(ref s) => ERR_INVITEONLYCHAN(Cow::Owned(s.clone().into_owned())),
+            &ERR_BANNEDFROMCHAN(ref s) => ERR_BANNEDFROMCHAN(Cow::Owned(s.clone().into_owned())),
+            &ERR_BADCHANNELKEY(ref s) => ERR_BADCHANNELKEY(Cow::Owned(s.clone().into_owned())),
+            &ERR_BADCHANMASK(ref s) => ERR_BADCHANMASK(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOCHANMODES(ref s) => ERR_NOCHANMODES(Cow::Owned(s.clone().into_owned())),
+            &ERR_BANLISTFULL(ref s) => ERR_BANLISTFULL(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOPRIVILEGES(ref s) => ERR_NOPRIVILEGES(Cow::Owned(s.clone().into_owned())),
+            &ERR_CHANOPRIVSNEEDED(ref s) => ERR_CHANOPRIVSNEEDED(Cow::Owned(s.clone().into_owned())),
+            &ERR_CANTKILLSERVER(ref s) => ERR_CANTKILLSERVER(Cow::Owned(s.clone().into_owned())),
+            &ERR_RESTRICTED(ref s) => ERR_RESTRICTED(Cow::Owned(s.clone().into_owned())),
+            &ERR_UNIQOPPRIVSNEEDED(ref s) => ERR_UNIQOPPRIVSNEEDED(Cow::Owned(s.clone().into_owned())),
+            &ERR_NOOPERHOST(ref s) => ERR_NOOPERHOST(Cow::Owned(s.clone().into_owned())),
+            &ERR_UMODEUNKNOWNFLAG(ref s) => ERR_UMODEUNKNOWNFLAG(Cow::Owned(s.clone().into_owned())),
+            &ERR_USERSDONTMATCH(ref s) => ERR_USERSDONTMATCH(Cow::Owned(s.clone().into_owned())),
+        }
+
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/lazy_static/lib.rs.html b/src/lazy_static/lib.rs.html new file mode 100644 index 0000000..b6e5e1e --- /dev/null +++ b/src/lazy_static/lib.rs.html @@ -0,0 +1,345 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+/*!
+A macro for declaring lazily evaluated statics.
+
+Using this macro, it is possible to have `static`s that require code to be
+executed at runtime in order to be initialized.
+This includes anything requiring heap allocations, like vectors or hash maps,
+as well as anything that requires function calls to be computed.
+
+# Syntax
+
+```ignore
+lazy_static! {
+    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
+    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
+    ...
+    [pub] static ref NAME_N: TYPE_N = EXPR_N;
+}
+```
+
+# Semantic
+
+For a given `static ref NAME: TYPE = EXPR;`, the macro generates a
+unique type that implements `Deref<TYPE>` and stores it in a static with name `NAME`.
+
+On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
+can return a reference to the same object.
+
+Like regular `static mut`s, this macro only works for types that fulfill the `Sync`
+trait.
+
+# Example
+
+Using the macro:
+
+```rust
+#[macro_use]
+extern crate lazy_static;
+
+use std::collections::HashMap;
+
+lazy_static! {
+    static ref HASHMAP: HashMap<u32, &'static str> = {
+        let mut m = HashMap::new();
+        m.insert(0, "foo");
+        m.insert(1, "bar");
+        m.insert(2, "baz");
+        m
+    };
+    static ref COUNT: usize = HASHMAP.len();
+    static ref NUMBER: u32 = times_two(21);
+}
+
+fn times_two(n: u32) -> u32 { n * 2 }
+
+fn main() {
+    println!("The map has {} entries.", *COUNT);
+    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
+    println!("A expensive calculation on a static results in: {}.", *NUMBER);
+}
+```
+
+# Implementation details
+
+The `Deref` implementation uses a hidden `static mut` that is guarded by a atomic check
+using the `sync::Once` abstraction. All lazily evaluated values are currently
+put in a heap allocated box, due to the Rust language currently not providing any way to
+define uninitialized `static mut` values.
+
+*/
+
+#![crate_type = "dylib"]
+
+#[macro_export]
+macro_rules! lazy_static {
+    (static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
+        lazy_static!(PRIV static ref $N : $T = $e; $($t)*);
+    };
+    (pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
+        lazy_static!(PUB static ref $N : $T = $e; $($t)*);
+    };
+    ($VIS:ident static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
+        lazy_static!(MAKE TY $VIS $N);
+        impl ::std::ops::Deref for $N {
+            type Target = $T;
+            fn deref<'a>(&'a self) -> &'a $T {
+                #[inline(always)]
+                fn __static_ref_initialize() -> Box<$T> { Box::new($e) }
+
+                unsafe {
+                    use std::sync::{Once, ONCE_INIT};
+                    use std::mem::transmute;
+
+                    #[inline(always)]
+                    fn require_sync<T: Sync>(_: &T) { }
+
+                    static mut DATA: *const $T = 0 as *const $T;
+                    static mut ONCE: Once = ONCE_INIT;
+                    ONCE.call_once(|| {
+                        DATA = transmute::<Box<$T>, *const $T>(__static_ref_initialize());
+                    });
+                    let static_ref = &*DATA;
+                    require_sync(static_ref);
+                    static_ref
+                }
+            }
+        }
+        lazy_static!($($t)*);
+    };
+    (MAKE TY PUB $N:ident) => {
+        #[allow(missing_copy_implementations)]
+        #[allow(non_camel_case_types)]
+        #[allow(dead_code)]
+        pub struct $N {__private_field: ()}
+        pub static $N: $N = $N {__private_field: ()};
+    };
+    (MAKE TY PRIV $N:ident) => {
+        #[allow(missing_copy_implementations)]
+        #[allow(non_camel_case_types)]
+        #[allow(dead_code)]
+        struct $N {__private_field: ()}
+        static $N: $N = $N {__private_field: ()};
+    };
+    () => ()
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libc/lib.rs.html b/src/libc/lib.rs.html new file mode 100644 index 0000000..ac022cd --- /dev/null +++ b/src/libc/lib.rs.html @@ -0,0 +1,12869 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
   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
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+3201
+3202
+3203
+3204
+3205
+3206
+3207
+3208
+3209
+3210
+3211
+3212
+3213
+3214
+3215
+3216
+3217
+3218
+3219
+3220
+3221
+3222
+3223
+3224
+3225
+3226
+3227
+3228
+3229
+3230
+3231
+3232
+3233
+3234
+3235
+3236
+3237
+3238
+3239
+3240
+3241
+3242
+3243
+3244
+3245
+3246
+3247
+3248
+3249
+3250
+3251
+3252
+3253
+3254
+3255
+3256
+3257
+3258
+3259
+3260
+3261
+3262
+3263
+3264
+3265
+3266
+3267
+3268
+3269
+3270
+3271
+3272
+3273
+3274
+3275
+3276
+3277
+3278
+3279
+3280
+3281
+3282
+3283
+3284
+3285
+3286
+3287
+3288
+3289
+3290
+3291
+3292
+3293
+3294
+3295
+3296
+3297
+3298
+3299
+3300
+3301
+3302
+3303
+3304
+3305
+3306
+3307
+3308
+3309
+3310
+3311
+3312
+3313
+3314
+3315
+3316
+3317
+3318
+3319
+3320
+3321
+3322
+3323
+3324
+3325
+3326
+3327
+3328
+3329
+3330
+3331
+3332
+3333
+3334
+3335
+3336
+3337
+3338
+3339
+3340
+3341
+3342
+3343
+3344
+3345
+3346
+3347
+3348
+3349
+3350
+3351
+3352
+3353
+3354
+3355
+3356
+3357
+3358
+3359
+3360
+3361
+3362
+3363
+3364
+3365
+3366
+3367
+3368
+3369
+3370
+3371
+3372
+3373
+3374
+3375
+3376
+3377
+3378
+3379
+3380
+3381
+3382
+3383
+3384
+3385
+3386
+3387
+3388
+3389
+3390
+3391
+3392
+3393
+3394
+3395
+3396
+3397
+3398
+3399
+3400
+3401
+3402
+3403
+3404
+3405
+3406
+3407
+3408
+3409
+3410
+3411
+3412
+3413
+3414
+3415
+3416
+3417
+3418
+3419
+3420
+3421
+3422
+3423
+3424
+3425
+3426
+3427
+3428
+3429
+3430
+3431
+3432
+3433
+3434
+3435
+3436
+3437
+3438
+3439
+3440
+3441
+3442
+3443
+3444
+3445
+3446
+3447
+3448
+3449
+3450
+3451
+3452
+3453
+3454
+3455
+3456
+3457
+3458
+3459
+3460
+3461
+3462
+3463
+3464
+3465
+3466
+3467
+3468
+3469
+3470
+3471
+3472
+3473
+3474
+3475
+3476
+3477
+3478
+3479
+3480
+3481
+3482
+3483
+3484
+3485
+3486
+3487
+3488
+3489
+3490
+3491
+3492
+3493
+3494
+3495
+3496
+3497
+3498
+3499
+3500
+3501
+3502
+3503
+3504
+3505
+3506
+3507
+3508
+3509
+3510
+3511
+3512
+3513
+3514
+3515
+3516
+3517
+3518
+3519
+3520
+3521
+3522
+3523
+3524
+3525
+3526
+3527
+3528
+3529
+3530
+3531
+3532
+3533
+3534
+3535
+3536
+3537
+3538
+3539
+3540
+3541
+3542
+3543
+3544
+3545
+3546
+3547
+3548
+3549
+3550
+3551
+3552
+3553
+3554
+3555
+3556
+3557
+3558
+3559
+3560
+3561
+3562
+3563
+3564
+3565
+3566
+3567
+3568
+3569
+3570
+3571
+3572
+3573
+3574
+3575
+3576
+3577
+3578
+3579
+3580
+3581
+3582
+3583
+3584
+3585
+3586
+3587
+3588
+3589
+3590
+3591
+3592
+3593
+3594
+3595
+3596
+3597
+3598
+3599
+3600
+3601
+3602
+3603
+3604
+3605
+3606
+3607
+3608
+3609
+3610
+3611
+3612
+3613
+3614
+3615
+3616
+3617
+3618
+3619
+3620
+3621
+3622
+3623
+3624
+3625
+3626
+3627
+3628
+3629
+3630
+3631
+3632
+3633
+3634
+3635
+3636
+3637
+3638
+3639
+3640
+3641
+3642
+3643
+3644
+3645
+3646
+3647
+3648
+3649
+3650
+3651
+3652
+3653
+3654
+3655
+3656
+3657
+3658
+3659
+3660
+3661
+3662
+3663
+3664
+3665
+3666
+3667
+3668
+3669
+3670
+3671
+3672
+3673
+3674
+3675
+3676
+3677
+3678
+3679
+3680
+3681
+3682
+3683
+3684
+3685
+3686
+3687
+3688
+3689
+3690
+3691
+3692
+3693
+3694
+3695
+3696
+3697
+3698
+3699
+3700
+3701
+3702
+3703
+3704
+3705
+3706
+3707
+3708
+3709
+3710
+3711
+3712
+3713
+3714
+3715
+3716
+3717
+3718
+3719
+3720
+3721
+3722
+3723
+3724
+3725
+3726
+3727
+3728
+3729
+3730
+3731
+3732
+3733
+3734
+3735
+3736
+3737
+3738
+3739
+3740
+3741
+3742
+3743
+3744
+3745
+3746
+3747
+3748
+3749
+3750
+3751
+3752
+3753
+3754
+3755
+3756
+3757
+3758
+3759
+3760
+3761
+3762
+3763
+3764
+3765
+3766
+3767
+3768
+3769
+3770
+3771
+3772
+3773
+3774
+3775
+3776
+3777
+3778
+3779
+3780
+3781
+3782
+3783
+3784
+3785
+3786
+3787
+3788
+3789
+3790
+3791
+3792
+3793
+3794
+3795
+3796
+3797
+3798
+3799
+3800
+3801
+3802
+3803
+3804
+3805
+3806
+3807
+3808
+3809
+3810
+3811
+3812
+3813
+3814
+3815
+3816
+3817
+3818
+3819
+3820
+3821
+3822
+3823
+3824
+3825
+3826
+3827
+3828
+3829
+3830
+3831
+3832
+3833
+3834
+3835
+3836
+3837
+3838
+3839
+3840
+3841
+3842
+3843
+3844
+3845
+3846
+3847
+3848
+3849
+3850
+3851
+3852
+3853
+3854
+3855
+3856
+3857
+3858
+3859
+3860
+3861
+3862
+3863
+3864
+3865
+3866
+3867
+3868
+3869
+3870
+3871
+3872
+3873
+3874
+3875
+3876
+3877
+3878
+3879
+3880
+3881
+3882
+3883
+3884
+3885
+3886
+3887
+3888
+3889
+3890
+3891
+3892
+3893
+3894
+3895
+3896
+3897
+3898
+3899
+3900
+3901
+3902
+3903
+3904
+3905
+3906
+3907
+3908
+3909
+3910
+3911
+3912
+3913
+3914
+3915
+3916
+3917
+3918
+3919
+3920
+3921
+3922
+3923
+3924
+3925
+3926
+3927
+3928
+3929
+3930
+3931
+3932
+3933
+3934
+3935
+3936
+3937
+3938
+3939
+3940
+3941
+3942
+3943
+3944
+3945
+3946
+3947
+3948
+3949
+3950
+3951
+3952
+3953
+3954
+3955
+3956
+3957
+3958
+3959
+3960
+3961
+3962
+3963
+3964
+3965
+3966
+3967
+3968
+3969
+3970
+3971
+3972
+3973
+3974
+3975
+3976
+3977
+3978
+3979
+3980
+3981
+3982
+3983
+3984
+3985
+3986
+3987
+3988
+3989
+3990
+3991
+3992
+3993
+3994
+3995
+3996
+3997
+3998
+3999
+4000
+4001
+4002
+4003
+4004
+4005
+4006
+4007
+4008
+4009
+4010
+4011
+4012
+4013
+4014
+4015
+4016
+4017
+4018
+4019
+4020
+4021
+4022
+4023
+4024
+4025
+4026
+4027
+4028
+4029
+4030
+4031
+4032
+4033
+4034
+4035
+4036
+4037
+4038
+4039
+4040
+4041
+4042
+4043
+4044
+4045
+4046
+4047
+4048
+4049
+4050
+4051
+4052
+4053
+4054
+4055
+4056
+4057
+4058
+4059
+4060
+4061
+4062
+4063
+4064
+4065
+4066
+4067
+4068
+4069
+4070
+4071
+4072
+4073
+4074
+4075
+4076
+4077
+4078
+4079
+4080
+4081
+4082
+4083
+4084
+4085
+4086
+4087
+4088
+4089
+4090
+4091
+4092
+4093
+4094
+4095
+4096
+4097
+4098
+4099
+4100
+4101
+4102
+4103
+4104
+4105
+4106
+4107
+4108
+4109
+4110
+4111
+4112
+4113
+4114
+4115
+4116
+4117
+4118
+4119
+4120
+4121
+4122
+4123
+4124
+4125
+4126
+4127
+4128
+4129
+4130
+4131
+4132
+4133
+4134
+4135
+4136
+4137
+4138
+4139
+4140
+4141
+4142
+4143
+4144
+4145
+4146
+4147
+4148
+4149
+4150
+4151
+4152
+4153
+4154
+4155
+4156
+4157
+4158
+4159
+4160
+4161
+4162
+4163
+4164
+4165
+4166
+4167
+4168
+4169
+4170
+4171
+4172
+4173
+4174
+4175
+4176
+4177
+4178
+4179
+4180
+4181
+4182
+4183
+4184
+4185
+4186
+4187
+4188
+4189
+4190
+4191
+4192
+4193
+4194
+4195
+4196
+4197
+4198
+4199
+4200
+4201
+4202
+4203
+4204
+4205
+4206
+4207
+4208
+4209
+4210
+4211
+4212
+4213
+4214
+4215
+4216
+4217
+4218
+4219
+4220
+4221
+4222
+4223
+4224
+4225
+4226
+4227
+4228
+4229
+4230
+4231
+4232
+4233
+4234
+4235
+4236
+4237
+4238
+4239
+4240
+4241
+4242
+4243
+4244
+4245
+4246
+4247
+4248
+4249
+4250
+4251
+4252
+4253
+4254
+4255
+4256
+4257
+4258
+4259
+4260
+4261
+4262
+4263
+4264
+4265
+4266
+4267
+4268
+4269
+4270
+4271
+4272
+4273
+4274
+4275
+4276
+4277
+4278
+4279
+4280
+4281
+4282
+4283
+4284
+4285
+4286
+4287
+4288
+4289
+4290
+4291
+4292
+4293
+4294
+4295
+4296
+4297
+4298
+4299
+4300
+4301
+4302
+4303
+4304
+4305
+4306
+4307
+4308
+4309
+4310
+4311
+4312
+4313
+4314
+4315
+4316
+4317
+4318
+4319
+4320
+4321
+4322
+4323
+4324
+4325
+4326
+4327
+4328
+4329
+4330
+4331
+4332
+4333
+4334
+4335
+4336
+4337
+4338
+4339
+4340
+4341
+4342
+4343
+4344
+4345
+4346
+4347
+4348
+4349
+4350
+4351
+4352
+4353
+4354
+4355
+4356
+4357
+4358
+4359
+4360
+4361
+4362
+4363
+4364
+4365
+4366
+4367
+4368
+4369
+4370
+4371
+4372
+4373
+4374
+4375
+4376
+4377
+4378
+4379
+4380
+4381
+4382
+4383
+4384
+4385
+4386
+4387
+4388
+4389
+4390
+4391
+4392
+4393
+4394
+4395
+4396
+4397
+4398
+4399
+4400
+4401
+4402
+4403
+4404
+4405
+4406
+4407
+4408
+4409
+4410
+4411
+4412
+4413
+4414
+4415
+4416
+4417
+4418
+4419
+4420
+4421
+4422
+4423
+4424
+4425
+4426
+4427
+4428
+4429
+4430
+4431
+4432
+4433
+4434
+4435
+4436
+4437
+4438
+4439
+4440
+4441
+4442
+4443
+4444
+4445
+4446
+4447
+4448
+4449
+4450
+4451
+4452
+4453
+4454
+4455
+4456
+4457
+4458
+4459
+4460
+4461
+4462
+4463
+4464
+4465
+4466
+4467
+4468
+4469
+4470
+4471
+4472
+4473
+4474
+4475
+4476
+4477
+4478
+4479
+4480
+4481
+4482
+4483
+4484
+4485
+4486
+4487
+4488
+4489
+4490
+4491
+4492
+4493
+4494
+4495
+4496
+4497
+4498
+4499
+4500
+4501
+4502
+4503
+4504
+4505
+4506
+4507
+4508
+4509
+4510
+4511
+4512
+4513
+4514
+4515
+4516
+4517
+4518
+4519
+4520
+4521
+4522
+4523
+4524
+4525
+4526
+4527
+4528
+4529
+4530
+4531
+4532
+4533
+4534
+4535
+4536
+4537
+4538
+4539
+4540
+4541
+4542
+4543
+4544
+4545
+4546
+4547
+4548
+4549
+4550
+4551
+4552
+4553
+4554
+4555
+4556
+4557
+4558
+4559
+4560
+4561
+4562
+4563
+4564
+4565
+4566
+4567
+4568
+4569
+4570
+4571
+4572
+4573
+4574
+4575
+4576
+4577
+4578
+4579
+4580
+4581
+4582
+4583
+4584
+4585
+4586
+4587
+4588
+4589
+4590
+4591
+4592
+4593
+4594
+4595
+4596
+4597
+4598
+4599
+4600
+4601
+4602
+4603
+4604
+4605
+4606
+4607
+4608
+4609
+4610
+4611
+4612
+4613
+4614
+4615
+4616
+4617
+4618
+4619
+4620
+4621
+4622
+4623
+4624
+4625
+4626
+4627
+4628
+4629
+4630
+4631
+4632
+4633
+4634
+4635
+4636
+4637
+4638
+4639
+4640
+4641
+4642
+4643
+4644
+4645
+4646
+4647
+4648
+4649
+4650
+4651
+4652
+4653
+4654
+4655
+4656
+4657
+4658
+4659
+4660
+4661
+4662
+4663
+4664
+4665
+4666
+4667
+4668
+4669
+4670
+4671
+4672
+4673
+4674
+4675
+4676
+4677
+4678
+4679
+4680
+4681
+4682
+4683
+4684
+4685
+4686
+4687
+4688
+4689
+4690
+4691
+4692
+4693
+4694
+4695
+4696
+4697
+4698
+4699
+4700
+4701
+4702
+4703
+4704
+4705
+4706
+4707
+4708
+4709
+4710
+4711
+4712
+4713
+4714
+4715
+4716
+4717
+4718
+4719
+4720
+4721
+4722
+4723
+4724
+4725
+4726
+4727
+4728
+4729
+4730
+4731
+4732
+4733
+4734
+4735
+4736
+4737
+4738
+4739
+4740
+4741
+4742
+4743
+4744
+4745
+4746
+4747
+4748
+4749
+4750
+4751
+4752
+4753
+4754
+4755
+4756
+4757
+4758
+4759
+4760
+4761
+4762
+4763
+4764
+4765
+4766
+4767
+4768
+4769
+4770
+4771
+4772
+4773
+4774
+4775
+4776
+4777
+4778
+4779
+4780
+4781
+4782
+4783
+4784
+4785
+4786
+4787
+4788
+4789
+4790
+4791
+4792
+4793
+4794
+4795
+4796
+4797
+4798
+4799
+4800
+4801
+4802
+4803
+4804
+4805
+4806
+4807
+4808
+4809
+4810
+4811
+4812
+4813
+4814
+4815
+4816
+4817
+4818
+4819
+4820
+4821
+4822
+4823
+4824
+4825
+4826
+4827
+4828
+4829
+4830
+4831
+4832
+4833
+4834
+4835
+4836
+4837
+4838
+4839
+4840
+4841
+4842
+4843
+4844
+4845
+4846
+4847
+4848
+4849
+4850
+4851
+4852
+4853
+4854
+4855
+4856
+4857
+4858
+4859
+4860
+4861
+4862
+4863
+4864
+4865
+4866
+4867
+4868
+4869
+4870
+4871
+4872
+4873
+4874
+4875
+4876
+4877
+4878
+4879
+4880
+4881
+4882
+4883
+4884
+4885
+4886
+4887
+4888
+4889
+4890
+4891
+4892
+4893
+4894
+4895
+4896
+4897
+4898
+4899
+4900
+4901
+4902
+4903
+4904
+4905
+4906
+4907
+4908
+4909
+4910
+4911
+4912
+4913
+4914
+4915
+4916
+4917
+4918
+4919
+4920
+4921
+4922
+4923
+4924
+4925
+4926
+4927
+4928
+4929
+4930
+4931
+4932
+4933
+4934
+4935
+4936
+4937
+4938
+4939
+4940
+4941
+4942
+4943
+4944
+4945
+4946
+4947
+4948
+4949
+4950
+4951
+4952
+4953
+4954
+4955
+4956
+4957
+4958
+4959
+4960
+4961
+4962
+4963
+4964
+4965
+4966
+4967
+4968
+4969
+4970
+4971
+4972
+4973
+4974
+4975
+4976
+4977
+4978
+4979
+4980
+4981
+4982
+4983
+4984
+4985
+4986
+4987
+4988
+4989
+4990
+4991
+4992
+4993
+4994
+4995
+4996
+4997
+4998
+4999
+5000
+5001
+5002
+5003
+5004
+5005
+5006
+5007
+5008
+5009
+5010
+5011
+5012
+5013
+5014
+5015
+5016
+5017
+5018
+5019
+5020
+5021
+5022
+5023
+5024
+5025
+5026
+5027
+5028
+5029
+5030
+5031
+5032
+5033
+5034
+5035
+5036
+5037
+5038
+5039
+5040
+5041
+5042
+5043
+5044
+5045
+5046
+5047
+5048
+5049
+5050
+5051
+5052
+5053
+5054
+5055
+5056
+5057
+5058
+5059
+5060
+5061
+5062
+5063
+5064
+5065
+5066
+5067
+5068
+5069
+5070
+5071
+5072
+5073
+5074
+5075
+5076
+5077
+5078
+5079
+5080
+5081
+5082
+5083
+5084
+5085
+5086
+5087
+5088
+5089
+5090
+5091
+5092
+5093
+5094
+5095
+5096
+5097
+5098
+5099
+5100
+5101
+5102
+5103
+5104
+5105
+5106
+5107
+5108
+5109
+5110
+5111
+5112
+5113
+5114
+5115
+5116
+5117
+5118
+5119
+5120
+5121
+5122
+5123
+5124
+5125
+5126
+5127
+5128
+5129
+5130
+5131
+5132
+5133
+5134
+5135
+5136
+5137
+5138
+5139
+5140
+5141
+5142
+5143
+5144
+5145
+5146
+5147
+5148
+5149
+5150
+5151
+5152
+5153
+5154
+5155
+5156
+5157
+5158
+5159
+5160
+5161
+5162
+5163
+5164
+5165
+5166
+5167
+5168
+5169
+5170
+5171
+5172
+5173
+5174
+5175
+5176
+5177
+5178
+5179
+5180
+5181
+5182
+5183
+5184
+5185
+5186
+5187
+5188
+5189
+5190
+5191
+5192
+5193
+5194
+5195
+5196
+5197
+5198
+5199
+5200
+5201
+5202
+5203
+5204
+5205
+5206
+5207
+5208
+5209
+5210
+5211
+5212
+5213
+5214
+5215
+5216
+5217
+5218
+5219
+5220
+5221
+5222
+5223
+5224
+5225
+5226
+5227
+5228
+5229
+5230
+5231
+5232
+5233
+5234
+5235
+5236
+5237
+5238
+5239
+5240
+5241
+5242
+5243
+5244
+5245
+5246
+5247
+5248
+5249
+5250
+5251
+5252
+5253
+5254
+5255
+5256
+5257
+5258
+5259
+5260
+5261
+5262
+5263
+5264
+5265
+5266
+5267
+5268
+5269
+5270
+5271
+5272
+5273
+5274
+5275
+5276
+5277
+5278
+5279
+5280
+5281
+5282
+5283
+5284
+5285
+5286
+5287
+5288
+5289
+5290
+5291
+5292
+5293
+5294
+5295
+5296
+5297
+5298
+5299
+5300
+5301
+5302
+5303
+5304
+5305
+5306
+5307
+5308
+5309
+5310
+5311
+5312
+5313
+5314
+5315
+5316
+5317
+5318
+5319
+5320
+5321
+5322
+5323
+5324
+5325
+5326
+5327
+5328
+5329
+5330
+5331
+5332
+5333
+5334
+5335
+5336
+5337
+5338
+5339
+5340
+5341
+5342
+5343
+5344
+5345
+5346
+5347
+5348
+5349
+5350
+5351
+5352
+5353
+5354
+5355
+5356
+5357
+5358
+5359
+5360
+5361
+5362
+5363
+5364
+5365
+5366
+5367
+5368
+5369
+5370
+5371
+5372
+5373
+5374
+5375
+5376
+5377
+5378
+5379
+5380
+5381
+5382
+5383
+5384
+5385
+5386
+5387
+5388
+5389
+5390
+5391
+5392
+5393
+5394
+5395
+5396
+5397
+5398
+5399
+5400
+5401
+5402
+5403
+5404
+5405
+5406
+5407
+5408
+5409
+5410
+5411
+5412
+5413
+5414
+5415
+5416
+5417
+5418
+5419
+5420
+5421
+5422
+5423
+5424
+5425
+5426
+5427
+5428
+5429
+5430
+5431
+5432
+5433
+5434
+5435
+5436
+5437
+5438
+5439
+5440
+5441
+5442
+5443
+5444
+5445
+5446
+5447
+5448
+5449
+5450
+5451
+5452
+5453
+5454
+5455
+5456
+5457
+5458
+5459
+5460
+5461
+5462
+5463
+5464
+5465
+5466
+5467
+5468
+5469
+5470
+5471
+5472
+5473
+5474
+5475
+5476
+5477
+5478
+5479
+5480
+5481
+5482
+5483
+5484
+5485
+5486
+5487
+5488
+5489
+5490
+5491
+5492
+5493
+5494
+5495
+5496
+5497
+5498
+5499
+5500
+5501
+5502
+5503
+5504
+5505
+5506
+5507
+5508
+5509
+5510
+5511
+5512
+5513
+5514
+5515
+5516
+5517
+5518
+5519
+5520
+5521
+5522
+5523
+5524
+5525
+5526
+5527
+5528
+5529
+5530
+5531
+5532
+5533
+5534
+5535
+5536
+5537
+5538
+5539
+5540
+5541
+5542
+5543
+5544
+5545
+5546
+5547
+5548
+5549
+5550
+5551
+5552
+5553
+5554
+5555
+5556
+5557
+5558
+5559
+5560
+5561
+5562
+5563
+5564
+5565
+5566
+5567
+5568
+5569
+5570
+5571
+5572
+5573
+5574
+5575
+5576
+5577
+5578
+5579
+5580
+5581
+5582
+5583
+5584
+5585
+5586
+5587
+5588
+5589
+5590
+5591
+5592
+5593
+5594
+5595
+5596
+5597
+5598
+5599
+5600
+5601
+5602
+5603
+5604
+5605
+5606
+5607
+5608
+5609
+5610
+5611
+5612
+5613
+5614
+5615
+5616
+5617
+5618
+5619
+5620
+5621
+5622
+5623
+5624
+5625
+5626
+5627
+5628
+5629
+5630
+5631
+5632
+5633
+5634
+5635
+5636
+5637
+5638
+5639
+5640
+5641
+5642
+5643
+5644
+5645
+5646
+5647
+5648
+5649
+5650
+5651
+5652
+5653
+5654
+5655
+5656
+5657
+5658
+5659
+5660
+5661
+5662
+5663
+5664
+5665
+5666
+5667
+5668
+5669
+5670
+5671
+5672
+5673
+5674
+5675
+5676
+5677
+5678
+5679
+5680
+5681
+5682
+5683
+5684
+5685
+5686
+5687
+5688
+5689
+5690
+5691
+5692
+5693
+5694
+5695
+5696
+5697
+5698
+5699
+5700
+5701
+5702
+5703
+5704
+5705
+5706
+5707
+5708
+5709
+5710
+5711
+5712
+5713
+5714
+5715
+5716
+5717
+5718
+5719
+5720
+5721
+5722
+5723
+5724
+5725
+5726
+5727
+5728
+5729
+5730
+5731
+5732
+5733
+5734
+5735
+5736
+5737
+5738
+5739
+5740
+5741
+5742
+5743
+5744
+5745
+5746
+5747
+5748
+5749
+5750
+5751
+5752
+5753
+5754
+5755
+5756
+5757
+5758
+5759
+5760
+5761
+5762
+5763
+5764
+5765
+5766
+5767
+5768
+5769
+5770
+5771
+5772
+5773
+5774
+5775
+5776
+5777
+5778
+5779
+5780
+5781
+5782
+5783
+5784
+5785
+5786
+5787
+5788
+5789
+5790
+5791
+5792
+5793
+5794
+5795
+5796
+5797
+5798
+5799
+5800
+5801
+5802
+5803
+5804
+5805
+5806
+5807
+5808
+5809
+5810
+5811
+5812
+5813
+5814
+5815
+5816
+5817
+5818
+5819
+5820
+5821
+5822
+5823
+5824
+5825
+5826
+5827
+5828
+5829
+5830
+5831
+5832
+5833
+5834
+5835
+5836
+5837
+5838
+5839
+5840
+5841
+5842
+5843
+5844
+5845
+5846
+5847
+5848
+5849
+5850
+5851
+5852
+5853
+5854
+5855
+5856
+5857
+5858
+5859
+5860
+5861
+5862
+5863
+5864
+5865
+5866
+5867
+5868
+5869
+5870
+5871
+5872
+5873
+5874
+5875
+5876
+5877
+5878
+5879
+5880
+5881
+5882
+5883
+5884
+5885
+5886
+5887
+5888
+5889
+5890
+5891
+5892
+5893
+5894
+5895
+5896
+5897
+5898
+5899
+5900
+5901
+5902
+5903
+5904
+5905
+5906
+5907
+5908
+5909
+5910
+5911
+5912
+5913
+5914
+5915
+5916
+5917
+5918
+5919
+5920
+5921
+5922
+5923
+5924
+5925
+5926
+5927
+5928
+5929
+5930
+5931
+5932
+5933
+5934
+5935
+5936
+5937
+5938
+5939
+5940
+5941
+5942
+5943
+5944
+5945
+5946
+5947
+5948
+5949
+5950
+5951
+5952
+5953
+5954
+5955
+5956
+5957
+5958
+5959
+5960
+5961
+5962
+5963
+5964
+5965
+5966
+5967
+5968
+5969
+5970
+5971
+5972
+5973
+5974
+5975
+5976
+5977
+5978
+5979
+5980
+5981
+5982
+5983
+5984
+5985
+5986
+5987
+5988
+5989
+5990
+5991
+5992
+5993
+5994
+5995
+5996
+5997
+5998
+5999
+6000
+6001
+6002
+6003
+6004
+6005
+6006
+6007
+6008
+6009
+6010
+6011
+6012
+6013
+6014
+6015
+6016
+6017
+6018
+6019
+6020
+6021
+6022
+6023
+6024
+6025
+6026
+6027
+6028
+6029
+6030
+6031
+6032
+6033
+6034
+6035
+6036
+6037
+6038
+6039
+6040
+6041
+6042
+6043
+6044
+6045
+6046
+6047
+6048
+6049
+6050
+6051
+6052
+6053
+6054
+6055
+6056
+6057
+6058
+6059
+6060
+6061
+6062
+6063
+6064
+6065
+6066
+6067
+6068
+6069
+6070
+6071
+6072
+6073
+6074
+6075
+6076
+6077
+6078
+6079
+6080
+6081
+6082
+6083
+6084
+6085
+6086
+6087
+6088
+6089
+6090
+6091
+6092
+6093
+6094
+6095
+6096
+6097
+6098
+6099
+6100
+6101
+6102
+6103
+6104
+6105
+6106
+6107
+6108
+6109
+6110
+6111
+6112
+6113
+6114
+6115
+6116
+6117
+6118
+6119
+6120
+6121
+6122
+6123
+6124
+6125
+6126
+6127
+6128
+6129
+6130
+6131
+6132
+6133
+6134
+6135
+6136
+6137
+6138
+6139
+6140
+6141
+6142
+6143
+6144
+6145
+6146
+6147
+6148
+6149
+6150
+6151
+6152
+6153
+6154
+6155
+6156
+6157
+6158
+6159
+6160
+6161
+6162
+6163
+6164
+6165
+6166
+6167
+6168
+6169
+6170
+6171
+6172
+6173
+6174
+6175
+6176
+6177
+6178
+6179
+6180
+6181
+6182
+6183
+6184
+6185
+6186
+6187
+6188
+6189
+6190
+6191
+6192
+6193
+6194
+6195
+6196
+6197
+6198
+6199
+6200
+6201
+6202
+6203
+6204
+6205
+6206
+6207
+6208
+6209
+6210
+6211
+6212
+6213
+6214
+6215
+6216
+6217
+6218
+6219
+6220
+6221
+6222
+6223
+6224
+6225
+6226
+6227
+6228
+6229
+6230
+6231
+6232
+6233
+6234
+6235
+6236
+6237
+6238
+6239
+6240
+6241
+6242
+6243
+6244
+6245
+6246
+6247
+6248
+6249
+6250
+6251
+6252
+6253
+6254
+6255
+6256
+6257
+6258
+6259
+6260
+6261
+6262
+6263
+6264
+6265
+6266
+6267
+6268
+6269
+6270
+6271
+6272
+6273
+6274
+6275
+6276
+6277
+6278
+6279
+6280
+6281
+6282
+6283
+6284
+6285
+6286
+6287
+6288
+6289
+6290
+6291
+6292
+6293
+6294
+6295
+6296
+6297
+6298
+6299
+6300
+6301
+6302
+6303
+6304
+6305
+6306
+6307
+6308
+6309
+6310
+6311
+6312
+6313
+6314
+6315
+6316
+6317
+6318
+6319
+6320
+6321
+6322
+6323
+6324
+6325
+6326
+6327
+6328
+6329
+6330
+6331
+6332
+6333
+6334
+6335
+6336
+6337
+6338
+6339
+6340
+6341
+6342
+6343
+6344
+6345
+6346
+6347
+6348
+6349
+6350
+6351
+6352
+6353
+6354
+6355
+6356
+6357
+6358
+6359
+6360
+6361
+6362
+6363
+6364
+6365
+6366
+6367
+6368
+6369
+6370
+6371
+6372
+6373
+6374
+6375
+6376
+6377
+6378
+6379
+6380
+6381
+6382
+6383
+6384
+6385
+6386
+
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
+#![cfg_attr(stage0, feature(custom_attribute))]
+#![crate_name = "libc"]
+#![crate_type = "rlib"]
+#![cfg_attr(not(feature = "cargo-build"), unstable(feature = "libc",
+                                                   reason = "use `libc` from crates.io"))]
+#![cfg_attr(not(feature = "cargo-build"), feature(staged_api, core, no_std))]
+#![cfg_attr(not(feature = "cargo-build"), staged_api)]
+#![cfg_attr(not(feature = "cargo-build"), no_std)]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+       html_root_url = "http://doc.rust-lang.org/nightly/",
+       html_playground_url = "http://play.rust-lang.org/")]
+#![cfg_attr(test, feature(test))]
+
+//! Bindings for the C standard library and other platform libraries
+//!
+//! **NOTE:** These are *architecture and libc* specific. On Linux, these
+//! bindings are only correct for glibc.
+//!
+//! This module contains bindings to the C standard library, organized into
+//! modules by their defining standard.  Additionally, it contains some assorted
+//! platform-specific definitions.  For convenience, most functions and types
+//! are reexported, so `use libc::*` will import the available C bindings as
+//! appropriate for the target platform. The exact set of functions available
+//! are platform specific.
+//!
+//! *Note:* Because these definitions are platform-specific, some may not appear
+//! in the generated documentation.
+//!
+//! We consider the following specs reasonably normative with respect to
+//! interoperating with the C standard library (libc/msvcrt):
+//!
+//! * ISO 9899:1990 ('C95', 'ANSI C', 'Standard C'), NA1, 1995.
+//! * ISO 9899:1999 ('C99' or 'C9x').
+//! * ISO 9945:1988 / IEEE 1003.1-1988 ('POSIX.1').
+//! * ISO 9945:2001 / IEEE 1003.1-2001 ('POSIX:2001', 'SUSv3').
+//! * ISO 9945:2008 / IEEE 1003.1-2008 ('POSIX:2008', 'SUSv4').
+//!
+//! Note that any reference to the 1996 revision of POSIX, or any revs between
+//! 1990 (when '88 was approved at ISO) and 2001 (when the next actual
+//! revision-revision happened), are merely additions of other chapters (1b and
+//! 1c) outside the core interfaces.
+//!
+//! Despite having several names each, these are *reasonably* coherent
+//! point-in-time, list-of-definition sorts of specs. You can get each under a
+//! variety of names but will wind up with the same definition in each case.
+//!
+//! See standards(7) in linux-manpages for more details.
+//!
+//! Our interface to these libraries is complicated by the non-universality of
+//! conformance to any of them. About the only thing universally supported is
+//! the first (C95), beyond that definitions quickly become absent on various
+//! platforms.
+//!
+//! We therefore wind up dividing our module-space up (mostly for the sake of
+//! sanity while editing, filling-in-details and eliminating duplication) into
+//! definitions common-to-all (held in modules named c95, c99, posix88, posix01
+//! and posix08) and definitions that appear only on *some* platforms (named
+//! 'extra'). This would be things like significant OSX foundation kit, or Windows
+//! library kernel32.dll, or various fancy glibc, Linux or BSD extensions.
+//!
+//! In addition to the per-platform 'extra' modules, we define a module of
+//! 'common BSD' libc routines that never quite made it into POSIX but show up
+//! in multiple derived systems. This is the 4.4BSD r2 / 1995 release, the final
+//! one from Berkeley after the lawsuits died down and the CSRG dissolved.
+
+#![allow(bad_style, raw_pointer_derive)]
+#![cfg_attr(target_os = "nacl", allow(unused_imports))]
+#[cfg(feature = "cargo-build")] extern crate std as core;
+#[cfg(not(feature = "cargo-build"))] extern crate core;
+
+#[cfg(test)] extern crate std;
+#[cfg(test)] extern crate test;
+
+// Explicit export lists for the intersection (provided here) mean that
+// you can write more-platform-agnostic code if you stick to just these
+// symbols.
+
+pub use types::common::c95::*;
+pub use types::common::c99::*;
+pub use types::common::posix88::*;
+pub use types::os::common::posix01::*;
+pub use types::os::common::bsd44::*;
+pub use types::os::arch::c95::*;
+pub use types::os::arch::c99::*;
+pub use types::os::arch::posix88::*;
+pub use types::os::arch::posix01::*;
+pub use types::os::arch::extra::*;
+
+pub use consts::os::c95::*;
+pub use consts::os::posix88::*;
+pub use consts::os::posix01::*;
+pub use consts::os::bsd44::*;
+pub use consts::os::extra::*;
+
+pub use funcs::c95::ctype::*;
+pub use funcs::c95::stdio::*;
+pub use funcs::c95::stdlib::*;
+pub use funcs::c95::string::*;
+pub use funcs::posix88::fcntl::*;
+pub use funcs::posix88::stat_::*;
+pub use funcs::posix88::stdio::*;
+pub use funcs::posix88::unistd::*;
+
+pub use funcs::bsd43::*;
+
+// But we also reexport most everything
+// if you're interested in writing platform-specific code.
+
+// FIXME: This is a mess, but the design of this entire module needs to be
+// reconsidered, so I'm not inclined to do better right now. As part of
+// #11870 I removed all the pub globs here, leaving explicit reexports
+// of everything that is actually used in-tree.
+//
+// So the following exports don't follow any particular plan.
+
+#[cfg(unix)] pub use consts::os::sysconf::*;
+
+#[cfg(unix)] pub use funcs::posix88::mman::*;
+#[cfg(unix)] pub use funcs::posix88::dirent::*;
+#[cfg(unix)] pub use funcs::posix88::net::*;
+#[cfg(unix)] pub use funcs::posix01::stat_::*;
+#[cfg(unix)] pub use funcs::posix01::unistd::*;
+#[cfg(unix)] pub use funcs::posix01::resource::*;
+
+
+#[cfg(windows)] pub use funcs::extra::kernel32::*;
+#[cfg(windows)] pub use funcs::extra::winsock::*;
+#[cfg(windows)] pub use funcs::extra::msvcrt::*;
+
+// On NaCl, these libraries are static. Thus it would be a Bad Idea to link them
+// in when creating a test crate.
+#[cfg(not(any(windows, target_env = "musl", all(target_os = "nacl", test))))]
+#[link(name = "c")]
+#[link(name = "m")]
+extern {}
+
+#[cfg(all(target_env = "musl", not(test)))]
+#[link(name = "c", kind = "static")]
+extern {}
+
+// libnacl provides functions that require a trip through the IRT to work.
+// ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip
+// to the kernel.
+#[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))]
+#[link(name = "nacl", kind = "static")]
+extern {}
+
+// pnaclmm provides a number of functions that the toolchain's Clang emits calls
+// to when codegening atomic ops. All the functions within wrap various atomic
+// operations.
+// Yes, it could be linked by rustc explicitly, however by linking it here
+// instead we save a bit of time where bins are involved (by not running the
+// optimizations on the whole pnaclmm foreach binary built).
+#[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))]
+#[link(name = "pnaclmm", kind = "static")]
+extern {}
+
+pub mod types {
+
+    // Types tend to vary *per architecture* so we pull their definitions out
+    // into this module.
+
+    // Standard types that are opaque or common, so are not per-target.
+    pub mod common {
+        pub mod c95 {
+            /// Type used to construct void pointers for use with C.
+            ///
+            /// This type is only useful as a pointer target. Do not use it as a
+            /// return type for FFI functions which have the `void` return type in
+            /// C. Use the unit type `()` or omit the return type instead.
+            ///
+            /// For LLVM to recognize the void pointer type and by extension
+            /// functions like malloc(), we need to have it represented as i8* in
+            /// LLVM bitcode. The enum used here ensures this and prevents misuse
+            /// of the "raw" type by only having private variants.. We need two
+            /// variants, because the compiler complains about the repr attribute
+            /// otherwise.
+            #[repr(u8)]
+            pub enum c_void {
+                __variant1,
+                __variant2,
+            }
+
+            pub enum FILE {}
+            pub enum fpos_t {}
+        }
+        pub mod c99 {
+            pub type int8_t = i8;
+            pub type int16_t = i16;
+            pub type int32_t = i32;
+            pub type int64_t = i64;
+            pub type uint8_t = u8;
+            pub type uint16_t = u16;
+            pub type uint32_t = u32;
+            pub type uint64_t = u64;
+        }
+        pub mod posix88 {
+            pub enum DIR {}
+            pub enum dirent_t {}
+        }
+        pub mod posix01 {}
+        pub mod posix08 {}
+        pub mod bsd44 {}
+    }
+
+    // Standard types that are scalar but vary by OS and arch.
+
+    #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))]
+    pub mod os {
+        pub mod common {
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_ulong, size_t,
+                                                 time_t, suseconds_t, c_long};
+
+                #[cfg(not(target_os = "nacl"))]
+                pub type pthread_t = c_ulong;
+                #[cfg(target_os = "nacl")]
+                pub type pthread_t = *mut c_void;
+                pub type rlim_t = u64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct glob_t {
+                    pub gl_pathc: size_t,
+                    pub gl_pathv: *mut *mut c_char,
+                    pub gl_offs:  size_t,
+
+                    pub __unused1: *mut c_void,
+                    pub __unused2: *mut c_void,
+                    pub __unused3: *mut c_void,
+                    pub __unused4: *mut c_void,
+                    pub __unused5: *mut c_void,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timeval {
+                    pub tv_sec: time_t,
+                    pub tv_usec: suseconds_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timespec {
+                    pub tv_sec: time_t,
+                    pub tv_nsec: c_long,
+                }
+
+                pub enum timezone {}
+
+                pub type sighandler_t = size_t;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rlimit {
+                    pub rlim_cur: rlim_t,
+                    pub rlim_max: rlim_t,
+                }
+            }
+
+            pub mod bsd43 {
+                use types::os::common::posix01::timeval;
+                use types::os::arch::c95::c_long;
+                // This is also specified in POSIX 2001, but only has two fields. All implementors
+                // implement BSD 4.3 version.
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rusage {
+                    pub ru_utime: timeval,
+                    pub ru_stime: timeval,
+                    pub ru_maxrss: c_long,
+                    pub ru_ixrss: c_long,
+                    pub ru_idrss: c_long,
+                    pub ru_isrss: c_long,
+                    pub ru_minflt: c_long,
+                    pub ru_majflt: c_long,
+                    pub ru_nswap: c_long,
+                    pub ru_inblock: c_long,
+                    pub ru_oublock: c_long,
+                    pub ru_msgsnd: c_long,
+                    pub ru_msgrcv: c_long,
+                    pub ru_nsignals: c_long,
+                    pub ru_nvcsw: c_long,
+                    pub ru_nivcsw: c_long
+                }
+            }
+
+            pub mod bsd44 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, c_uint};
+
+                pub type socklen_t = u32;
+                pub type sa_family_t = u16;
+                pub type in_port_t = u16;
+                pub type in_addr_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr {
+                    pub sa_family: sa_family_t,
+                    pub sa_data: [u8; 14],
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_storage {
+                    pub ss_family: sa_family_t,
+                    pub __ss_align: isize,
+                    #[cfg(target_pointer_width = "32")]
+                    pub __ss_pad2: [u8; 128 - 2 * 4],
+                    #[cfg(target_pointer_width = "64")]
+                    pub __ss_pad2: [u8; 128 - 2 * 8],
+                }
+                impl ::core::clone::Clone for sockaddr_storage {
+                    fn clone(&self) -> sockaddr_storage { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in {
+                    pub sin_family: sa_family_t,
+                    pub sin_port: in_port_t,
+                    pub sin_addr: in_addr,
+                    pub sin_zero: [u8; 8],
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in_addr {
+                    pub s_addr: in_addr_t,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+                    pub sin6_family: sa_family_t,
+                    pub sin6_port: in_port_t,
+                    pub sin6_flowinfo: u32,
+                    pub sin6_addr: in6_addr,
+                    pub sin6_scope_id: u32,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in6_addr {
+                    pub s6_addr: [u16; 8]
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip_mreq {
+                    pub imr_multiaddr: in_addr,
+                    pub imr_interface: in_addr,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip6_mreq {
+                    pub ipv6mr_multiaddr: in6_addr,
+                    pub ipv6mr_interface: c_uint,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct addrinfo {
+                    pub ai_flags: c_int,
+                    pub ai_family: c_int,
+                    pub ai_socktype: c_int,
+                    pub ai_protocol: c_int,
+                    pub ai_addrlen: socklen_t,
+
+                    #[cfg(target_os = "linux")]
+                    pub ai_addr: *mut sockaddr,
+
+                    #[cfg(target_os = "linux")]
+                    pub ai_canonname: *mut c_char,
+
+                    #[cfg(any(target_os = "android", target_os = "nacl"))]
+                    pub ai_canonname: *mut c_char,
+
+                    #[cfg(any(target_os = "android", target_os = "nacl"))]
+                    pub ai_addr: *mut sockaddr,
+
+                    pub ai_next: *mut addrinfo,
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_un {
+                    pub sun_family: sa_family_t,
+                    pub sun_path: [c_char; 108]
+                }
+                impl ::core::clone::Clone for sockaddr_un {
+                    fn clone(&self) -> sockaddr_un { *self }
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ifaddrs {
+                    pub ifa_next: *mut ifaddrs,
+                    pub ifa_name: *mut c_char,
+                    pub ifa_flags: c_uint,
+                    pub ifa_addr: *mut sockaddr,
+                    pub ifa_netmask: *mut sockaddr,
+                    pub ifa_ifu: *mut sockaddr, // FIXME This should be a union
+                    pub ifa_data: *mut c_void
+                }
+
+            }
+        }
+
+        #[cfg(any(target_arch = "x86",
+                  target_arch = "arm",
+                  target_arch = "mips",
+                  target_arch = "mipsel",
+                  target_arch = "powerpc",
+                  target_arch = "le32"))]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i32;
+                pub type c_ulong = u32;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u32;
+                pub type ptrdiff_t = i32;
+                pub type clock_t = i32;
+                pub type time_t = i32;
+                pub type suseconds_t = i32;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i32;
+                pub type uintptr_t = u32;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            #[cfg(any(target_arch = "x86",
+                      target_arch = "mips",
+                      target_arch = "mipsel",
+                      target_arch = "powerpc",
+                      target_arch = "le32",
+                      all(target_arch = "arm", not(target_os = "android"))))]
+            pub mod posix88 {
+                pub type off_t = i32;
+                pub type dev_t = u64;
+                pub type ino_t = u32;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u32;
+                pub type ssize_t = i32;
+            }
+            #[cfg(all(target_arch = "arm", target_os = "android"))]
+            pub mod posix88 {
+                pub type off_t = i32;
+                pub type dev_t = u32;
+                pub type ino_t = u32;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = i32;
+            }
+            #[cfg(any(target_arch = "x86",
+                      target_arch = "le32",
+                      target_arch = "powerpc",
+                      all(target_arch = "arm", not(target_os = "android"))))]
+            pub mod posix01 {
+                use types::os::arch::c95::{c_short, c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u32;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i32;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub __pad1: c_short,
+                    pub st_ino: ino_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub __pad2: c_short,
+                    pub st_size: off_t,
+                    pub st_blksize: blksize_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub __unused4: c_long,
+                    pub __unused5: c_long,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct pthread_attr_t {
+                    pub __size: [u32; 9]
+                }
+            }
+            #[cfg(all(target_arch = "arm", target_os = "android"))]
+            pub mod posix01 {
+                use types::os::arch::c95::{c_uchar, c_uint, c_ulong, time_t};
+                use types::os::arch::c99::{c_longlong, c_ulonglong};
+                use types::os::arch::posix88::{uid_t, gid_t, ino_t};
+
+                pub type nlink_t = u16;
+                pub type blksize_t = u32;
+                pub type blkcnt_t = u32;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: c_ulonglong,
+                    pub __pad0: [c_uchar; 4],
+                    pub __st_ino: ino_t,
+                    pub st_mode: c_uint,
+                    pub st_nlink: c_uint,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: c_ulonglong,
+                    pub __pad3: [c_uchar; 4],
+                    pub st_size: c_longlong,
+                    pub st_blksize: blksize_t,
+                    pub st_blocks: c_ulonglong,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_ulong,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_ulong,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_ulong,
+                    pub st_ino: c_ulonglong,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct pthread_attr_t {
+                    pub __size: [u32; 9]
+                }
+            }
+            #[cfg(any(target_arch = "mips",
+                      target_arch = "mipsel"))]
+            pub mod posix01 {
+                use types::os::arch::c95::{c_long, c_ulong, time_t};
+                use types::os::arch::posix88::{gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u32;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i32;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: c_ulong,
+                    pub st_pad1: [c_long; 3],
+                    pub st_ino: ino_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: c_ulong,
+                    pub st_pad2: [c_long; 2],
+                    pub st_size: off_t,
+                    pub st_pad3: c_long,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_blksize: blksize_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_pad5: [c_long; 14],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct pthread_attr_t {
+                    pub __size: [u32; 9]
+                }
+            }
+            pub mod posix08 {}
+            pub mod bsd44 {}
+            pub mod extra {
+                use types::os::arch::c95::{c_ushort, c_int, c_uchar};
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_ll {
+                    pub sll_family: c_ushort,
+                    pub sll_protocol: c_ushort,
+                    pub sll_ifindex: c_int,
+                    pub sll_hatype: c_ushort,
+                    pub sll_pkttype: c_uchar,
+                    pub sll_halen: c_uchar,
+                    pub sll_addr: [c_uchar; 8]
+                }
+            }
+
+        }
+
+        #[cfg(any(target_arch = "x86_64",
+                  target_arch = "aarch64"))]
+        pub mod arch {
+            pub mod c95 {
+                #[cfg(not(target_arch = "aarch64"))]
+                pub type c_char = i8;
+                #[cfg(target_arch = "aarch64")]
+                pub type c_char = u8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i64;
+                pub type c_ulong = u64;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u64;
+                pub type ptrdiff_t = i64;
+                pub type clock_t = i64;
+                pub type time_t = i64;
+                pub type suseconds_t = i64;
+                #[cfg(not(target_arch = "aarch64"))]
+                pub type wchar_t = i32;
+                #[cfg(target_arch = "aarch64")]
+                pub type wchar_t = u32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i64;
+                pub type uintptr_t = u64;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                pub type off_t = i64;
+                pub type dev_t = u64;
+                pub type ino_t = u64;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u32;
+                pub type ssize_t = i64;
+            }
+            #[cfg(not(target_arch = "aarch64"))]
+            pub mod posix01 {
+                use types::os::arch::c95::{c_int, c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u64;
+                pub type blksize_t = i64;
+                pub type blkcnt_t = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_ino: ino_t,
+                    pub st_nlink: nlink_t,
+                    pub st_mode: mode_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub __pad0: c_int,
+                    pub st_rdev: dev_t,
+                    pub st_size: off_t,
+                    pub st_blksize: blksize_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub __unused: [c_long; 3],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct pthread_attr_t {
+                    pub __size: [u64; 7]
+                }
+            }
+            #[cfg(target_arch = "aarch64")]
+            pub mod posix01 {
+                use types::os::arch::c95::{c_int, c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u32;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_ino: ino_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub __pad1: dev_t,
+                    pub st_size: off_t,
+                    pub st_blksize: blksize_t,
+                    pub __pad2: c_int,
+                    pub st_blocks: blkcnt_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub __unused: [c_int; 2],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct pthread_attr_t {
+                    pub __size: [u64; 8]
+                }
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+                use types::os::arch::c95::{c_ushort, c_int, c_uchar};
+                #[derive(Copy, Clone)] pub struct sockaddr_ll {
+                    pub sll_family: c_ushort,
+                    pub sll_protocol: c_ushort,
+                    pub sll_ifindex: c_int,
+                    pub sll_hatype: c_ushort,
+                    pub sll_pkttype: c_uchar,
+                    pub sll_halen: c_uchar,
+                    pub sll_addr: [c_uchar; 8]
+                }
+
+            }
+        }
+    }
+
+    #[cfg(target_os = "freebsd")]
+    pub mod os {
+        pub mod common {
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, size_t,
+                                                 time_t, suseconds_t, c_long};
+                use types::os::arch::c99::{uintptr_t};
+
+                pub type pthread_t = uintptr_t;
+                pub type rlim_t = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct glob_t {
+                    pub gl_pathc:  size_t,
+                    pub __unused1: size_t,
+                    pub gl_offs:   size_t,
+                    pub __unused2: c_int,
+                    pub gl_pathv:  *mut *mut c_char,
+
+                    pub __unused3: *mut c_void,
+
+                    pub __unused4: *mut c_void,
+                    pub __unused5: *mut c_void,
+                    pub __unused6: *mut c_void,
+                    pub __unused7: *mut c_void,
+                    pub __unused8: *mut c_void,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timeval {
+                    pub tv_sec: time_t,
+                    pub tv_usec: suseconds_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timespec {
+                    pub tv_sec: time_t,
+                    pub tv_nsec: c_long,
+                }
+
+                pub enum timezone {}
+
+                pub type sighandler_t = size_t;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rlimit {
+                    pub rlim_cur: rlim_t,
+                    pub rlim_max: rlim_t,
+                }
+            }
+
+            pub mod bsd43 {
+                use types::os::common::posix01::timeval;
+                use types::os::arch::c95::c_long;
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rusage {
+                    pub ru_utime: timeval,
+                    pub ru_stime: timeval,
+                    pub ru_maxrss: c_long,
+                    pub ru_ixrss: c_long,
+                    pub ru_idrss: c_long,
+                    pub ru_isrss: c_long,
+                    pub ru_minflt: c_long,
+                    pub ru_majflt: c_long,
+                    pub ru_nswap: c_long,
+                    pub ru_inblock: c_long,
+                    pub ru_oublock: c_long,
+                    pub ru_msgsnd: c_long,
+                    pub ru_msgrcv: c_long,
+                    pub ru_nsignals: c_long,
+                    pub ru_nvcsw: c_long,
+                    pub ru_nivcsw: c_long
+                }
+            }
+
+            pub mod bsd44 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, c_uint};
+
+                pub type socklen_t = u32;
+                pub type sa_family_t = u8;
+                pub type in_port_t = u16;
+                pub type in_addr_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr {
+                    pub sa_len: u8,
+                    pub sa_family: sa_family_t,
+                    pub sa_data: [u8; 14],
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_storage {
+                    pub ss_len: u8,
+                    pub ss_family: sa_family_t,
+                    pub __ss_pad1: [u8; 6],
+                    pub __ss_align: i64,
+                    pub __ss_pad2: [u8; 112],
+                }
+                impl ::core::clone::Clone for sockaddr_storage {
+                    fn clone(&self) -> sockaddr_storage { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in {
+                    pub sin_len: u8,
+                    pub sin_family: sa_family_t,
+                    pub sin_port: in_port_t,
+                    pub sin_addr: in_addr,
+                    pub sin_zero: [u8; 8],
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in_addr {
+                    pub s_addr: in_addr_t,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+                    pub sin6_len: u8,
+                    pub sin6_family: sa_family_t,
+                    pub sin6_port: in_port_t,
+                    pub sin6_flowinfo: u32,
+                    pub sin6_addr: in6_addr,
+                    pub sin6_scope_id: u32,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in6_addr {
+                    pub s6_addr: [u16; 8]
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip_mreq {
+                    pub imr_multiaddr: in_addr,
+                    pub imr_interface: in_addr,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip6_mreq {
+                    pub ipv6mr_multiaddr: in6_addr,
+                    pub ipv6mr_interface: c_uint,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct addrinfo {
+                    pub ai_flags: c_int,
+                    pub ai_family: c_int,
+                    pub ai_socktype: c_int,
+                    pub ai_protocol: c_int,
+                    pub ai_addrlen: socklen_t,
+                    pub ai_canonname: *mut c_char,
+                    pub ai_addr: *mut sockaddr,
+                    pub ai_next: *mut addrinfo,
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_un {
+                    pub sun_len: u8,
+                    pub sun_family: sa_family_t,
+                    pub sun_path: [c_char; 104]
+                }
+                impl ::core::clone::Clone for sockaddr_un {
+                    fn clone(&self) -> sockaddr_un { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ifaddrs {
+                    pub ifa_next: *mut ifaddrs,
+                    pub ifa_name: *mut c_char,
+                    pub ifa_flags: c_uint,
+                    pub ifa_addr: *mut sockaddr,
+                    pub ifa_netmask: *mut sockaddr,
+                    pub ifa_dstaddr: *mut sockaddr,
+                    pub ifa_data: *mut c_void
+                }
+
+
+            }
+        }
+
+        #[cfg(target_arch = "x86_64")]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i64;
+                pub type c_ulong = u64;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u64;
+                pub type ptrdiff_t = i64;
+                pub type clock_t = i32;
+                pub type time_t = i64;
+                pub type suseconds_t = i64;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i64;
+                pub type uintptr_t = u64;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                pub type off_t = i64;
+                pub type dev_t = u32;
+                pub type ino_t = u32;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = i64;
+            }
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::common::c99::{uint8_t, uint32_t, int32_t};
+                use types::os::arch::c95::{c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u16;
+                pub type blksize_t = i64;
+                pub type blkcnt_t = i64;
+                pub type fflags_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_ino: ino_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_size: off_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_blksize: blksize_t,
+                    pub st_flags: fflags_t,
+                    pub st_gen: uint32_t,
+                    pub st_lspare: int32_t,
+                    pub st_birthtime: time_t,
+                    pub st_birthtime_nsec: c_long,
+                    pub __unused: [uint8_t; 2],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                pub type pthread_attr_t = *mut c_void;
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+            }
+        }
+    }
+
+    #[cfg(target_os = "dragonfly")]
+    pub mod os {
+        pub mod common {
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, size_t,
+                                                 time_t, suseconds_t, c_long};
+                use types::os::arch::c99::{uintptr_t};
+
+                pub type pthread_t = uintptr_t;
+                pub type rlim_t = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct glob_t {
+                    pub gl_pathc:  size_t,
+                    pub __unused1: size_t,
+                    pub gl_offs:   size_t,
+                    pub __unused2: c_int,
+                    pub gl_pathv:  *mut *mut c_char,
+
+                    pub __unused3: *mut c_void,
+
+                    pub __unused4: *mut c_void,
+                    pub __unused5: *mut c_void,
+                    pub __unused6: *mut c_void,
+                    pub __unused7: *mut c_void,
+                    pub __unused8: *mut c_void,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timeval {
+                    pub tv_sec: time_t,
+                    pub tv_usec: suseconds_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timespec {
+                    pub tv_sec: time_t,
+                    pub tv_nsec: c_long,
+                }
+
+                pub enum timezone {}
+
+                pub type sighandler_t = size_t;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rlimit {
+                    pub rlim_cur: rlim_t,
+                    pub rlim_max: rlim_t,
+                }
+            }
+
+            pub mod bsd43 {
+                use types::os::common::posix01::timeval;
+                use types::os::arch::c95::c_long;
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rusage {
+                    pub ru_utime: timeval,
+                    pub ru_stime: timeval,
+                    pub ru_maxrss: c_long,
+                    pub ru_ixrss: c_long,
+                    pub ru_idrss: c_long,
+                    pub ru_isrss: c_long,
+                    pub ru_minflt: c_long,
+                    pub ru_majflt: c_long,
+                    pub ru_nswap: c_long,
+                    pub ru_inblock: c_long,
+                    pub ru_oublock: c_long,
+                    pub ru_msgsnd: c_long,
+                    pub ru_msgrcv: c_long,
+                    pub ru_nsignals: c_long,
+                    pub ru_nvcsw: c_long,
+                    pub ru_nivcsw: c_long
+                }
+            }
+
+            pub mod bsd44 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, c_uint};
+
+                pub type socklen_t = u32;
+                pub type sa_family_t = u8;
+                pub type in_port_t = u16;
+                pub type in_addr_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr {
+                    pub sa_len: u8,
+                    pub sa_family: sa_family_t,
+                    pub sa_data: [u8; 14],
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_storage {
+                    pub ss_len: u8,
+                    pub ss_family: sa_family_t,
+                    pub __ss_pad1: [u8; 6],
+                    pub __ss_align: i64,
+                    pub __ss_pad2: [u8; 112],
+                }
+                impl ::core::clone::Clone for sockaddr_storage {
+                    fn clone(&self) -> sockaddr_storage { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in {
+                    pub sin_len: u8,
+                    pub sin_family: sa_family_t,
+                    pub sin_port: in_port_t,
+                    pub sin_addr: in_addr,
+                    pub sin_zero: [u8; 8],
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in_addr {
+                    pub s_addr: in_addr_t,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+                    pub sin6_len: u8,
+                    pub sin6_family: sa_family_t,
+                    pub sin6_port: in_port_t,
+                    pub sin6_flowinfo: u32,
+                    pub sin6_addr: in6_addr,
+                    pub sin6_scope_id: u32,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in6_addr {
+                    pub s6_addr: [u16; 8]
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip_mreq {
+                    pub imr_multiaddr: in_addr,
+                    pub imr_interface: in_addr,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip6_mreq {
+                    pub ipv6mr_multiaddr: in6_addr,
+                    pub ipv6mr_interface: c_uint,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct addrinfo {
+                    pub ai_flags: c_int,
+                    pub ai_family: c_int,
+                    pub ai_socktype: c_int,
+                    pub ai_protocol: c_int,
+                    pub ai_addrlen: socklen_t,
+                    pub ai_canonname: *mut c_char,
+                    pub ai_addr: *mut sockaddr,
+                    pub ai_next: *mut addrinfo,
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_un {
+                    pub sun_len: u8,
+                    pub sun_family: sa_family_t,
+                    pub sun_path: [c_char; 104]
+                }
+                impl ::core::clone::Clone for sockaddr_un {
+                    fn clone(&self) -> sockaddr_un { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ifaddrs {
+                    pub ifa_next: *mut ifaddrs,
+                    pub ifa_name: *mut c_char,
+                    pub ifa_flags: c_uint,
+                    pub ifa_addr: *mut sockaddr,
+                    pub ifa_netmask: *mut sockaddr,
+                    pub ifa_dstaddr: *mut sockaddr,
+                    pub ifa_data: *mut c_void
+                }
+
+            }
+        }
+
+        #[cfg(target_arch = "x86_64")]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i64;
+                pub type c_ulong = u64;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u64;
+                pub type ptrdiff_t = i64;
+                pub type clock_t = i32;
+                pub type time_t = i64;
+                pub type suseconds_t = i64;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i64;
+                pub type uintptr_t = u64;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                pub type off_t = i64;
+                pub type dev_t = u32;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = i64;
+            }
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::common::c99::{uint16_t, uint32_t, int32_t, uint64_t, int64_t};
+                use types::os::arch::c95::{c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = u16;
+                pub type blksize_t = uint32_t;
+                pub type ino_t = uint64_t;
+                pub type blkcnt_t = i64;
+                pub type fflags_t = u32;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_ino: ino_t,
+                    pub st_nlink: nlink_t,
+                    pub st_dev: dev_t,
+                    pub st_mode: mode_t,
+                    pub st_padding1: uint16_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_size: off_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_blksize: blksize_t,
+                    pub st_flags: fflags_t,
+                    pub st_gen: uint32_t,
+                    pub st_lspare: int32_t,
+                    pub st_qspare1: int64_t,
+                    pub st_qspare2: int64_t,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                pub type pthread_attr_t = *mut c_void;
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+            }
+        }
+    }
+
+    #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+    pub mod os {
+        pub mod common {
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, size_t,
+                                                 time_t, suseconds_t, c_long};
+                use types::os::arch::c99::{uintptr_t};
+
+                pub type pthread_t = uintptr_t;
+                pub type rlim_t = u64;
+
+                #[cfg(target_os = "bitrig")]
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct glob_t {
+                    pub gl_pathc:  c_int,
+                    pub gl_matchc: c_int,
+                    pub gl_offs:   c_int,
+                    pub gl_flags:  c_int,
+                    pub gl_pathv:  *mut *mut c_char,
+                    pub __unused1: *mut c_void,
+                    pub __unused2: *mut c_void,
+                    pub __unused3: *mut c_void,
+                    pub __unused4: *mut c_void,
+                    pub __unused5: *mut c_void,
+                    pub __unused6: *mut c_void,
+                    pub __unused7: *mut c_void,
+                }
+
+                #[cfg(target_os = "openbsd")]
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct glob_t {
+                    pub gl_pathc:  c_int,
+                    pub __unused1: c_int,
+                    pub gl_offs:   c_int,
+                    pub __unused2: c_int,
+                    pub gl_pathv:  *mut *mut c_char,
+
+                    pub __unused3: *mut c_void,
+
+                    pub __unused4: *mut c_void,
+                    pub __unused5: *mut c_void,
+                    pub __unused6: *mut c_void,
+                    pub __unused7: *mut c_void,
+                    pub __unused8: *mut c_void,
+                    pub __unused9: *mut c_void,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timeval {
+                    pub tv_sec: time_t,
+                    pub tv_usec: suseconds_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timespec {
+                    pub tv_sec: time_t,
+                    pub tv_nsec: c_long,
+                }
+
+                pub enum timezone {}
+
+                pub type sighandler_t = size_t;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rlimit {
+                    pub rlim_cur: rlim_t,
+                    pub rlim_max: rlim_t,
+                }
+            }
+
+            pub mod bsd43 {
+                use types::os::common::posix01::timeval;
+                use types::os::arch::c95::c_long;
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rusage {
+                    pub ru_utime: timeval,
+                    pub ru_stime: timeval,
+                    pub ru_maxrss: c_long,
+                    pub ru_ixrss: c_long,
+                    pub ru_idrss: c_long,
+                    pub ru_isrss: c_long,
+                    pub ru_minflt: c_long,
+                    pub ru_majflt: c_long,
+                    pub ru_nswap: c_long,
+                    pub ru_inblock: c_long,
+                    pub ru_oublock: c_long,
+                    pub ru_msgsnd: c_long,
+                    pub ru_msgrcv: c_long,
+                    pub ru_nsignals: c_long,
+                    pub ru_nvcsw: c_long,
+                    pub ru_nivcsw: c_long
+                }
+            }
+
+            pub mod bsd44 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, c_uint};
+
+                pub type socklen_t = u32;
+                pub type sa_family_t = u8;
+                pub type in_port_t = u16;
+                pub type in_addr_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr {
+                    pub sa_len: u8,
+                    pub sa_family: sa_family_t,
+                    pub sa_data: [u8; 14],
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_storage {
+                    pub ss_len: u8,
+                    pub ss_family: sa_family_t,
+                    pub __ss_pad1: [u8; 6],
+                    pub __ss_pad2: i64,
+                    pub __ss_pad3: [u8; 240],
+                }
+                impl ::core::clone::Clone for sockaddr_storage {
+                    fn clone(&self) -> sockaddr_storage { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in {
+                    pub sin_len: u8,
+                    pub sin_family: sa_family_t,
+                    pub sin_port: in_port_t,
+                    pub sin_addr: in_addr,
+                    pub sin_zero: [u8; 8],
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in_addr {
+                    pub s_addr: in_addr_t,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+                    pub sin6_len: u8,
+                    pub sin6_family: sa_family_t,
+                    pub sin6_port: in_port_t,
+                    pub sin6_flowinfo: u32,
+                    pub sin6_addr: in6_addr,
+                    pub sin6_scope_id: u32,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in6_addr {
+                    pub s6_addr: [u16; 8]
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip_mreq {
+                    pub imr_multiaddr: in_addr,
+                    pub imr_interface: in_addr,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip6_mreq {
+                    pub ipv6mr_multiaddr: in6_addr,
+                    pub ipv6mr_interface: c_uint,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct addrinfo {
+                    pub ai_flags: c_int,
+                    pub ai_family: c_int,
+                    pub ai_socktype: c_int,
+                    pub ai_protocol: c_int,
+                    pub ai_addrlen: socklen_t,
+                    pub ai_addr: *mut sockaddr,
+                    pub ai_canonname: *mut c_char,
+                    pub ai_next: *mut addrinfo,
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_un {
+                    pub sun_len: u8,
+                    pub sun_family: sa_family_t,
+                    pub sun_path: [c_char; 104]
+                }
+                impl ::core::clone::Clone for sockaddr_un {
+                    fn clone(&self) -> sockaddr_un { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ifaddrs {
+                    pub ifa_next: *mut ifaddrs,
+                    pub ifa_name: *mut c_char,
+                    pub ifa_flags: c_uint,
+                    pub ifa_addr: *mut sockaddr,
+                    pub ifa_netmask: *mut sockaddr,
+                    pub ifa_dstaddr: *mut sockaddr,
+                    pub ifa_data: *mut c_void
+                }
+            }
+        }
+
+        #[cfg(target_arch = "x86_64")]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i64;
+                pub type c_ulong = u64;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u64;
+                pub type ptrdiff_t = i64;
+                pub type clock_t = i64;
+                pub type time_t = i64;
+                pub type suseconds_t = i64;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i64;
+                pub type uintptr_t = u64;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                use types::os::arch::c95::{c_long};
+                pub type off_t = i64;
+                pub type dev_t = i32;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u32;
+                pub type ssize_t = c_long;
+            }
+            pub mod posix01 {
+                use types::common::c95::{c_void};
+                use types::common::c99::{uint32_t, uint64_t};
+                use types::os::arch::c95::{c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t};
+                use types::os::arch::posix88::{mode_t, off_t};
+                use types::os::arch::posix88::{uid_t};
+
+                pub type nlink_t = uint32_t;
+                pub type blksize_t = uint32_t;
+                pub type ino_t = uint64_t;
+                pub type blkcnt_t = i64;
+                pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_mode: mode_t,
+                    pub st_dev: dev_t,
+                    pub st_ino: ino_t,
+                    pub st_nlink: nlink_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_size: off_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_blksize: blksize_t,
+                    pub st_flags: fflags_t,
+                    pub st_gen: uint32_t,
+                    pub st_birthtime: time_t,
+                    pub st_birthtime_nsec: c_long,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                pub type pthread_attr_t = *mut c_void;
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+            }
+        }
+    }
+
+    #[cfg(target_os = "windows")]
+    pub mod os {
+        pub mod common {
+            pub mod posix01 {
+                use types::os::arch::c95::{c_short, time_t, c_long};
+                use types::os::arch::extra::{int64, time64_t};
+                use types::os::arch::posix88::{dev_t, ino_t};
+
+                // pub Note: this is the struct called stat64 in Windows. Not stat,
+                // nor stati64.
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_ino: ino_t,
+                    pub st_mode: u16,
+                    pub st_nlink: c_short,
+                    pub st_uid: c_short,
+                    pub st_gid: c_short,
+                    pub st_rdev: dev_t,
+                    pub st_size: int64,
+                    pub st_atime: time64_t,
+                    pub st_mtime: time64_t,
+                    pub st_ctime: time64_t,
+                }
+
+                // note that this is called utimbuf64 in Windows
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time64_t,
+                    pub modtime: time64_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timeval {
+                    pub tv_sec: c_long,
+                    pub tv_usec: c_long,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timespec {
+                    pub tv_sec: time_t,
+                    pub tv_nsec: c_long,
+                }
+
+                pub enum timezone {}
+            }
+
+            pub mod bsd44 {
+                use types::os::arch::c95::{c_char, c_int, c_uint, size_t};
+                use types::os::arch::c99::uintptr_t;
+
+                pub type SOCKET = uintptr_t;
+                pub type socklen_t = c_int;
+                pub type sa_family_t = u16;
+                pub type in_port_t = u16;
+                pub type in_addr_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr {
+                    pub sa_family: sa_family_t,
+                    pub sa_data: [u8; 14],
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_storage {
+                    pub ss_family: sa_family_t,
+                    pub __ss_pad1: [u8; 6],
+                    pub __ss_align: i64,
+                    pub __ss_pad2: [u8; 112],
+                }
+                impl ::core::clone::Clone for sockaddr_storage {
+                    fn clone(&self) -> sockaddr_storage { *self }
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in {
+                    pub sin_family: sa_family_t,
+                    pub sin_port: in_port_t,
+                    pub sin_addr: in_addr,
+                    pub sin_zero: [u8; 8],
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in_addr {
+                    pub s_addr: in_addr_t,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+                    pub sin6_family: sa_family_t,
+                    pub sin6_port: in_port_t,
+                    pub sin6_flowinfo: u32,
+                    pub sin6_addr: in6_addr,
+                    pub sin6_scope_id: u32,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in6_addr {
+                    pub s6_addr: [u16; 8]
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip_mreq {
+                    pub imr_multiaddr: in_addr,
+                    pub imr_interface: in_addr,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip6_mreq {
+                    pub ipv6mr_multiaddr: in6_addr,
+                    pub ipv6mr_interface: c_uint,
+                }
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct addrinfo {
+                    pub ai_flags: c_int,
+                    pub ai_family: c_int,
+                    pub ai_socktype: c_int,
+                    pub ai_protocol: c_int,
+                    pub ai_addrlen: size_t,
+                    pub ai_canonname: *mut c_char,
+                    pub ai_addr: *mut sockaddr,
+                    pub ai_next: *mut addrinfo,
+                }
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_un {
+                    pub sun_family: sa_family_t,
+                    pub sun_path: [c_char; 108]
+                }
+                impl ::core::clone::Clone for sockaddr_un {
+                    fn clone(&self) -> sockaddr_un { *self }
+                }
+            }
+        }
+
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i32;
+                pub type c_ulong = u32;
+                pub type c_float = f32;
+                pub type c_double = f64;
+
+                #[cfg(target_arch = "x86")]
+                pub type size_t = u32;
+                #[cfg(target_arch = "x86_64")]
+                pub type size_t = u64;
+
+                #[cfg(target_arch = "x86")]
+                pub type ptrdiff_t = i32;
+                #[cfg(target_arch = "x86_64")]
+                pub type ptrdiff_t = i64;
+
+                pub type clock_t = i32;
+
+                #[cfg(target_arch = "x86")]
+                pub type time_t = i32;
+                #[cfg(target_arch = "x86_64")]
+                pub type time_t = i64;
+
+                #[cfg(target_arch = "x86")]
+                pub type suseconds_t = i32;
+                #[cfg(target_arch = "x86_64")]
+                pub type suseconds_t = i64;
+
+                pub type wchar_t = u16;
+            }
+
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+
+                #[cfg(target_arch = "x86")]
+                pub type intptr_t = i32;
+                #[cfg(target_arch = "x86_64")]
+                pub type intptr_t = i64;
+
+                #[cfg(target_arch = "x86")]
+                pub type uintptr_t = u32;
+                #[cfg(target_arch = "x86_64")]
+                pub type uintptr_t = u64;
+
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+
+            pub mod posix88 {
+                pub type off_t = i32;
+                pub type dev_t = u32;
+                pub type ino_t = u16;
+
+                pub type pid_t = u32;
+
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+
+                #[cfg(target_arch = "x86")]
+                pub type ssize_t = i32;
+                #[cfg(target_arch = "x86_64")]
+                pub type ssize_t = i64;
+            }
+
+            pub mod posix01 {
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+                use consts::os::extra::{MAX_PROTOCOL_CHAIN,
+                                              WSAPROTOCOL_LEN};
+                use types::common::c95::c_void;
+                use types::os::arch::c95::{c_char, c_int, c_uint, size_t};
+                use types::os::arch::c95::{c_long, c_ulong};
+                use types::os::arch::c95::{wchar_t};
+                use types::os::arch::c99::{c_ulonglong, c_longlong, uintptr_t};
+
+                pub type BOOL = c_int;
+                pub type BYTE = u8;
+                pub type BOOLEAN = BYTE;
+                pub type CCHAR = c_char;
+                pub type CHAR = c_char;
+
+                pub type DWORD = c_ulong;
+                pub type DWORDLONG = c_ulonglong;
+
+                pub type HANDLE = LPVOID;
+                pub type HINSTANCE = HANDLE;
+                pub type HMODULE = HINSTANCE;
+
+                pub type LONG = c_long;
+                pub type PLONG = *mut c_long;
+
+                #[cfg(target_arch = "x86")]
+                pub type LONG_PTR = c_long;
+                #[cfg(target_arch = "x86_64")]
+                pub type LONG_PTR = i64;
+
+                pub type LARGE_INTEGER = c_longlong;
+                pub type PLARGE_INTEGER = *mut c_longlong;
+
+                pub type LPCWSTR = *const WCHAR;
+                pub type LPCSTR = *const CHAR;
+
+                pub type LPWSTR = *mut WCHAR;
+                pub type LPSTR = *mut CHAR;
+
+                pub type LPWCH = *mut WCHAR;
+                pub type LPCH = *mut CHAR;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct SECURITY_ATTRIBUTES {
+                    pub nLength: DWORD,
+                    pub lpSecurityDescriptor: LPVOID,
+                    pub bInheritHandle: BOOL,
+                }
+                pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
+
+                pub type LPVOID = *mut c_void;
+                pub type LPCVOID = *const c_void;
+                pub type LPBYTE = *mut BYTE;
+                pub type LPWORD = *mut WORD;
+                pub type LPDWORD = *mut DWORD;
+                pub type LPHANDLE = *mut HANDLE;
+
+                pub type LRESULT = LONG_PTR;
+                pub type PBOOL = *mut BOOL;
+                pub type WCHAR = wchar_t;
+                pub type WORD = u16;
+                pub type SIZE_T = size_t;
+
+                pub type time64_t = i64;
+                pub type int64 = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct STARTUPINFO {
+                    pub cb: DWORD,
+                    pub lpReserved: LPWSTR,
+                    pub lpDesktop: LPWSTR,
+                    pub lpTitle: LPWSTR,
+                    pub dwX: DWORD,
+                    pub dwY: DWORD,
+                    pub dwXSize: DWORD,
+                    pub dwYSize: DWORD,
+                    pub dwXCountChars: DWORD,
+                    pub dwYCountCharts: DWORD,
+                    pub dwFillAttribute: DWORD,
+                    pub dwFlags: DWORD,
+                    pub wShowWindow: WORD,
+                    pub cbReserved2: WORD,
+                    pub lpReserved2: LPBYTE,
+                    pub hStdInput: HANDLE,
+                    pub hStdOutput: HANDLE,
+                    pub hStdError: HANDLE,
+                }
+                pub type LPSTARTUPINFO = *mut STARTUPINFO;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct PROCESS_INFORMATION {
+                    pub hProcess: HANDLE,
+                    pub hThread: HANDLE,
+                    pub dwProcessId: DWORD,
+                    pub dwThreadId: DWORD,
+                }
+                pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct SYSTEM_INFO {
+                    pub wProcessorArchitecture: WORD,
+                    pub wReserved: WORD,
+                    pub dwPageSize: DWORD,
+                    pub lpMinimumApplicationAddress: LPVOID,
+                    pub lpMaximumApplicationAddress: LPVOID,
+                    pub dwActiveProcessorMask: uintptr_t,
+                    pub dwNumberOfProcessors: DWORD,
+                    pub dwProcessorType: DWORD,
+                    pub dwAllocationGranularity: DWORD,
+                    pub wProcessorLevel: WORD,
+                    pub wProcessorRevision: WORD,
+                }
+                pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct MEMORY_BASIC_INFORMATION {
+                    pub BaseAddress: LPVOID,
+                    pub AllocationBase: LPVOID,
+                    pub AllocationProtect: DWORD,
+                    pub RegionSize: SIZE_T,
+                    pub State: DWORD,
+                    pub Protect: DWORD,
+                    pub Type: DWORD,
+                }
+                pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct OVERLAPPED {
+                    pub Internal: *mut c_ulong,
+                    pub InternalHigh: *mut c_ulong,
+                    pub Offset: DWORD,
+                    pub OffsetHigh: DWORD,
+                    pub hEvent: HANDLE,
+                }
+
+                pub type LPOVERLAPPED = *mut OVERLAPPED;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct FILETIME {
+                    pub dwLowDateTime: DWORD,
+                    pub dwHighDateTime: DWORD,
+                }
+
+                pub type LPFILETIME = *mut FILETIME;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct GUID {
+                    pub Data1: DWORD,
+                    pub Data2: WORD,
+                    pub Data3: WORD,
+                    pub Data4: [BYTE; 8],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct WSAPROTOCOLCHAIN {
+                    pub ChainLen: c_int,
+                    pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize],
+                }
+
+                pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;
+
+                #[repr(C)]
+                #[derive(Copy)] pub struct WSAPROTOCOL_INFO {
+                    pub dwServiceFlags1: DWORD,
+                    pub dwServiceFlags2: DWORD,
+                    pub dwServiceFlags3: DWORD,
+                    pub dwServiceFlags4: DWORD,
+                    pub dwProviderFlags: DWORD,
+                    pub ProviderId: GUID,
+                    pub dwCatalogEntryId: DWORD,
+                    pub ProtocolChain: WSAPROTOCOLCHAIN,
+                    pub iVersion: c_int,
+                    pub iAddressFamily: c_int,
+                    pub iMaxSockAddr: c_int,
+                    pub iMinSockAddr: c_int,
+                    pub iSocketType: c_int,
+                    pub iProtocol: c_int,
+                    pub iProtocolMaxOffset: c_int,
+                    pub iNetworkByteOrder: c_int,
+                    pub iSecurityScheme: c_int,
+                    pub dwMessageSize: DWORD,
+                    pub dwProviderReserved: DWORD,
+                    pub szProtocol: [u8; WSAPROTOCOL_LEN as usize + 1],
+                }
+                impl ::core::clone::Clone for WSAPROTOCOL_INFO {
+                    fn clone(&self) -> WSAPROTOCOL_INFO { *self }
+                }
+
+                pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
+
+                pub type GROUP = c_uint;
+
+                #[repr(C)]
+                #[derive(Copy)] pub struct WIN32_FIND_DATAW {
+                    pub dwFileAttributes: DWORD,
+                    pub ftCreationTime: FILETIME,
+                    pub ftLastAccessTime: FILETIME,
+                    pub ftLastWriteTime: FILETIME,
+                    pub nFileSizeHigh: DWORD,
+                    pub nFileSizeLow: DWORD,
+                    pub dwReserved0: DWORD,
+                    pub dwReserved1: DWORD,
+                    pub cFileName: [wchar_t; 260], // #define MAX_PATH 260
+                    pub cAlternateFileName: [wchar_t; 14],
+                }
+                impl ::core::clone::Clone for WIN32_FIND_DATAW {
+                    fn clone(&self) -> WIN32_FIND_DATAW { *self }
+                }
+
+                pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
+            }
+        }
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub mod os {
+        pub mod common {
+            pub mod posix01 {
+                use types::common::c95::c_void;
+                use types::os::arch::c95::{c_char, c_int, size_t, time_t};
+                use types::os::arch::c95::{suseconds_t, c_long};
+                use types::os::arch::c99::{uintptr_t};
+
+                pub type pthread_t = uintptr_t;
+                pub type rlim_t = u64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct glob_t {
+                    pub gl_pathc:  size_t,
+                    pub __unused1: c_int,
+                    pub gl_offs:   size_t,
+                    pub __unused2: c_int,
+                    pub gl_pathv:  *mut *mut c_char,
+
+                    pub __unused3: *mut c_void,
+
+                    pub __unused4: *mut c_void,
+                    pub __unused5: *mut c_void,
+                    pub __unused6: *mut c_void,
+                    pub __unused7: *mut c_void,
+                    pub __unused8: *mut c_void,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timeval {
+                    pub tv_sec: time_t,
+                    pub tv_usec: suseconds_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct timespec {
+                    pub tv_sec: time_t,
+                    pub tv_nsec: c_long,
+                }
+
+                pub enum timezone {}
+
+                pub type sighandler_t = size_t;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rlimit {
+                    pub rlim_cur: rlim_t,
+                    pub rlim_max: rlim_t,
+                }
+            }
+
+            pub mod bsd43 {
+                use types::os::common::posix01::timeval;
+                use types::os::arch::c95::c_long;
+                #[repr(C)]
+                #[derive(Copy, Clone)]
+                pub struct rusage {
+                    pub ru_utime: timeval,
+                    pub ru_stime: timeval,
+                    pub ru_maxrss: c_long,
+                    pub ru_ixrss: c_long,
+                    pub ru_idrss: c_long,
+                    pub ru_isrss: c_long,
+                    pub ru_minflt: c_long,
+                    pub ru_majflt: c_long,
+                    pub ru_nswap: c_long,
+                    pub ru_inblock: c_long,
+                    pub ru_oublock: c_long,
+                    pub ru_msgsnd: c_long,
+                    pub ru_msgrcv: c_long,
+                    pub ru_nsignals: c_long,
+                    pub ru_nvcsw: c_long,
+                    pub ru_nivcsw: c_long
+                }
+            }
+
+            pub mod bsd44 {
+                use types::common::c95::{c_void};
+                use types::os::arch::c95::{c_char, c_int, c_uint};
+
+                pub type socklen_t = u32;
+                pub type sa_family_t = u8;
+                pub type in_port_t = u16;
+                pub type in_addr_t = u32;
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr {
+                    pub sa_len: u8,
+                    pub sa_family: sa_family_t,
+                    pub sa_data: [u8; 14],
+                }
+
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_storage {
+                    pub ss_len: u8,
+                    pub ss_family: sa_family_t,
+                    pub __ss_pad1: [u8; 6],
+                    pub __ss_align: i64,
+                    pub __ss_pad2: [u8; 112],
+                }
+                impl ::core::clone::Clone for sockaddr_storage {
+                    fn clone(&self) -> sockaddr_storage { *self }
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in {
+                    pub sin_len: u8,
+                    pub sin_family: sa_family_t,
+                    pub sin_port: in_port_t,
+                    pub sin_addr: in_addr,
+                    pub sin_zero: [u8; 8],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in_addr {
+                    pub s_addr: in_addr_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+                    pub sin6_len: u8,
+                    pub sin6_family: sa_family_t,
+                    pub sin6_port: in_port_t,
+                    pub sin6_flowinfo: u32,
+                    pub sin6_addr: in6_addr,
+                    pub sin6_scope_id: u32,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct in6_addr {
+                    pub s6_addr: [u16; 8]
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip_mreq {
+                    pub imr_multiaddr: in_addr,
+                    pub imr_interface: in_addr,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ip6_mreq {
+                    pub ipv6mr_multiaddr: in6_addr,
+                    pub ipv6mr_interface: c_uint,
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct addrinfo {
+                    pub ai_flags: c_int,
+                    pub ai_family: c_int,
+                    pub ai_socktype: c_int,
+                    pub ai_protocol: c_int,
+                    pub ai_addrlen: socklen_t,
+                    pub ai_canonname: *mut c_char,
+                    pub ai_addr: *mut sockaddr,
+                    pub ai_next: *mut addrinfo,
+                }
+
+                #[repr(C)]
+                #[derive(Copy)] pub struct sockaddr_un {
+                    pub sun_len: u8,
+                    pub sun_family: sa_family_t,
+                    pub sun_path: [c_char; 104]
+                }
+                impl ::core::clone::Clone for sockaddr_un {
+                    fn clone(&self) -> sockaddr_un { *self }
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct ifaddrs {
+                    pub ifa_next: *mut ifaddrs,
+                    pub ifa_name: *mut c_char,
+                    pub ifa_flags: c_uint,
+                    pub ifa_addr: *mut sockaddr,
+                    pub ifa_netmask: *mut sockaddr,
+                    pub ifa_dstaddr: *mut sockaddr,
+                    pub ifa_data: *mut c_void
+                }
+            }
+        }
+
+        #[cfg(any(target_arch = "arm", target_arch = "x86"))]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i32;
+                pub type c_ulong = u32;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u32;
+                pub type ptrdiff_t = i32;
+                pub type clock_t = c_ulong;
+                pub type time_t = c_long;
+                pub type suseconds_t = i32;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i32;
+                pub type uintptr_t = u32;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                use types::os::arch::c95::c_long;
+
+                pub type off_t = i64;
+                pub type dev_t = i32;
+                pub type ino_t = u64;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = c_long;
+            }
+            pub mod posix01 {
+                use types::common::c99::{int32_t, int64_t, uint32_t};
+                use types::os::arch::c95::{c_char, c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t,
+                                                     mode_t, off_t, uid_t};
+
+                pub type nlink_t = u16;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_ino: ino_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_birthtime: time_t,
+                    pub st_birthtime_nsec: c_long,
+                    pub st_size: off_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_blksize: blksize_t,
+                    pub st_flags: uint32_t,
+                    pub st_gen: uint32_t,
+                    pub st_lspare: int32_t,
+                    pub st_qspare: [int64_t; 2],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy)] pub struct pthread_attr_t {
+                    pub __sig: c_long,
+                    pub __opaque: [c_char; 36]
+                }
+                impl ::core::clone::Clone for pthread_attr_t {
+                    fn clone(&self) -> pthread_attr_t { *self }
+                }
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct mach_timebase_info {
+                    pub numer: u32,
+                    pub denom: u32,
+                }
+
+                pub type mach_timebase_info_data_t = mach_timebase_info;
+            }
+        }
+
+        #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
+        pub mod arch {
+            pub mod c95 {
+                pub type c_char = i8;
+                pub type c_schar = i8;
+                pub type c_uchar = u8;
+                pub type c_short = i16;
+                pub type c_ushort = u16;
+                pub type c_int = i32;
+                pub type c_uint = u32;
+                pub type c_long = i64;
+                pub type c_ulong = u64;
+                pub type c_float = f32;
+                pub type c_double = f64;
+                pub type size_t = u64;
+                pub type ptrdiff_t = i64;
+                pub type clock_t = c_ulong;
+                pub type time_t = c_long;
+                pub type suseconds_t = i32;
+                pub type wchar_t = i32;
+            }
+            pub mod c99 {
+                pub type c_longlong = i64;
+                pub type c_ulonglong = u64;
+                pub type intptr_t = i64;
+                pub type uintptr_t = u64;
+                pub type intmax_t = i64;
+                pub type uintmax_t = u64;
+            }
+            pub mod posix88 {
+                use types::os::arch::c95::c_long;
+
+                pub type off_t = i64;
+                pub type dev_t = i32;
+                pub type ino_t = u64;
+                pub type pid_t = i32;
+                pub type uid_t = u32;
+                pub type gid_t = u32;
+                pub type useconds_t = u32;
+                pub type mode_t = u16;
+                pub type ssize_t = c_long;
+            }
+            pub mod posix01 {
+                use types::common::c99::{int32_t, int64_t};
+                use types::common::c99::{uint32_t};
+                use types::os::arch::c95::{c_char, c_long, time_t};
+                use types::os::arch::posix88::{dev_t, gid_t, ino_t};
+                use types::os::arch::posix88::{mode_t, off_t, uid_t};
+
+                pub type nlink_t = u16;
+                pub type blksize_t = i32;
+                pub type blkcnt_t = i64;
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct stat {
+                    pub st_dev: dev_t,
+                    pub st_mode: mode_t,
+                    pub st_nlink: nlink_t,
+                    pub st_ino: ino_t,
+                    pub st_uid: uid_t,
+                    pub st_gid: gid_t,
+                    pub st_rdev: dev_t,
+                    pub st_atime: time_t,
+                    pub st_atime_nsec: c_long,
+                    pub st_mtime: time_t,
+                    pub st_mtime_nsec: c_long,
+                    pub st_ctime: time_t,
+                    pub st_ctime_nsec: c_long,
+                    pub st_birthtime: time_t,
+                    pub st_birthtime_nsec: c_long,
+                    pub st_size: off_t,
+                    pub st_blocks: blkcnt_t,
+                    pub st_blksize: blksize_t,
+                    pub st_flags: uint32_t,
+                    pub st_gen: uint32_t,
+                    pub st_lspare: int32_t,
+                    pub st_qspare: [int64_t; 2],
+                }
+
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct utimbuf {
+                    pub actime: time_t,
+                    pub modtime: time_t,
+                }
+
+                #[repr(C)]
+                #[derive(Copy)] pub struct pthread_attr_t {
+                    pub __sig: c_long,
+                    pub __opaque: [c_char; 56]
+                }
+                impl ::core::clone::Clone for pthread_attr_t {
+                    fn clone(&self) -> pthread_attr_t { *self }
+                }
+            }
+            pub mod posix08 {
+            }
+            pub mod bsd44 {
+            }
+            pub mod extra {
+                #[repr(C)]
+                #[derive(Copy, Clone)] pub struct mach_timebase_info {
+                    pub numer: u32,
+                    pub denom: u32,
+                }
+
+                pub type mach_timebase_info_data_t = mach_timebase_info;
+            }
+        }
+    }
+}
+
+pub mod consts {
+    // Consts tend to vary per OS so we pull their definitions out
+    // into this module.
+
+    #[cfg(target_os = "windows")]
+    pub mod os {
+        pub mod c95 {
+            use types::os::arch::c95::{c_int, c_uint};
+
+            pub const EXIT_FAILURE : c_int = 1;
+            pub const EXIT_SUCCESS : c_int = 0;
+            pub const RAND_MAX : c_int = 32767;
+            pub const EOF : c_int = -1;
+            pub const SEEK_SET : c_int = 0;
+            pub const SEEK_CUR : c_int = 1;
+            pub const SEEK_END : c_int = 2;
+            pub const _IOFBF : c_int = 0;
+            pub const _IONBF : c_int = 4;
+            pub const _IOLBF : c_int = 64;
+            pub const BUFSIZ : c_uint = 512;
+            pub const FOPEN_MAX : c_uint = 20;
+            pub const FILENAME_MAX : c_uint = 260;
+            pub const L_tmpnam : c_uint = 16;
+            pub const TMP_MAX : c_uint = 32767;
+
+            pub const WSAEINTR: c_int = 10004;
+            pub const WSAEBADF: c_int = 10009;
+            pub const WSAEACCES: c_int = 10013;
+            pub const WSAEFAULT: c_int = 10014;
+            pub const WSAEINVAL: c_int = 10022;
+            pub const WSAEMFILE: c_int = 10024;
+            pub const WSAEWOULDBLOCK: c_int = 10035;
+            pub const WSAEINPROGRESS: c_int = 10036;
+            pub const WSAEALREADY: c_int = 10037;
+            pub const WSAENOTSOCK: c_int = 10038;
+            pub const WSAEDESTADDRREQ: c_int = 10039;
+            pub const WSAEMSGSIZE: c_int = 10040;
+            pub const WSAEPROTOTYPE: c_int = 10041;
+            pub const WSAENOPROTOOPT: c_int = 10042;
+            pub const WSAEPROTONOSUPPORT: c_int = 10043;
+            pub const WSAESOCKTNOSUPPORT: c_int = 10044;
+            pub const WSAEOPNOTSUPP: c_int = 10045;
+            pub const WSAEPFNOSUPPORT: c_int = 10046;
+            pub const WSAEAFNOSUPPORT: c_int = 10047;
+            pub const WSAEADDRINUSE: c_int = 10048;
+            pub const WSAEADDRNOTAVAIL: c_int = 10049;
+            pub const WSAENETDOWN: c_int = 10050;
+            pub const WSAENETUNREACH: c_int = 10051;
+            pub const WSAENETRESET: c_int = 10052;
+            pub const WSAECONNABORTED: c_int = 10053;
+            pub const WSAECONNRESET: c_int = 10054;
+            pub const WSAENOBUFS: c_int = 10055;
+            pub const WSAEISCONN: c_int = 10056;
+            pub const WSAENOTCONN: c_int = 10057;
+            pub const WSAESHUTDOWN: c_int = 10058;
+            pub const WSAETOOMANYREFS: c_int = 10059;
+            pub const WSAETIMEDOUT: c_int = 10060;
+            pub const WSAECONNREFUSED: c_int = 10061;
+            pub const WSAELOOP: c_int = 10062;
+            pub const WSAENAMETOOLONG: c_int = 10063;
+            pub const WSAEHOSTDOWN: c_int = 10064;
+            pub const WSAEHOSTUNREACH: c_int = 10065;
+            pub const WSAENOTEMPTY: c_int = 10066;
+            pub const WSAEPROCLIM: c_int = 10067;
+            pub const WSAEUSERS: c_int = 10068;
+            pub const WSAEDQUOT: c_int = 10069;
+            pub const WSAESTALE: c_int = 10070;
+            pub const WSAEREMOTE: c_int = 10071;
+            pub const WSASYSNOTREADY: c_int = 10091;
+            pub const WSAVERNOTSUPPORTED: c_int = 10092;
+            pub const WSANOTINITIALISED: c_int = 10093;
+            pub const WSAEDISCON: c_int = 10101;
+            pub const WSAENOMORE: c_int = 10102;
+            pub const WSAECANCELLED: c_int = 10103;
+            pub const WSAEINVALIDPROCTABLE: c_int = 10104;
+            pub const WSAEINVALIDPROVIDER: c_int = 10105;
+            pub const WSAEPROVIDERFAILEDINIT: c_int = 10106;
+        }
+        pub mod c99 {
+        }
+        pub mod posix88 {
+            use types::os::arch::c95::c_int;
+            use types::os::arch::posix88::mode_t;
+
+            pub const O_RDONLY : c_int = 0;
+            pub const O_WRONLY : c_int = 1;
+            pub const O_RDWR : c_int = 2;
+            pub const O_APPEND : c_int = 8;
+            pub const O_CREAT : c_int = 256;
+            pub const O_EXCL : c_int = 1024;
+            pub const O_TRUNC : c_int = 512;
+            pub const S_IFIFO : c_int = 4096;
+            pub const S_IFCHR : c_int = 8192;
+            pub const S_IFBLK : c_int = 12288;
+            pub const S_IFDIR : c_int = 16384;
+            pub const S_IFREG : c_int = 32768;
+            pub const S_IFLNK : c_int = 40960;
+            pub const S_IFMT : c_int = 61440;
+            pub const S_IEXEC : c_int = 64;
+            pub const S_IWRITE : c_int = 128;
+            pub const S_IREAD : c_int = 256;
+            pub const S_IRWXU : c_int = 448;
+            pub const S_IXUSR : c_int = 64;
+            pub const S_IWUSR : c_int = 128;
+            pub const S_IRUSR : c_int = 256;
+            pub const S_IRWXG : mode_t = 56;
+            pub const S_IXGRP : mode_t = 8;
+            pub const S_IWGRP : mode_t = 16;
+            pub const S_IRGRP : mode_t = 32;
+            pub const S_IRWXO : mode_t = 7;
+            pub const S_IXOTH : mode_t = 1;
+            pub const S_IWOTH : mode_t = 2;
+            pub const S_IROTH : mode_t = 4;
+            pub const F_OK : c_int = 0;
+            pub const R_OK : c_int = 4;
+            pub const W_OK : c_int = 2;
+            pub const X_OK : c_int = 1;
+            pub const STDIN_FILENO : c_int = 0;
+            pub const STDOUT_FILENO : c_int = 1;
+            pub const STDERR_FILENO : c_int = 2;
+        }
+        pub mod posix01 {
+        }
+        pub mod posix08 {
+        }
+        pub mod bsd44 {
+            use types::os::arch::c95::c_int;
+
+            pub const AF_INET: c_int = 2;
+            pub const AF_INET6: c_int = 23;
+            pub const SOCK_STREAM: c_int = 1;
+            pub const SOCK_DGRAM: c_int = 2;
+            pub const SOCK_RAW: c_int = 3;
+            pub const IPPROTO_TCP: c_int = 6;
+            pub const IPPROTO_IP: c_int = 0;
+            pub const IPPROTO_IPV6: c_int = 41;
+            pub const IP_MULTICAST_TTL: c_int = 10;
+            pub const IP_MULTICAST_LOOP: c_int = 11;
+            pub const IP_ADD_MEMBERSHIP: c_int = 12;
+            pub const IP_DROP_MEMBERSHIP: c_int = 13;
+            pub const IPV6_ADD_MEMBERSHIP: c_int = 5;
+            pub const IPV6_DROP_MEMBERSHIP: c_int = 6;
+            pub const IP_TTL: c_int = 4;
+            pub const IP_HDRINCL: c_int = 2;
+
+            pub const TCP_NODELAY: c_int = 0x0001;
+            pub const SOL_SOCKET: c_int = 0xffff;
+
+            pub const SO_DEBUG: c_int = 0x0001;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
+            pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
+
+            pub const IFF_LOOPBACK: c_int = 4;
+
+            pub const SHUT_RD: c_int = 0;
+            pub const SHUT_WR: c_int = 1;
+            pub const SHUT_RDWR: c_int = 2;
+        }
+        pub mod extra {
+            use types::os::common::bsd44::SOCKET;
+            use types::os::arch::c95::{c_int, c_long};
+            use types::os::arch::extra::{WORD, DWORD, BOOL, HANDLE};
+
+            pub const TRUE : BOOL = 1;
+            pub const FALSE : BOOL = 0;
+
+            pub const O_TEXT : c_int = 16384;
+            pub const O_BINARY : c_int = 32768;
+            pub const O_NOINHERIT: c_int = 128;
+
+            pub const ERROR_SUCCESS : c_int = 0;
+            pub const ERROR_INVALID_FUNCTION: c_int = 1;
+            pub const ERROR_FILE_NOT_FOUND: c_int = 2;
+            pub const ERROR_ACCESS_DENIED: c_int = 5;
+            pub const ERROR_INVALID_HANDLE : c_int = 6;
+            pub const ERROR_BROKEN_PIPE: c_int = 109;
+            pub const ERROR_DISK_FULL : c_int = 112;
+            pub const ERROR_CALL_NOT_IMPLEMENTED : c_int = 120;
+            pub const ERROR_INSUFFICIENT_BUFFER : c_int = 122;
+            pub const ERROR_INVALID_NAME : c_int = 123;
+            pub const ERROR_ALREADY_EXISTS : c_int = 183;
+            pub const ERROR_PIPE_BUSY: c_int = 231;
+            pub const ERROR_NO_DATA: c_int = 232;
+            pub const ERROR_INVALID_ADDRESS : c_int = 487;
+            pub const ERROR_PIPE_CONNECTED: c_int = 535;
+            pub const ERROR_NOTHING_TO_TERMINATE: c_int = 758;
+            pub const ERROR_OPERATION_ABORTED: c_int = 995;
+            pub const ERROR_IO_PENDING: c_int = 997;
+            pub const ERROR_FILE_INVALID : c_int = 1006;
+            pub const ERROR_NOT_FOUND: c_int = 1168;
+            pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+
+            pub const DELETE : DWORD = 0x00010000;
+            pub const READ_CONTROL : DWORD = 0x00020000;
+            pub const SYNCHRONIZE : DWORD = 0x00100000;
+            pub const WRITE_DAC : DWORD = 0x00040000;
+            pub const WRITE_OWNER : DWORD = 0x00080000;
+
+            pub const PROCESS_CREATE_PROCESS : DWORD = 0x0080;
+            pub const PROCESS_CREATE_THREAD : DWORD = 0x0002;
+            pub const PROCESS_DUP_HANDLE : DWORD = 0x0040;
+            pub const PROCESS_QUERY_INFORMATION : DWORD = 0x0400;
+            pub const PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000;
+            pub const PROCESS_SET_INFORMATION : DWORD = 0x0200;
+            pub const PROCESS_SET_QUOTA : DWORD = 0x0100;
+            pub const PROCESS_SUSPEND_RESUME : DWORD = 0x0800;
+            pub const PROCESS_TERMINATE : DWORD = 0x0001;
+            pub const PROCESS_VM_OPERATION : DWORD = 0x0008;
+            pub const PROCESS_VM_READ : DWORD = 0x0010;
+            pub const PROCESS_VM_WRITE : DWORD = 0x0020;
+
+            pub const STARTF_FORCEONFEEDBACK : DWORD = 0x00000040;
+            pub const STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080;
+            pub const STARTF_PREVENTPINNING : DWORD = 0x00002000;
+            pub const STARTF_RUNFULLSCREEN : DWORD = 0x00000020;
+            pub const STARTF_TITLEISAPPID : DWORD = 0x00001000;
+            pub const STARTF_TITLEISLINKNAME : DWORD = 0x00000800;
+            pub const STARTF_USECOUNTCHARS : DWORD = 0x00000008;
+            pub const STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010;
+            pub const STARTF_USEHOTKEY : DWORD = 0x00000200;
+            pub const STARTF_USEPOSITION : DWORD = 0x00000004;
+            pub const STARTF_USESHOWWINDOW : DWORD = 0x00000001;
+            pub const STARTF_USESIZE : DWORD = 0x00000002;
+            pub const STARTF_USESTDHANDLES : DWORD = 0x00000100;
+
+            pub const WAIT_ABANDONED : DWORD = 0x00000080;
+            pub const WAIT_OBJECT_0 : DWORD = 0x00000000;
+            pub const WAIT_TIMEOUT : DWORD = 0x00000102;
+            pub const WAIT_FAILED : DWORD = !0;
+
+            pub const DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001;
+            pub const DUPLICATE_SAME_ACCESS : DWORD = 0x00000002;
+
+            pub const INFINITE : DWORD = !0;
+            pub const STILL_ACTIVE : DWORD = 259;
+
+            pub const MEM_COMMIT : DWORD = 0x00001000;
+            pub const MEM_RESERVE : DWORD = 0x00002000;
+            pub const MEM_DECOMMIT : DWORD = 0x00004000;
+            pub const MEM_RELEASE : DWORD = 0x00008000;
+            pub const MEM_RESET : DWORD = 0x00080000;
+            pub const MEM_RESET_UNDO : DWORD = 0x1000000;
+            pub const MEM_LARGE_PAGES : DWORD = 0x20000000;
+            pub const MEM_PHYSICAL : DWORD = 0x00400000;
+            pub const MEM_TOP_DOWN : DWORD = 0x00100000;
+            pub const MEM_WRITE_WATCH : DWORD = 0x00200000;
+
+            pub const PAGE_EXECUTE : DWORD = 0x10;
+            pub const PAGE_EXECUTE_READ : DWORD = 0x20;
+            pub const PAGE_EXECUTE_READWRITE : DWORD = 0x40;
+            pub const PAGE_EXECUTE_WRITECOPY : DWORD = 0x80;
+            pub const PAGE_NOACCESS : DWORD = 0x01;
+            pub const PAGE_READONLY : DWORD = 0x02;
+            pub const PAGE_READWRITE : DWORD = 0x04;
+            pub const PAGE_WRITECOPY : DWORD = 0x08;
+            pub const PAGE_GUARD : DWORD = 0x100;
+            pub const PAGE_NOCACHE : DWORD = 0x200;
+            pub const PAGE_WRITECOMBINE : DWORD = 0x400;
+
+            pub const SEC_COMMIT : DWORD = 0x8000000;
+            pub const SEC_IMAGE : DWORD = 0x1000000;
+            pub const SEC_IMAGE_NO_EXECUTE : DWORD = 0x11000000;
+            pub const SEC_LARGE_PAGES : DWORD = 0x80000000;
+            pub const SEC_NOCACHE : DWORD = 0x10000000;
+            pub const SEC_RESERVE : DWORD = 0x4000000;
+            pub const SEC_WRITECOMBINE : DWORD = 0x40000000;
+
+            pub const FILE_MAP_ALL_ACCESS : DWORD = 0xf001f;
+            pub const FILE_MAP_READ : DWORD = 0x4;
+            pub const FILE_MAP_WRITE : DWORD = 0x2;
+            pub const FILE_MAP_COPY : DWORD = 0x1;
+            pub const FILE_MAP_EXECUTE : DWORD = 0x20;
+
+            pub const PROCESSOR_ARCHITECTURE_INTEL : WORD = 0;
+            pub const PROCESSOR_ARCHITECTURE_ARM : WORD = 5;
+            pub const PROCESSOR_ARCHITECTURE_IA64 : WORD = 6;
+            pub const PROCESSOR_ARCHITECTURE_AMD64 : WORD = 9;
+            pub const PROCESSOR_ARCHITECTURE_UNKNOWN : WORD = 0xffff;
+
+            pub const MOVEFILE_COPY_ALLOWED: DWORD = 2;
+            pub const MOVEFILE_CREATE_HARDLINK: DWORD = 16;
+            pub const MOVEFILE_DELAY_UNTIL_REBOOT: DWORD = 4;
+            pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE: DWORD = 32;
+            pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1;
+            pub const MOVEFILE_WRITE_THROUGH: DWORD = 8;
+
+            pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 1;
+
+            pub const FILE_SHARE_DELETE: DWORD = 0x4;
+            pub const FILE_SHARE_READ: DWORD = 0x1;
+            pub const FILE_SHARE_WRITE: DWORD = 0x2;
+
+            pub const CREATE_ALWAYS: DWORD = 2;
+            pub const CREATE_NEW: DWORD = 1;
+            pub const OPEN_ALWAYS: DWORD = 4;
+            pub const OPEN_EXISTING: DWORD = 3;
+            pub const TRUNCATE_EXISTING: DWORD = 5;
+
+            pub const FILE_APPEND_DATA: DWORD = 0x00000004;
+            pub const FILE_READ_DATA: DWORD = 0x00000001;
+            pub const FILE_WRITE_DATA: DWORD = 0x00000002;
+
+            pub const FILE_ATTRIBUTE_ARCHIVE: DWORD = 0x20;
+            pub const FILE_ATTRIBUTE_COMPRESSED: DWORD = 0x800;
+            pub const FILE_ATTRIBUTE_DEVICE: DWORD = 0x40;
+            pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
+            pub const FILE_ATTRIBUTE_ENCRYPTED: DWORD = 0x4000;
+            pub const FILE_ATTRIBUTE_HIDDEN: DWORD = 0x2;
+            pub const FILE_ATTRIBUTE_INTEGRITY_STREAM: DWORD = 0x8000;
+            pub const FILE_ATTRIBUTE_NORMAL: DWORD = 0x80;
+            pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: DWORD = 0x2000;
+            pub const FILE_ATTRIBUTE_NO_SCRUB_DATA: DWORD = 0x20000;
+            pub const FILE_ATTRIBUTE_OFFLINE: DWORD = 0x1000;
+            pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1;
+            pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400;
+            pub const FILE_ATTRIBUTE_SPARSE_FILE: DWORD = 0x200;
+            pub const FILE_ATTRIBUTE_SYSTEM: DWORD = 0x4;
+            pub const FILE_ATTRIBUTE_TEMPORARY: DWORD = 0x100;
+            pub const FILE_ATTRIBUTE_VIRTUAL: DWORD = 0x10000;
+
+            pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000;
+            pub const FILE_FLAG_DELETE_ON_CLOSE: DWORD = 0x04000000;
+            pub const FILE_FLAG_NO_BUFFERING: DWORD = 0x20000000;
+            pub const FILE_FLAG_OPEN_NO_RECALL: DWORD = 0x00100000;
+            pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000;
+            pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000;
+            pub const FILE_FLAG_POSIX_SEMANTICS: DWORD = 0x0100000;
+            pub const FILE_FLAG_RANDOM_ACCESS: DWORD = 0x10000000;
+            pub const FILE_FLAG_SESSION_AWARE: DWORD = 0x00800000;
+            pub const FILE_FLAG_SEQUENTIAL_SCAN: DWORD = 0x08000000;
+            pub const FILE_FLAG_WRITE_THROUGH: DWORD = 0x80000000;
+            pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
+
+            pub const FILE_NAME_NORMALIZED: DWORD = 0x0;
+            pub const FILE_NAME_OPENED: DWORD = 0x8;
+
+            pub const VOLUME_NAME_DOS: DWORD = 0x0;
+            pub const VOLUME_NAME_GUID: DWORD = 0x1;
+            pub const VOLUME_NAME_NONE: DWORD = 0x4;
+            pub const VOLUME_NAME_NT: DWORD = 0x2;
+
+            pub const GENERIC_READ: DWORD = 0x80000000;
+            pub const GENERIC_WRITE: DWORD = 0x40000000;
+            pub const GENERIC_EXECUTE: DWORD = 0x20000000;
+            pub const GENERIC_ALL: DWORD = 0x10000000;
+            pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+            pub const FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
+
+            pub const STANDARD_RIGHTS_READ: DWORD = 0x20000;
+            pub const STANDARD_RIGHTS_WRITE: DWORD = 0x20000;
+            pub const FILE_WRITE_EA: DWORD = 0x00000010;
+            pub const FILE_READ_EA: DWORD = 0x00000008;
+            pub const FILE_GENERIC_READ: DWORD =
+                STANDARD_RIGHTS_READ | FILE_READ_DATA |
+                FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE;
+            pub const FILE_GENERIC_WRITE: DWORD =
+                STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA |
+                FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA |
+                SYNCHRONIZE;
+
+            pub const FILE_BEGIN: DWORD = 0;
+            pub const FILE_CURRENT: DWORD = 1;
+            pub const FILE_END: DWORD = 2;
+
+            pub const MAX_PROTOCOL_CHAIN: DWORD = 7;
+            pub const WSAPROTOCOL_LEN: DWORD = 255;
+            pub const INVALID_SOCKET: SOCKET = !0;
+
+            pub const DETACHED_PROCESS: DWORD = 0x00000008;
+            pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200;
+            pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400;
+
+            pub const PIPE_ACCESS_DUPLEX: DWORD = 0x00000003;
+            pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+            pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
+            pub const PIPE_TYPE_BYTE: DWORD = 0x00000000;
+            pub const PIPE_TYPE_MESSAGE: DWORD = 0x00000004;
+            pub const PIPE_READMODE_BYTE: DWORD = 0x00000000;
+            pub const PIPE_READMODE_MESSAGE: DWORD = 0x00000002;
+            pub const PIPE_WAIT: DWORD = 0x00000000;
+            pub const PIPE_NOWAIT: DWORD = 0x00000001;
+            pub const PIPE_ACCEPT_REMOTE_CLIENTS: DWORD = 0x00000000;
+            pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008;
+            pub const PIPE_UNLIMITED_INSTANCES: DWORD = 255;
+
+            pub const IPPROTO_RAW: c_int = 255;
+
+            pub const FIONBIO: c_long = -0x7FFB9982;
+        }
+        pub mod sysconf {
+        }
+    }
+
+
+    #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))]
+    pub mod os {
+        pub mod c95 {
+            use types::os::arch::c95::{c_int, c_uint};
+
+            pub const EXIT_FAILURE : c_int = 1;
+            pub const EXIT_SUCCESS : c_int = 0;
+            pub const RAND_MAX : c_int = 2147483647;
+            pub const EOF : c_int = -1;
+            pub const SEEK_SET : c_int = 0;
+            pub const SEEK_CUR : c_int = 1;
+            pub const SEEK_END : c_int = 2;
+            pub const _IOFBF : c_int = 0;
+            pub const _IONBF : c_int = 2;
+            pub const _IOLBF : c_int = 1;
+            pub const BUFSIZ : c_uint = 8192;
+            pub const FOPEN_MAX : c_uint = 16;
+            pub const FILENAME_MAX : c_uint = 4096;
+            pub const L_tmpnam : c_uint = 20;
+            pub const TMP_MAX : c_uint = 238328;
+        }
+        pub mod c99 {
+        }
+        #[cfg(any(target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "arm",
+                  target_arch = "aarch64",
+                  target_arch = "le32",
+                  target_arch = "powerpc"))]
+        pub mod posix88 {
+            use types::os::arch::c95::c_int;
+            use types::common::c95::c_void;
+            use types::os::arch::posix88::mode_t;
+
+            pub const O_RDONLY : c_int = 0;
+            pub const O_WRONLY : c_int = 1;
+            pub const O_RDWR : c_int = 2;
+            pub const O_APPEND : c_int = 1024;
+            pub const O_CREAT : c_int = 64;
+            pub const O_EXCL : c_int = 128;
+            pub const O_NOCTTY : c_int = 256;
+            pub const O_TRUNC : c_int = 512;
+            pub const S_IFIFO : mode_t = 4096;
+            pub const S_IFCHR : mode_t = 8192;
+            pub const S_IFBLK : mode_t = 24576;
+            pub const S_IFDIR : mode_t = 16384;
+            pub const S_IFREG : mode_t = 32768;
+            pub const S_IFLNK : mode_t = 40960;
+            pub const S_IFMT : mode_t = 61440;
+            pub const S_IEXEC : mode_t = 64;
+            pub const S_IWRITE : mode_t = 128;
+            pub const S_IREAD : mode_t = 256;
+            pub const S_IRWXU : mode_t = 448;
+            pub const S_IXUSR : mode_t = 64;
+            pub const S_IWUSR : mode_t = 128;
+            pub const S_IRUSR : mode_t = 256;
+            pub const S_IRWXG : mode_t = 56;
+            pub const S_IXGRP : mode_t = 8;
+            pub const S_IWGRP : mode_t = 16;
+            pub const S_IRGRP : mode_t = 32;
+            pub const S_IRWXO : mode_t = 7;
+            pub const S_IXOTH : mode_t = 1;
+            pub const S_IWOTH : mode_t = 2;
+            pub const S_IROTH : mode_t = 4;
+            pub const F_OK : c_int = 0;
+            pub const R_OK : c_int = 4;
+            pub const W_OK : c_int = 2;
+            pub const X_OK : c_int = 1;
+            pub const STDIN_FILENO : c_int = 0;
+            pub const STDOUT_FILENO : c_int = 1;
+            pub const STDERR_FILENO : c_int = 2;
+            pub const F_LOCK : c_int = 1;
+            pub const F_TEST : c_int = 3;
+            pub const F_TLOCK : c_int = 2;
+            pub const F_ULOCK : c_int = 0;
+            pub const SIGHUP : c_int = 1;
+            pub const SIGINT : c_int = 2;
+            pub const SIGQUIT : c_int = 3;
+            pub const SIGILL : c_int = 4;
+            pub const SIGABRT : c_int = 6;
+            pub const SIGFPE : c_int = 8;
+            pub const SIGKILL : c_int = 9;
+            pub const SIGSEGV : c_int = 11;
+            pub const SIGPIPE : c_int = 13;
+            pub const SIGALRM : c_int = 14;
+            pub const SIGTERM : c_int = 15;
+
+            pub const PROT_NONE : c_int = 0;
+            pub const PROT_READ : c_int = 1;
+            pub const PROT_WRITE : c_int = 2;
+            pub const PROT_EXEC : c_int = 4;
+
+            pub const MAP_FILE : c_int = 0x0000;
+            pub const MAP_SHARED : c_int = 0x0001;
+            pub const MAP_PRIVATE : c_int = 0x0002;
+            pub const MAP_FIXED : c_int = 0x0010;
+            pub const MAP_ANON : c_int = 0x0020;
+
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
+
+            pub const MCL_CURRENT : c_int = 0x0001;
+            pub const MCL_FUTURE : c_int = 0x0002;
+
+            pub const MS_ASYNC : c_int = 0x0001;
+            pub const MS_INVALIDATE : c_int = 0x0002;
+            pub const MS_SYNC : c_int = 0x0004;
+
+            pub const EPERM : c_int = 1;
+            pub const ENOENT : c_int = 2;
+            pub const ESRCH : c_int = 3;
+            pub const EINTR : c_int = 4;
+            pub const EIO : c_int = 5;
+            pub const ENXIO : c_int = 6;
+            pub const E2BIG : c_int = 7;
+            pub const ENOEXEC : c_int = 8;
+            pub const EBADF : c_int = 9;
+            pub const ECHILD : c_int = 10;
+            pub const EAGAIN : c_int = 11;
+            pub const ENOMEM : c_int = 12;
+            pub const EACCES : c_int = 13;
+            pub const EFAULT : c_int = 14;
+            pub const ENOTBLK : c_int = 15;
+            pub const EBUSY : c_int = 16;
+            pub const EEXIST : c_int = 17;
+            pub const EXDEV : c_int = 18;
+            pub const ENODEV : c_int = 19;
+            pub const ENOTDIR : c_int = 20;
+            pub const EISDIR : c_int = 21;
+            pub const EINVAL : c_int = 22;
+            pub const ENFILE : c_int = 23;
+            pub const EMFILE : c_int = 24;
+            pub const ENOTTY : c_int = 25;
+            pub const ETXTBSY : c_int = 26;
+            pub const EFBIG : c_int = 27;
+            pub const ENOSPC : c_int = 28;
+            pub const ESPIPE : c_int = 29;
+            pub const EROFS : c_int = 30;
+            pub const EMLINK : c_int = 31;
+            pub const EPIPE : c_int = 32;
+            pub const EDOM : c_int = 33;
+            pub const ERANGE : c_int = 34;
+
+            pub const EDEADLK: c_int = 35;
+            pub const ENAMETOOLONG: c_int = 36;
+            pub const ENOLCK: c_int = 37;
+            pub const ENOSYS: c_int = 38;
+            pub const ENOTEMPTY: c_int = 39;
+            pub const ELOOP: c_int = 40;
+            pub const EWOULDBLOCK: c_int = EAGAIN;
+            pub const ENOMSG: c_int = 42;
+            pub const EIDRM: c_int = 43;
+            pub const ECHRNG: c_int = 44;
+            pub const EL2NSYNC: c_int = 45;
+            pub const EL3HLT: c_int = 46;
+            pub const EL3RST: c_int = 47;
+            pub const ELNRNG: c_int = 48;
+            pub const EUNATCH: c_int = 49;
+            pub const ENOCSI: c_int = 50;
+            pub const EL2HLT: c_int = 51;
+            pub const EBADE: c_int = 52;
+            pub const EBADR: c_int = 53;
+            pub const EXFULL: c_int = 54;
+            pub const ENOANO: c_int = 55;
+            pub const EBADRQC: c_int = 56;
+            pub const EBADSLT: c_int = 57;
+
+            pub const EDEADLOCK: c_int = EDEADLK;
+
+            pub const EBFONT: c_int = 59;
+            pub const ENOSTR: c_int = 60;
+            pub const ENODATA: c_int = 61;
+            pub const ETIME: c_int = 62;
+            pub const ENOSR: c_int = 63;
+            pub const ENONET: c_int = 64;
+            pub const ENOPKG: c_int = 65;
+            pub const EREMOTE: c_int = 66;
+            pub const ENOLINK: c_int = 67;
+            pub const EADV: c_int = 68;
+            pub const ESRMNT: c_int = 69;
+            pub const ECOMM: c_int = 70;
+            pub const EPROTO: c_int = 71;
+            pub const EMULTIHOP: c_int = 72;
+            pub const EDOTDOT: c_int = 73;
+            pub const EBADMSG: c_int = 74;
+            pub const EOVERFLOW: c_int = 75;
+            pub const ENOTUNIQ: c_int = 76;
+            pub const EBADFD: c_int = 77;
+            pub const EREMCHG: c_int = 78;
+            pub const ELIBACC: c_int = 79;
+            pub const ELIBBAD: c_int = 80;
+            pub const ELIBSCN: c_int = 81;
+            pub const ELIBMAX: c_int = 82;
+            pub const ELIBEXEC: c_int = 83;
+            pub const EILSEQ: c_int = 84;
+            pub const ERESTART: c_int = 85;
+            pub const ESTRPIPE: c_int = 86;
+            pub const EUSERS: c_int = 87;
+            pub const ENOTSOCK: c_int = 88;
+            pub const EDESTADDRREQ: c_int = 89;
+            pub const EMSGSIZE: c_int = 90;
+            pub const EPROTOTYPE: c_int = 91;
+            pub const ENOPROTOOPT: c_int = 92;
+            pub const EPROTONOSUPPORT: c_int = 93;
+            pub const ESOCKTNOSUPPORT: c_int = 94;
+            pub const EOPNOTSUPP: c_int = 95;
+            pub const EPFNOSUPPORT: c_int = 96;
+            pub const EAFNOSUPPORT: c_int = 97;
+            pub const EADDRINUSE: c_int = 98;
+            pub const EADDRNOTAVAIL: c_int = 99;
+            pub const ENETDOWN: c_int = 100;
+            pub const ENETUNREACH: c_int = 101;
+            pub const ENETRESET: c_int = 102;
+            pub const ECONNABORTED: c_int = 103;
+            pub const ECONNRESET: c_int = 104;
+            pub const ENOBUFS: c_int = 105;
+            pub const EISCONN: c_int = 106;
+            pub const ENOTCONN: c_int = 107;
+            pub const ESHUTDOWN: c_int = 108;
+            pub const ETOOMANYREFS: c_int = 109;
+            pub const ETIMEDOUT: c_int = 110;
+            pub const ECONNREFUSED: c_int = 111;
+            pub const EHOSTDOWN: c_int = 112;
+            pub const EHOSTUNREACH: c_int = 113;
+            pub const EALREADY: c_int = 114;
+            pub const EINPROGRESS: c_int = 115;
+            pub const ESTALE: c_int = 116;
+            pub const EUCLEAN: c_int = 117;
+            pub const ENOTNAM: c_int = 118;
+            pub const ENAVAIL: c_int = 119;
+            pub const EISNAM: c_int = 120;
+            pub const EREMOTEIO: c_int = 121;
+            pub const EDQUOT: c_int = 122;
+
+            pub const ENOMEDIUM: c_int = 123;
+            pub const EMEDIUMTYPE: c_int = 124;
+            pub const ECANCELED: c_int = 125;
+            pub const ENOKEY: c_int = 126;
+            pub const EKEYEXPIRED: c_int = 127;
+            pub const EKEYREVOKED: c_int = 128;
+            pub const EKEYREJECTED: c_int = 129;
+
+            pub const EOWNERDEAD: c_int = 130;
+            pub const ENOTRECOVERABLE: c_int = 131;
+
+            pub const ERFKILL: c_int = 132;
+
+            pub const EHWPOISON: c_int = 133;
+        }
+
+        #[cfg(any(target_arch = "mips",
+                  target_arch = "mipsel"))]
+        pub mod posix88 {
+            use types::os::arch::c95::c_int;
+            use types::common::c95::c_void;
+            use types::os::arch::posix88::mode_t;
+
+            pub const O_RDONLY : c_int = 0;
+            pub const O_WRONLY : c_int = 1;
+            pub const O_RDWR : c_int = 2;
+            pub const O_APPEND : c_int = 8;
+            pub const O_CREAT : c_int = 256;
+            pub const O_EXCL : c_int = 1024;
+            pub const O_NOCTTY : c_int = 2048;
+            pub const O_TRUNC : c_int = 512;
+            pub const S_IFIFO : mode_t = 4096;
+            pub const S_IFCHR : mode_t = 8192;
+            pub const S_IFBLK : mode_t = 24576;
+            pub const S_IFDIR : mode_t = 16384;
+            pub const S_IFREG : mode_t = 32768;
+            pub const S_IFLNK : mode_t = 40960;
+            pub const S_IFMT : mode_t = 61440;
+            pub const S_IEXEC : mode_t = 64;
+            pub const S_IWRITE : mode_t = 128;
+            pub const S_IREAD : mode_t = 256;
+            pub const S_IRWXU : mode_t = 448;
+            pub const S_IXUSR : mode_t = 64;
+            pub const S_IWUSR : mode_t = 128;
+            pub const S_IRUSR : mode_t = 256;
+            pub const S_IRWXG : mode_t = 56;
+            pub const S_IXGRP : mode_t = 8;
+            pub const S_IWGRP : mode_t = 16;
+            pub const S_IRGRP : mode_t = 32;
+            pub const S_IRWXO : mode_t = 7;
+            pub const S_IXOTH : mode_t = 1;
+            pub const S_IWOTH : mode_t = 2;
+            pub const S_IROTH : mode_t = 4;
+            pub const F_OK : c_int = 0;
+            pub const R_OK : c_int = 4;
+            pub const W_OK : c_int = 2;
+            pub const X_OK : c_int = 1;
+            pub const STDIN_FILENO : c_int = 0;
+            pub const STDOUT_FILENO : c_int = 1;
+            pub const STDERR_FILENO : c_int = 2;
+            pub const F_LOCK : c_int = 1;
+            pub const F_TEST : c_int = 3;
+            pub const F_TLOCK : c_int = 2;
+            pub const F_ULOCK : c_int = 0;
+            pub const SIGHUP : c_int = 1;
+            pub const SIGINT : c_int = 2;
+            pub const SIGQUIT : c_int = 3;
+            pub const SIGILL : c_int = 4;
+            pub const SIGABRT : c_int = 6;
+            pub const SIGFPE : c_int = 8;
+            pub const SIGKILL : c_int = 9;
+            pub const SIGSEGV : c_int = 11;
+            pub const SIGPIPE : c_int = 13;
+            pub const SIGALRM : c_int = 14;
+            pub const SIGTERM : c_int = 15;
+
+            pub const PROT_NONE : c_int = 0;
+            pub const PROT_READ : c_int = 1;
+            pub const PROT_WRITE : c_int = 2;
+            pub const PROT_EXEC : c_int = 4;
+
+            pub const MAP_FILE : c_int = 0x0000;
+            pub const MAP_SHARED : c_int = 0x0001;
+            pub const MAP_PRIVATE : c_int = 0x0002;
+            pub const MAP_FIXED : c_int = 0x0010;
+            pub const MAP_ANON : c_int = 0x0800;
+
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
+
+            pub const MCL_CURRENT : c_int = 0x0001;
+            pub const MCL_FUTURE : c_int = 0x0002;
+
+            pub const MS_ASYNC : c_int = 0x0001;
+            pub const MS_INVALIDATE : c_int = 0x0002;
+            pub const MS_SYNC : c_int = 0x0004;
+
+            pub const EPERM : c_int = 1;
+            pub const ENOENT : c_int = 2;
+            pub const ESRCH : c_int = 3;
+            pub const EINTR : c_int = 4;
+            pub const EIO : c_int = 5;
+            pub const ENXIO : c_int = 6;
+            pub const E2BIG : c_int = 7;
+            pub const ENOEXEC : c_int = 8;
+            pub const EBADF : c_int = 9;
+            pub const ECHILD : c_int = 10;
+            pub const EAGAIN : c_int = 11;
+            pub const ENOMEM : c_int = 12;
+            pub const EACCES : c_int = 13;
+            pub const EFAULT : c_int = 14;
+            pub const ENOTBLK : c_int = 15;
+            pub const EBUSY : c_int = 16;
+            pub const EEXIST : c_int = 17;
+            pub const EXDEV : c_int = 18;
+            pub const ENODEV : c_int = 19;
+            pub const ENOTDIR : c_int = 20;
+            pub const EISDIR : c_int = 21;
+            pub const EINVAL : c_int = 22;
+            pub const ENFILE : c_int = 23;
+            pub const EMFILE : c_int = 24;
+            pub const ENOTTY : c_int = 25;
+            pub const ETXTBSY : c_int = 26;
+            pub const EFBIG : c_int = 27;
+            pub const ENOSPC : c_int = 28;
+            pub const ESPIPE : c_int = 29;
+            pub const EROFS : c_int = 30;
+            pub const EMLINK : c_int = 31;
+            pub const EPIPE : c_int = 32;
+            pub const EDOM : c_int = 33;
+            pub const ERANGE : c_int = 34;
+
+            pub const ENOMSG: c_int = 35;
+            pub const EIDRM: c_int = 36;
+            pub const ECHRNG: c_int = 37;
+            pub const EL2NSYNC: c_int = 38;
+            pub const EL3HLT: c_int = 39;
+            pub const EL3RST: c_int = 40;
+            pub const ELNRNG: c_int = 41;
+            pub const EUNATCH: c_int = 42;
+            pub const ENOCSI: c_int = 43;
+            pub const EL2HLT: c_int = 44;
+            pub const EDEADLK: c_int = 45;
+            pub const ENOLCK: c_int = 46;
+            pub const EBADE: c_int = 50;
+            pub const EBADR: c_int = 51;
+            pub const EXFULL: c_int = 52;
+            pub const ENOANO: c_int = 53;
+            pub const EBADRQC: c_int = 54;
+            pub const EBADSLT: c_int = 55;
+            pub const EDEADLOCK: c_int = 56;
+            pub const EBFONT: c_int = 59;
+            pub const ENOSTR: c_int = 60;
+            pub const ENODATA: c_int = 61;
+            pub const ETIME: c_int = 62;
+            pub const ENOSR: c_int = 63;
+            pub const ENONET: c_int = 64;
+            pub const ENOPKG: c_int = 65;
+            pub const EREMOTE: c_int = 66;
+            pub const ENOLINK: c_int = 67;
+            pub const EADV: c_int = 68;
+            pub const ESRMNT: c_int = 69;
+            pub const ECOMM: c_int = 70;
+            pub const EPROTO: c_int = 71;
+            pub const EDOTDOT: c_int = 73;
+            pub const EMULTIHOP: c_int = 74;
+            pub const EBADMSG: c_int = 77;
+            pub const ENAMETOOLONG: c_int = 78;
+            pub const EOVERFLOW: c_int = 79;
+            pub const ENOTUNIQ: c_int = 80;
+            pub const EBADFD: c_int = 81;
+            pub const EREMCHG: c_int = 82;
+            pub const ELIBACC: c_int = 83;
+            pub const ELIBBAD: c_int = 84;
+            pub const ELIBSCN: c_int = 95;
+            pub const ELIBMAX: c_int = 86;
+            pub const ELIBEXEC: c_int = 87;
+            pub const EILSEQ: c_int = 88;
+            pub const ENOSYS: c_int = 89;
+            pub const ELOOP: c_int = 90;
+            pub const ERESTART: c_int = 91;
+            pub const ESTRPIPE: c_int = 92;
+            pub const ENOTEMPTY: c_int = 93;
+            pub const EUSERS: c_int = 94;
+            pub const ENOTSOCK: c_int = 95;
+            pub const EDESTADDRREQ: c_int = 96;
+            pub const EMSGSIZE: c_int = 97;
+            pub const EPROTOTYPE: c_int = 98;
+            pub const ENOPROTOOPT: c_int = 99;
+            pub const EPROTONOSUPPORT: c_int = 120;
+            pub const ESOCKTNOSUPPORT: c_int = 121;
+            pub const EOPNOTSUPP: c_int = 122;
+            pub const EPFNOSUPPORT: c_int = 123;
+            pub const EAFNOSUPPORT: c_int = 124;
+            pub const EADDRINUSE: c_int = 125;
+            pub const EADDRNOTAVAIL: c_int = 126;
+            pub const ENETDOWN: c_int = 127;
+            pub const ENETUNREACH: c_int = 128;
+            pub const ENETRESET: c_int = 129;
+            pub const ECONNABORTED: c_int = 130;
+            pub const ECONNRESET: c_int = 131;
+            pub const ENOBUFS: c_int = 132;
+            pub const EISCONN: c_int = 133;
+            pub const ENOTCONN: c_int = 134;
+            pub const EUCLEAN: c_int = 135;
+            pub const ENOTNAM: c_int = 137;
+            pub const ENAVAIL: c_int = 138;
+            pub const EISNAM: c_int = 139;
+            pub const EREMOTEIO: c_int = 140;
+            pub const ESHUTDOWN: c_int = 143;
+            pub const ETOOMANYREFS: c_int = 144;
+            pub const ETIMEDOUT: c_int = 145;
+            pub const ECONNREFUSED: c_int = 146;
+            pub const EHOSTDOWN: c_int = 147;
+            pub const EHOSTUNREACH: c_int = 148;
+            pub const EWOULDBLOCK: c_int = EAGAIN;
+            pub const EALREADY: c_int = 149;
+            pub const EINPROGRESS: c_int = 150;
+            pub const ESTALE: c_int = 151;
+            pub const ECANCELED: c_int = 158;
+
+            pub const ENOMEDIUM: c_int = 159;
+            pub const EMEDIUMTYPE: c_int = 160;
+            pub const ENOKEY: c_int = 161;
+            pub const EKEYEXPIRED: c_int = 162;
+            pub const EKEYREVOKED: c_int = 163;
+            pub const EKEYREJECTED: c_int = 164;
+
+            pub const EOWNERDEAD: c_int = 165;
+            pub const ENOTRECOVERABLE: c_int = 166;
+
+            pub const ERFKILL: c_int = 167;
+
+            pub const EHWPOISON: c_int = 168;
+
+            pub const EDQUOT: c_int = 1133;
+        }
+        #[cfg(not(target_os = "nacl"))]
+        pub mod posix01 {
+            use types::os::arch::c95::{c_int, size_t};
+            use types::os::common::posix01::rlim_t;
+
+            pub const F_DUPFD : c_int = 0;
+            pub const F_GETFD : c_int = 1;
+            pub const F_SETFD : c_int = 2;
+            pub const F_GETFL : c_int = 3;
+            pub const F_SETFL : c_int = 4;
+
+            pub const O_ACCMODE : c_int = 3;
+
+            pub const SIGTRAP : c_int = 5;
+            pub const SIG_IGN: size_t = 1;
+
+            pub const GLOB_ERR      : c_int = 1 << 0;
+            pub const GLOB_MARK     : c_int = 1 << 1;
+            pub const GLOB_NOSORT   : c_int = 1 << 2;
+            pub const GLOB_DOOFFS   : c_int = 1 << 3;
+            pub const GLOB_NOCHECK  : c_int = 1 << 4;
+            pub const GLOB_APPEND   : c_int = 1 << 5;
+            pub const GLOB_NOESCAPE : c_int = 1 << 6;
+
+            pub const GLOB_NOSPACE  : c_int = 1;
+            pub const GLOB_ABORTED  : c_int = 2;
+            pub const GLOB_NOMATCH  : c_int = 3;
+
+            pub const POSIX_MADV_NORMAL : c_int = 0;
+            pub const POSIX_MADV_RANDOM : c_int = 1;
+            pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
+            pub const POSIX_MADV_WILLNEED : c_int = 3;
+            pub const POSIX_MADV_DONTNEED : c_int = 4;
+
+            pub const _SC_MQ_PRIO_MAX : c_int = 28;
+            pub const _SC_IOV_MAX : c_int = 60;
+            pub const _SC_GETGR_R_SIZE_MAX : c_int = 69;
+            pub const _SC_GETPW_R_SIZE_MAX : c_int = 70;
+            pub const _SC_LOGIN_NAME_MAX : c_int = 71;
+            pub const _SC_TTY_NAME_MAX : c_int = 72;
+            pub const _SC_THREADS : c_int = 67;
+            pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68;
+            pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73;
+            pub const _SC_THREAD_KEYS_MAX : c_int = 74;
+            pub const _SC_THREAD_STACK_MIN : c_int = 75;
+            pub const _SC_THREAD_THREADS_MAX : c_int = 76;
+            pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
+            pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
+            pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79;
+            pub const _SC_THREAD_PRIO_INHERIT : c_int = 80;
+            pub const _SC_THREAD_PRIO_PROTECT : c_int = 81;
+            pub const _SC_THREAD_PROCESS_SHARED : c_int = 82;
+            pub const _SC_ATEXIT_MAX : c_int = 87;
+            pub const _SC_XOPEN_VERSION : c_int = 89;
+            pub const _SC_XOPEN_XCU_VERSION : c_int = 90;
+            pub const _SC_XOPEN_UNIX : c_int = 91;
+            pub const _SC_XOPEN_CRYPT : c_int = 92;
+            pub const _SC_XOPEN_ENH_I18N : c_int = 93;
+            pub const _SC_XOPEN_SHM : c_int = 94;
+            pub const _SC_XOPEN_LEGACY : c_int = 129;
+            pub const _SC_XOPEN_REALTIME : c_int = 130;
+            pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131;
+
+
+
+            pub const PTHREAD_CREATE_JOINABLE: c_int = 0;
+            pub const PTHREAD_CREATE_DETACHED: c_int = 1;
+
+            #[cfg(target_os = "android")]
+            pub const PTHREAD_STACK_MIN: size_t = 8192;
+
+            #[cfg(all(target_os = "linux",
+                      any(target_arch = "arm",
+                          target_arch = "x86",
+                          target_arch = "x86_64")))]
+            pub const PTHREAD_STACK_MIN: size_t = 16384;
+
+            #[cfg(all(target_os = "linux",
+                      any(target_arch = "mips",
+                          target_arch = "mipsel",
+                          target_arch = "aarch64",
+                          target_arch = "powerpc")))]
+            pub const PTHREAD_STACK_MIN: size_t = 131072;
+
+            pub const CLOCK_REALTIME: c_int = 0;
+            pub const CLOCK_MONOTONIC: c_int = 1;
+
+            pub const RLIMIT_CPU: c_int = 0;
+            pub const RLIMIT_FSIZE: c_int = 1;
+            pub const RLIMIT_DATA: c_int = 2;
+            pub const RLIMIT_STACK: c_int = 3;
+            pub const RLIMIT_CORE: c_int = 4;
+            pub const RLIMIT_RSS: c_int = 5;
+            pub const RLIMIT_NOFILE: c_int = 7;
+            pub const RLIMIT_AS: c_int = 9;
+            pub const RLIMIT_NPROC: c_int = 6;
+            pub const RLIMIT_MEMLOCK: c_int = 8;
+            pub const RLIMIT_LOCKS: c_int = 10;
+            pub const RLIMIT_SIGPENDING: c_int = 11;
+            pub const RLIMIT_MSGQUEUE: c_int = 12;
+            pub const RLIMIT_NICE: c_int = 13;
+            pub const RLIMIT_RTPRIO: c_int = 14;
+            pub const RLIMIT_RTTIME: c_int = 15;
+            pub const RLIMIT_NLIMITS: c_int = 16;
+            pub const RLIM_INFINITY: rlim_t = 0xffff_ffff_ffff_ffff;
+            pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY;
+            pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY;
+
+            pub const RUSAGE_SELF: c_int = 0;
+            pub const RUSAGE_CHILDREN: c_int = -1;
+            pub const RUSAGE_THREAD: c_int = 1;
+        }
+        #[cfg(target_os = "nacl")]
+        pub mod posix01 {
+            use types::os::arch::c95::{c_int, size_t};
+            use types::os::common::posix01::rlim_t;
+
+            pub const F_DUPFD : c_int = 0;
+            pub const F_GETFD : c_int = 1;
+            pub const F_SETFD : c_int = 2;
+            pub const F_GETFL : c_int = 3;
+            pub const F_SETFL : c_int = 4;
+
+            pub const SIGTRAP : c_int = 5;
+            pub const SIG_IGN: size_t = 1;
+
+            pub const GLOB_ERR      : c_int = 1 << 0;
+            pub const GLOB_MARK     : c_int = 1 << 1;
+            pub const GLOB_NOSORT   : c_int = 1 << 2;
+            pub const GLOB_DOOFFS   : c_int = 1 << 3;
+            pub const GLOB_NOCHECK  : c_int = 1 << 4;
+            pub const GLOB_APPEND   : c_int = 1 << 5;
+            pub const GLOB_NOESCAPE : c_int = 1 << 6;
+
+            pub const GLOB_NOSPACE  : c_int = 1;
+            pub const GLOB_ABORTED  : c_int = 2;
+            pub const GLOB_NOMATCH  : c_int = 3;
+
+            pub const POSIX_MADV_NORMAL : c_int = 0;
+            pub const POSIX_MADV_RANDOM : c_int = 1;
+            pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
+            pub const POSIX_MADV_WILLNEED : c_int = 3;
+            pub const POSIX_MADV_DONTNEED : c_int = 4;
+
+            pub const _SC_MQ_PRIO_MAX : c_int = 28;
+            pub const _SC_IOV_MAX : c_int = 60;
+            pub const _SC_GETGR_R_SIZE_MAX : c_int = 69;
+            pub const _SC_GETPW_R_SIZE_MAX : c_int = 70;
+            pub const _SC_LOGIN_NAME_MAX : c_int = 71;
+            pub const _SC_TTY_NAME_MAX : c_int = 72;
+            pub const _SC_THREADS : c_int = 67;
+            pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68;
+            pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73;
+            pub const _SC_THREAD_KEYS_MAX : c_int = 74;
+            pub const _SC_THREAD_STACK_MIN : c_int = 75;
+            pub const _SC_THREAD_THREADS_MAX : c_int = 76;
+            pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
+            pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
+            pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79;
+            pub const _SC_THREAD_PRIO_INHERIT : c_int = 80;
+            pub const _SC_THREAD_PRIO_PROTECT : c_int = 81;
+            pub const _SC_THREAD_PROCESS_SHARED : c_int = 82;
+            pub const _SC_ATEXIT_MAX : c_int = 87;
+            pub const _SC_XOPEN_VERSION : c_int = 89;
+            pub const _SC_XOPEN_XCU_VERSION : c_int = 90;
+            pub const _SC_XOPEN_UNIX : c_int = 91;
+            pub const _SC_XOPEN_CRYPT : c_int = 92;
+            pub const _SC_XOPEN_ENH_I18N : c_int = 93;
+            pub const _SC_XOPEN_SHM : c_int = 94;
+            pub const _SC_XOPEN_LEGACY : c_int = 129;
+            pub const _SC_XOPEN_REALTIME : c_int = 130;
+            pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131;
+
+            pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
+            pub const PTHREAD_CREATE_DETACHED: c_int = 0;
+
+            pub const PTHREAD_STACK_MIN: size_t = 1024;
+
+            pub const CLOCK_REALTIME: c_int = 0;
+            pub const CLOCK_MONOTONIC: c_int = 1;
+
+            pub const RLIMIT_CPU: c_int = 0;
+            pub const RLIMIT_FSIZE: c_int = 1;
+            pub const RLIMIT_DATA: c_int = 2;
+            pub const RLIMIT_STACK: c_int = 3;
+            pub const RLIMIT_CORE: c_int = 4;
+            pub const RLIMIT_RSS: c_int = 5;
+            pub const RLIMIT_NOFILE: c_int = 7;
+            pub const RLIMIT_AS: c_int = 9;
+            pub const RLIMIT_NPROC: c_int = 6;
+            pub const RLIMIT_MEMLOCK: c_int = 8;
+            pub const RLIMIT_LOCKS: c_int = 10;
+            pub const RLIMIT_SIGPENDING: c_int = 11;
+            pub const RLIMIT_MSGQUEUE: c_int = 12;
+            pub const RLIMIT_NICE: c_int = 13;
+            pub const RLIMIT_RTPRIO: c_int = 14;
+            pub const RLIMIT_RTTIME: c_int = 15;
+            pub const RLIMIT_NLIMITS: c_int = 16;
+
+            pub const RLIM_INFINITY: rlim_t = 0xffff_ffff_ffff_ffff;
+            pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY;
+            pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY;
+
+            pub const RUSAGE_SELF: c_int = 0;
+            pub const RUSAGE_CHILDREN: c_int = -1;
+            pub const RUSAGE_THREAD: c_int = 1;
+        }
+        pub mod posix08 {
+        }
+        #[cfg(any(target_arch = "arm",
+                  target_arch = "aarch64",
+                  target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "le32",
+                  target_arch = "powerpc"))]
+        pub mod bsd44 {
+            use types::os::arch::c95::c_int;
+
+            pub const MADV_NORMAL : c_int = 0;
+            pub const MADV_RANDOM : c_int = 1;
+            pub const MADV_SEQUENTIAL : c_int = 2;
+            pub const MADV_WILLNEED : c_int = 3;
+            pub const MADV_DONTNEED : c_int = 4;
+            pub const MADV_REMOVE : c_int = 9;
+            pub const MADV_DONTFORK : c_int = 10;
+            pub const MADV_DOFORK : c_int = 11;
+            pub const MADV_MERGEABLE : c_int = 12;
+            pub const MADV_UNMERGEABLE : c_int = 13;
+            pub const MADV_HWPOISON : c_int = 100;
+
+            pub const IFF_LOOPBACK: c_int = 0x8;
+
+            pub const AF_UNIX: c_int = 1;
+            pub const AF_INET: c_int = 2;
+            pub const AF_INET6: c_int = 10;
+            pub const SOCK_STREAM: c_int = 1;
+            pub const SOCK_DGRAM: c_int = 2;
+            pub const SOCK_RAW: c_int = 3;
+            pub const IPPROTO_TCP: c_int = 6;
+            pub const IPPROTO_IP: c_int = 0;
+            pub const IPPROTO_IPV6: c_int = 41;
+            pub const IP_MULTICAST_TTL: c_int = 33;
+            pub const IP_MULTICAST_LOOP: c_int = 34;
+            pub const IP_TTL: c_int = 2;
+            pub const IP_HDRINCL: c_int = 3;
+            pub const IP_ADD_MEMBERSHIP: c_int = 35;
+            pub const IP_DROP_MEMBERSHIP: c_int = 36;
+            pub const IPV6_ADD_MEMBERSHIP: c_int = 20;
+            pub const IPV6_DROP_MEMBERSHIP: c_int = 21;
+
+            pub const TCP_NODELAY: c_int = 1;
+            pub const TCP_MAXSEG: c_int = 2;
+            pub const TCP_CORK: c_int = 3;
+            pub const TCP_KEEPIDLE: c_int = 4;
+            pub const TCP_KEEPINTVL: c_int = 5;
+            pub const TCP_KEEPCNT: c_int = 6;
+            pub const TCP_SYNCNT: c_int = 7;
+            pub const TCP_LINGER2: c_int = 8;
+            pub const TCP_DEFER_ACCEPT: c_int = 9;
+            pub const TCP_WINDOW_CLAMP: c_int = 10;
+            pub const TCP_INFO: c_int = 11;
+            pub const TCP_QUICKACK: c_int = 12;
+            pub const TCP_CONGESTION: c_int = 13;
+            pub const TCP_MD5SIG: c_int = 14;
+            pub const TCP_COOKIE_TRANSACTIONS: c_int = 15;
+            pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16;
+            pub const TCP_THIN_DUPACK: c_int = 17;
+            pub const TCP_USER_TIMEOUT: c_int = 18;
+            pub const TCP_REPAIR: c_int = 19;
+            pub const TCP_REPAIR_QUEUE: c_int = 20;
+            pub const TCP_QUEUE_SEQ: c_int = 21;
+            pub const TCP_REPAIR_OPTIONS: c_int = 22;
+            pub const TCP_FASTOPEN: c_int = 23;
+            pub const TCP_TIMESTAMP: c_int = 24;
+
+            pub const SOL_SOCKET: c_int = 1;
+
+            pub const SO_DEBUG: c_int = 1;
+            pub const SO_REUSEADDR: c_int = 2;
+            pub const SO_TYPE: c_int = 3;
+            pub const SO_ERROR: c_int = 4;
+            pub const SO_DONTROUTE: c_int = 5;
+            pub const SO_BROADCAST: c_int = 6;
+            pub const SO_SNDBUF: c_int = 7;
+            pub const SO_RCVBUF: c_int = 8;
+            pub const SO_KEEPALIVE: c_int = 9;
+            pub const SO_OOBINLINE: c_int = 10;
+            pub const SO_LINGER: c_int = 13;
+            pub const SO_REUSEPORT: c_int = 15;
+            pub const SO_RCVLOWAT: c_int = 18;
+            pub const SO_SNDLOWAT: c_int = 19;
+            pub const SO_RCVTIMEO: c_int = 20;
+            pub const SO_SNDTIMEO: c_int = 21;
+            pub const SO_ACCEPTCONN: c_int = 30;
+
+            pub const SHUT_RD: c_int = 0;
+            pub const SHUT_WR: c_int = 1;
+            pub const SHUT_RDWR: c_int = 2;
+        }
+        #[cfg(any(target_arch = "mips",
+                  target_arch = "mipsel"))]
+        pub mod bsd44 {
+            use types::os::arch::c95::c_int;
+
+            pub const MADV_NORMAL : c_int = 0;
+            pub const MADV_RANDOM : c_int = 1;
+            pub const MADV_SEQUENTIAL : c_int = 2;
+            pub const MADV_WILLNEED : c_int = 3;
+            pub const MADV_DONTNEED : c_int = 4;
+            pub const MADV_REMOVE : c_int = 9;
+            pub const MADV_DONTFORK : c_int = 10;
+            pub const MADV_DOFORK : c_int = 11;
+            pub const MADV_MERGEABLE : c_int = 12;
+            pub const MADV_UNMERGEABLE : c_int = 13;
+            pub const MADV_HWPOISON : c_int = 100;
+
+            pub const AF_UNIX: c_int = 1;
+            pub const AF_INET: c_int = 2;
+            pub const AF_INET6: c_int = 10;
+            pub const SOCK_STREAM: c_int = 2;
+            pub const SOCK_DGRAM: c_int = 1;
+            pub const SOCK_RAW: c_int = 3;
+            pub const IPPROTO_TCP: c_int = 6;
+            pub const IPPROTO_IP: c_int = 0;
+            pub const IPPROTO_IPV6: c_int = 41;
+            pub const IP_MULTICAST_TTL: c_int = 33;
+            pub const IP_MULTICAST_LOOP: c_int = 34;
+            pub const IP_TTL: c_int = 2;
+            pub const IP_HDRINCL: c_int = 3;
+            pub const IP_ADD_MEMBERSHIP: c_int = 35;
+            pub const IP_DROP_MEMBERSHIP: c_int = 36;
+            pub const IPV6_ADD_MEMBERSHIP: c_int = 20;
+            pub const IPV6_DROP_MEMBERSHIP: c_int = 21;
+
+            pub const TCP_NODELAY: c_int = 1;
+            pub const TCP_MAXSEG: c_int = 2;
+            pub const TCP_CORK: c_int = 3;
+            pub const TCP_KEEPIDLE: c_int = 4;
+            pub const TCP_KEEPINTVL: c_int = 5;
+            pub const TCP_KEEPCNT: c_int = 6;
+            pub const TCP_SYNCNT: c_int = 7;
+            pub const TCP_LINGER2: c_int = 8;
+            pub const TCP_DEFER_ACCEPT: c_int = 9;
+            pub const TCP_WINDOW_CLAMP: c_int = 10;
+            pub const TCP_INFO: c_int = 11;
+            pub const TCP_QUICKACK: c_int = 12;
+            pub const TCP_CONGESTION: c_int = 13;
+            pub const TCP_MD5SIG: c_int = 14;
+            pub const TCP_COOKIE_TRANSACTIONS: c_int = 15;
+            pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16;
+            pub const TCP_THIN_DUPACK: c_int = 17;
+            pub const TCP_USER_TIMEOUT: c_int = 18;
+            pub const TCP_REPAIR: c_int = 19;
+            pub const TCP_REPAIR_QUEUE: c_int = 20;
+            pub const TCP_QUEUE_SEQ: c_int = 21;
+            pub const TCP_REPAIR_OPTIONS: c_int = 22;
+            pub const TCP_FASTOPEN: c_int = 23;
+            pub const TCP_TIMESTAMP: c_int = 24;
+
+            pub const SOL_SOCKET: c_int = 65535;
+
+            pub const SO_DEBUG: c_int = 0x0001;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
+            pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
+            pub const SO_ACCEPTCONN: c_int = 0x1009;
+
+            pub const SHUT_RD: c_int = 0;
+            pub const SHUT_WR: c_int = 1;
+            pub const SHUT_RDWR: c_int = 2;
+        }
+        #[cfg(any(target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "arm",
+                  target_arch = "aarch64",
+                  target_arch = "le32",
+                  target_arch = "powerpc"))]
+        pub mod extra {
+            use types::os::arch::c95::c_int;
+
+            pub const AF_PACKET : c_int = 17;
+            pub const IPPROTO_RAW : c_int = 255;
+
+            pub const O_RSYNC : c_int = 1052672;
+            pub const O_DSYNC : c_int = 4096;
+            pub const O_NONBLOCK : c_int = 2048;
+            pub const O_SYNC : c_int = 1052672;
+
+            pub const PROT_GROWSDOWN : c_int = 0x010000000;
+            pub const PROT_GROWSUP : c_int = 0x020000000;
+
+            pub const MAP_TYPE : c_int = 0x000f;
+            pub const MAP_ANONYMOUS : c_int = 0x0020;
+            pub const MAP_32BIT : c_int = 0x0040;
+            pub const MAP_GROWSDOWN : c_int = 0x0100;
+            pub const MAP_DENYWRITE : c_int = 0x0800;
+            pub const MAP_EXECUTABLE : c_int = 0x01000;
+            pub const MAP_LOCKED : c_int = 0x02000;
+            pub const MAP_NORESERVE : c_int = 0x04000;
+            pub const MAP_POPULATE : c_int = 0x08000;
+            pub const MAP_NONBLOCK : c_int = 0x010000;
+            pub const MAP_STACK : c_int = 0x020000;
+        }
+        #[cfg(any(target_arch = "mips",
+                  target_arch = "mipsel"))]
+        pub mod extra {
+            use types::os::arch::c95::c_int;
+
+            pub const AF_PACKET : c_int = 17;
+            pub const IPPROTO_RAW : c_int = 255;
+
+            pub const O_RSYNC : c_int = 16400;
+            pub const O_DSYNC : c_int = 16;
+            pub const O_NONBLOCK : c_int = 128;
+            pub const O_SYNC : c_int = 16400;
+
+            pub const PROT_GROWSDOWN : c_int = 0x01000000;
+            pub const PROT_GROWSUP : c_int = 0x02000000;
+
+            pub const MAP_TYPE : c_int = 0x000f;
+            pub const MAP_ANONYMOUS : c_int = 0x0800;
+            pub const MAP_GROWSDOWN : c_int = 0x01000;
+            pub const MAP_DENYWRITE : c_int = 0x02000;
+            pub const MAP_EXECUTABLE : c_int = 0x04000;
+            pub const MAP_LOCKED : c_int = 0x08000;
+            pub const MAP_NORESERVE : c_int = 0x0400;
+            pub const MAP_POPULATE : c_int = 0x010000;
+            pub const MAP_NONBLOCK : c_int = 0x020000;
+            pub const MAP_STACK : c_int = 0x040000;
+        }
+        #[cfg(target_os = "linux")]
+        pub mod sysconf {
+            use types::os::arch::c95::c_int;
+
+            pub const _SC_ARG_MAX : c_int = 0;
+            pub const _SC_CHILD_MAX : c_int = 1;
+            pub const _SC_CLK_TCK : c_int = 2;
+            pub const _SC_NGROUPS_MAX : c_int = 3;
+            pub const _SC_OPEN_MAX : c_int = 4;
+            pub const _SC_STREAM_MAX : c_int = 5;
+            pub const _SC_TZNAME_MAX : c_int = 6;
+            pub const _SC_JOB_CONTROL : c_int = 7;
+            pub const _SC_SAVED_IDS : c_int = 8;
+            pub const _SC_REALTIME_SIGNALS : c_int = 9;
+            pub const _SC_PRIORITY_SCHEDULING : c_int = 10;
+            pub const _SC_TIMERS : c_int = 11;
+            pub const _SC_ASYNCHRONOUS_IO : c_int = 12;
+            pub const _SC_PRIORITIZED_IO : c_int = 13;
+            pub const _SC_SYNCHRONIZED_IO : c_int = 14;
+            pub const _SC_FSYNC : c_int = 15;
+            pub const _SC_MAPPED_FILES : c_int = 16;
+            pub const _SC_MEMLOCK : c_int = 17;
+            pub const _SC_MEMLOCK_RANGE : c_int = 18;
+            pub const _SC_MEMORY_PROTECTION : c_int = 19;
+            pub const _SC_MESSAGE_PASSING : c_int = 20;
+            pub const _SC_SEMAPHORES : c_int = 21;
+            pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 22;
+            pub const _SC_AIO_LISTIO_MAX : c_int = 23;
+            pub const _SC_AIO_MAX : c_int = 24;
+            pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 25;
+            pub const _SC_DELAYTIMER_MAX : c_int = 26;
+            pub const _SC_MQ_OPEN_MAX : c_int = 27;
+            pub const _SC_VERSION : c_int = 29;
+            pub const _SC_PAGESIZE : c_int = 30;
+            pub const _SC_RTSIG_MAX : c_int = 31;
+            pub const _SC_SEM_NSEMS_MAX : c_int = 32;
+            pub const _SC_SEM_VALUE_MAX : c_int = 33;
+            pub const _SC_SIGQUEUE_MAX : c_int = 34;
+            pub const _SC_TIMER_MAX : c_int = 35;
+            pub const _SC_BC_BASE_MAX : c_int = 36;
+            pub const _SC_BC_DIM_MAX : c_int = 37;
+            pub const _SC_BC_SCALE_MAX : c_int = 38;
+            pub const _SC_BC_STRING_MAX : c_int = 39;
+            pub const _SC_COLL_WEIGHTS_MAX : c_int = 40;
+            pub const _SC_EXPR_NEST_MAX : c_int = 42;
+            pub const _SC_LINE_MAX : c_int = 43;
+            pub const _SC_RE_DUP_MAX : c_int = 44;
+            pub const _SC_2_VERSION : c_int = 46;
+            pub const _SC_2_C_BIND : c_int = 47;
+            pub const _SC_2_C_DEV : c_int = 48;
+            pub const _SC_2_FORT_DEV : c_int = 49;
+            pub const _SC_2_FORT_RUN : c_int = 50;
+            pub const _SC_2_SW_DEV : c_int = 51;
+            pub const _SC_2_LOCALEDEF : c_int = 52;
+            pub const _SC_NPROCESSORS_ONLN : c_int = 84;
+            pub const _SC_2_CHAR_TERM : c_int = 95;
+            pub const _SC_2_C_VERSION : c_int = 96;
+            pub const _SC_2_UPE : c_int = 97;
+            pub const _SC_XBS5_ILP32_OFF32 : c_int = 125;
+            pub const _SC_XBS5_ILP32_OFFBIG : c_int = 126;
+            pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 128;
+
+        }
+        #[cfg(target_os = "nacl")]
+        pub mod sysconf {
+            use types::os::arch::c95::c_int;
+
+            pub static _SC_SENDMSG_MAX_SIZE : c_int = 0;
+            pub static _SC_NPROCESSORS_ONLN : c_int = 1;
+            pub static _SC_PAGESIZE : c_int = 2;
+        }
+
+        #[cfg(target_os = "android")]
+        pub mod sysconf {
+            use types::os::arch::c95::c_int;
+
+            pub const _SC_ARG_MAX : c_int = 0;
+            pub const _SC_BC_BASE_MAX : c_int = 1;
+            pub const _SC_BC_DIM_MAX : c_int = 2;
+            pub const _SC_BC_SCALE_MAX : c_int = 3;
+            pub const _SC_BC_STRING_MAX : c_int = 4;
+            pub const _SC_CHILD_MAX : c_int = 5;
+            pub const _SC_CLK_TCK : c_int = 6;
+            pub const _SC_COLL_WEIGHTS_MAX : c_int = 7;
+            pub const _SC_EXPR_NEST_MAX : c_int = 8;
+            pub const _SC_LINE_MAX : c_int = 9;
+            pub const _SC_NGROUPS_MAX : c_int = 10;
+            pub const _SC_OPEN_MAX : c_int = 11;
+            pub const _SC_2_C_BIND : c_int = 13;
+            pub const _SC_2_C_DEV : c_int = 14;
+            pub const _SC_2_C_VERSION : c_int = 15;
+            pub const _SC_2_CHAR_TERM : c_int = 16;
+            pub const _SC_2_FORT_DEV : c_int = 17;
+            pub const _SC_2_FORT_RUN : c_int = 18;
+            pub const _SC_2_LOCALEDEF : c_int = 19;
+            pub const _SC_2_SW_DEV : c_int = 20;
+            pub const _SC_2_UPE : c_int = 21;
+            pub const _SC_2_VERSION : c_int = 22;
+            pub const _SC_JOB_CONTROL : c_int = 23;
+            pub const _SC_SAVED_IDS : c_int = 24;
+            pub const _SC_VERSION : c_int = 25;
+            pub const _SC_RE_DUP_MAX : c_int = 26;
+            pub const _SC_STREAM_MAX : c_int = 27;
+            pub const _SC_TZNAME_MAX : c_int = 28;
+            pub const _SC_PAGESIZE : c_int = 39;
+        }
+    }
+
+    #[cfg(any(target_os = "freebsd",
+              target_os = "dragonfly"))]
+    pub mod os {
+        pub mod c95 {
+            use types::os::arch::c95::{c_int, c_uint};
+
+            pub const EXIT_FAILURE : c_int = 1;
+            pub const EXIT_SUCCESS : c_int = 0;
+            pub const RAND_MAX : c_int = 2147483647;
+            pub const EOF : c_int = -1;
+            pub const SEEK_SET : c_int = 0;
+            pub const SEEK_CUR : c_int = 1;
+            pub const SEEK_END : c_int = 2;
+            pub const _IOFBF : c_int = 0;
+            pub const _IONBF : c_int = 2;
+            pub const _IOLBF : c_int = 1;
+            pub const BUFSIZ : c_uint = 1024;
+            pub const FOPEN_MAX : c_uint = 20;
+            pub const FILENAME_MAX : c_uint = 1024;
+            pub const L_tmpnam : c_uint = 1024;
+            pub const TMP_MAX : c_uint = 308915776;
+        }
+        pub mod c99 {
+        }
+        pub mod posix88 {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::c_int;
+            use types::os::arch::posix88::mode_t;
+
+            pub const O_RDONLY : c_int = 0;
+            pub const O_WRONLY : c_int = 1;
+            pub const O_RDWR : c_int = 2;
+            pub const O_APPEND : c_int = 8;
+            pub const O_CREAT : c_int = 512;
+            pub const O_EXCL : c_int = 2048;
+            pub const O_NOCTTY : c_int = 32768;
+            pub const O_TRUNC : c_int = 1024;
+            pub const S_IFIFO : mode_t = 4096;
+            pub const S_IFCHR : mode_t = 8192;
+            pub const S_IFBLK : mode_t = 24576;
+            pub const S_IFDIR : mode_t = 16384;
+            pub const S_IFREG : mode_t = 32768;
+            pub const S_IFLNK : mode_t = 40960;
+            pub const S_IFMT : mode_t = 61440;
+            pub const S_IEXEC : mode_t = 64;
+            pub const S_IWRITE : mode_t = 128;
+            pub const S_IREAD : mode_t = 256;
+            pub const S_IRWXU : mode_t = 448;
+            pub const S_IXUSR : mode_t = 64;
+            pub const S_IWUSR : mode_t = 128;
+            pub const S_IRUSR : mode_t = 256;
+            pub const S_IRWXG : mode_t = 56;
+            pub const S_IXGRP : mode_t = 8;
+            pub const S_IWGRP : mode_t = 16;
+            pub const S_IRGRP : mode_t = 32;
+            pub const S_IRWXO : mode_t = 7;
+            pub const S_IXOTH : mode_t = 1;
+            pub const S_IWOTH : mode_t = 2;
+            pub const S_IROTH : mode_t = 4;
+            pub const F_OK : c_int = 0;
+            pub const R_OK : c_int = 4;
+            pub const W_OK : c_int = 2;
+            pub const X_OK : c_int = 1;
+            pub const STDIN_FILENO : c_int = 0;
+            pub const STDOUT_FILENO : c_int = 1;
+            pub const STDERR_FILENO : c_int = 2;
+            pub const F_LOCK : c_int = 1;
+            pub const F_TEST : c_int = 3;
+            pub const F_TLOCK : c_int = 2;
+            pub const F_ULOCK : c_int = 0;
+            pub const SIGHUP : c_int = 1;
+            pub const SIGINT : c_int = 2;
+            pub const SIGQUIT : c_int = 3;
+            pub const SIGILL : c_int = 4;
+            pub const SIGABRT : c_int = 6;
+            pub const SIGFPE : c_int = 8;
+            pub const SIGKILL : c_int = 9;
+            pub const SIGSEGV : c_int = 11;
+            pub const SIGPIPE : c_int = 13;
+            pub const SIGALRM : c_int = 14;
+            pub const SIGTERM : c_int = 15;
+
+            pub const PROT_NONE : c_int = 0;
+            pub const PROT_READ : c_int = 1;
+            pub const PROT_WRITE : c_int = 2;
+            pub const PROT_EXEC : c_int = 4;
+
+            pub const MAP_FILE : c_int = 0x0000;
+            pub const MAP_SHARED : c_int = 0x0001;
+            pub const MAP_PRIVATE : c_int = 0x0002;
+            pub const MAP_FIXED : c_int = 0x0010;
+            pub const MAP_ANON : c_int = 0x1000;
+
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
+
+            pub const MCL_CURRENT : c_int = 0x0001;
+            pub const MCL_FUTURE : c_int = 0x0002;
+
+            pub const MS_SYNC : c_int = 0x0000;
+            pub const MS_ASYNC : c_int = 0x0001;
+            pub const MS_INVALIDATE : c_int = 0x0002;
+
+            pub const EPERM : c_int = 1;
+            pub const ENOENT : c_int = 2;
+            pub const ESRCH : c_int = 3;
+            pub const EINTR : c_int = 4;
+            pub const EIO : c_int = 5;
+            pub const ENXIO : c_int = 6;
+            pub const E2BIG : c_int = 7;
+            pub const ENOEXEC : c_int = 8;
+            pub const EBADF : c_int = 9;
+            pub const ECHILD : c_int = 10;
+            pub const EDEADLK : c_int = 11;
+            pub const ENOMEM : c_int = 12;
+            pub const EACCES : c_int = 13;
+            pub const EFAULT : c_int = 14;
+            pub const ENOTBLK : c_int = 15;
+            pub const EBUSY : c_int = 16;
+            pub const EEXIST : c_int = 17;
+            pub const EXDEV : c_int = 18;
+            pub const ENODEV : c_int = 19;
+            pub const ENOTDIR : c_int = 20;
+            pub const EISDIR : c_int = 21;
+            pub const EINVAL : c_int = 22;
+            pub const ENFILE : c_int = 23;
+            pub const EMFILE : c_int = 24;
+            pub const ENOTTY : c_int = 25;
+            pub const ETXTBSY : c_int = 26;
+            pub const EFBIG : c_int = 27;
+            pub const ENOSPC : c_int = 28;
+            pub const ESPIPE : c_int = 29;
+            pub const EROFS : c_int = 30;
+            pub const EMLINK : c_int = 31;
+            pub const EPIPE : c_int = 32;
+            pub const EDOM : c_int = 33;
+            pub const ERANGE : c_int = 34;
+            pub const EAGAIN : c_int = 35;
+            pub const EWOULDBLOCK : c_int = 35;
+            pub const EINPROGRESS : c_int = 36;
+            pub const EALREADY : c_int = 37;
+            pub const ENOTSOCK : c_int = 38;
+            pub const EDESTADDRREQ : c_int = 39;
+            pub const EMSGSIZE : c_int = 40;
+            pub const EPROTOTYPE : c_int = 41;
+            pub const ENOPROTOOPT : c_int = 42;
+            pub const EPROTONOSUPPORT : c_int = 43;
+            pub const ESOCKTNOSUPPORT : c_int = 44;
+            pub const EOPNOTSUPP : c_int = 45;
+            pub const EPFNOSUPPORT : c_int = 46;
+            pub const EAFNOSUPPORT : c_int = 47;
+            pub const EADDRINUSE : c_int = 48;
+            pub const EADDRNOTAVAIL : c_int = 49;
+            pub const ENETDOWN : c_int = 50;
+            pub const ENETUNREACH : c_int = 51;
+            pub const ENETRESET : c_int = 52;
+            pub const ECONNABORTED : c_int = 53;
+            pub const ECONNRESET : c_int = 54;
+            pub const ENOBUFS : c_int = 55;
+            pub const EISCONN : c_int = 56;
+            pub const ENOTCONN : c_int = 57;
+            pub const ESHUTDOWN : c_int = 58;
+            pub const ETOOMANYREFS : c_int = 59;
+            pub const ETIMEDOUT : c_int = 60;
+            pub const ECONNREFUSED : c_int = 61;
+            pub const ELOOP : c_int = 62;
+            pub const ENAMETOOLONG : c_int = 63;
+            pub const EHOSTDOWN : c_int = 64;
+            pub const EHOSTUNREACH : c_int = 65;
+            pub const ENOTEMPTY : c_int = 66;
+            pub const EPROCLIM : c_int = 67;
+            pub const EUSERS : c_int = 68;
+            pub const EDQUOT : c_int = 69;
+            pub const ESTALE : c_int = 70;
+            pub const EREMOTE : c_int = 71;
+            pub const EBADRPC : c_int = 72;
+            pub const ERPCMISMATCH : c_int = 73;
+            pub const EPROGUNAVAIL : c_int = 74;
+            pub const EPROGMISMATCH : c_int = 75;
+            pub const EPROCUNAVAIL : c_int = 76;
+            pub const ENOLCK : c_int = 77;
+            pub const ENOSYS : c_int = 78;
+            pub const EFTYPE : c_int = 79;
+            pub const EAUTH : c_int = 80;
+            pub const ENEEDAUTH : c_int = 81;
+            pub const EIDRM : c_int = 82;
+            pub const ENOMSG : c_int = 83;
+            pub const EOVERFLOW : c_int = 84;
+            pub const ECANCELED : c_int = 85;
+            pub const EILSEQ : c_int = 86;
+            pub const ENOATTR : c_int = 87;
+            pub const EDOOFUS : c_int = 88;
+            pub const EBADMSG : c_int = 89;
+            pub const EMULTIHOP : c_int = 90;
+            pub const ENOLINK : c_int = 91;
+            pub const EPROTO : c_int = 92;
+            pub const ENOMEDIUM : c_int = 93;
+            pub const EUNUSED94 : c_int = 94;
+            pub const EUNUSED95 : c_int = 95;
+            pub const EUNUSED96 : c_int = 96;
+            pub const EUNUSED97 : c_int = 97;
+            pub const EUNUSED98 : c_int = 98;
+            pub const EASYNC : c_int = 99;
+            pub const ELAST : c_int = 99;
+        }
+        pub mod posix01 {
+            use types::os::arch::c95::{c_int, size_t};
+            use types::os::common::posix01::rlim_t;
+
+            pub const F_DUPFD : c_int = 0;
+            pub const F_GETFD : c_int = 1;
+            pub const F_SETFD : c_int = 2;
+            pub const F_GETFL : c_int = 3;
+            pub const F_SETFL : c_int = 4;
+
+            pub const SIGTRAP : c_int = 5;
+            pub const SIG_IGN: size_t = 1;
+
+            pub const GLOB_APPEND   : c_int = 0x0001;
+            pub const GLOB_DOOFFS   : c_int = 0x0002;
+            pub const GLOB_ERR      : c_int = 0x0004;
+            pub const GLOB_MARK     : c_int = 0x0008;
+            pub const GLOB_NOCHECK  : c_int = 0x0010;
+            pub const GLOB_NOSORT   : c_int = 0x0020;
+            pub const GLOB_NOESCAPE : c_int = 0x2000;
+
+            pub const GLOB_NOSPACE  : c_int = -1;
+            pub const GLOB_ABORTED  : c_int = -2;
+            pub const GLOB_NOMATCH  : c_int = -3;
+
+            pub const POSIX_MADV_NORMAL : c_int = 0;
+            pub const POSIX_MADV_RANDOM : c_int = 1;
+            pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
+            pub const POSIX_MADV_WILLNEED : c_int = 3;
+            pub const POSIX_MADV_DONTNEED : c_int = 4;
+
+            pub const _SC_IOV_MAX : c_int = 56;
+            pub const _SC_GETGR_R_SIZE_MAX : c_int = 70;
+            pub const _SC_GETPW_R_SIZE_MAX : c_int = 71;
+            pub const _SC_LOGIN_NAME_MAX : c_int = 73;
+            pub const _SC_MQ_PRIO_MAX : c_int = 75;
+            pub const _SC_THREAD_ATTR_STACKADDR : c_int = 82;
+            pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 83;
+            pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85;
+            pub const _SC_THREAD_KEYS_MAX : c_int = 86;
+            pub const _SC_THREAD_PRIO_INHERIT : c_int = 87;
+            pub const _SC_THREAD_PRIO_PROTECT : c_int = 88;
+            pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89;
+            pub const _SC_THREAD_PROCESS_SHARED : c_int = 90;
+            pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 91;
+            pub const _SC_THREAD_STACK_MIN : c_int = 93;
+            pub const _SC_THREAD_THREADS_MAX : c_int = 94;
+            pub const _SC_THREADS : c_int = 96;
+            pub const _SC_TTY_NAME_MAX : c_int = 101;
+            pub const _SC_ATEXIT_MAX : c_int = 107;
+            pub const _SC_XOPEN_CRYPT : c_int = 108;
+            pub const _SC_XOPEN_ENH_I18N : c_int = 109;
+            pub const _SC_XOPEN_LEGACY : c_int = 110;
+            pub const _SC_XOPEN_REALTIME : c_int = 111;
+            pub const _SC_XOPEN_REALTIME_THREADS : c_int = 112;
+            pub const _SC_XOPEN_SHM : c_int = 113;
+            pub const _SC_XOPEN_UNIX : c_int = 115;
+            pub const _SC_XOPEN_VERSION : c_int = 116;
+            pub const _SC_XOPEN_XCU_VERSION : c_int = 117;
+
+            pub const PTHREAD_CREATE_JOINABLE: c_int = 0;
+            pub const PTHREAD_CREATE_DETACHED: c_int = 1;
+
+            #[cfg(target_arch = "arm")]
+            pub const PTHREAD_STACK_MIN: size_t = 4096;
+
+            #[cfg(all(target_os = "freebsd",
+                      any(target_arch = "mips",
+                          target_arch = "mipsel",
+                          target_arch = "x86",
+                          target_arch = "x86_64")))]
+            pub const PTHREAD_STACK_MIN: size_t = 2048;
+
+            #[cfg(target_os = "dragonfly")]
+            pub const PTHREAD_STACK_MIN: size_t = 1024;
+
+            pub const CLOCK_REALTIME: c_int = 0;
+            pub const CLOCK_MONOTONIC: c_int = 4;
+
+            pub const RLIMIT_CPU: c_int = 0;
+            pub const RLIMIT_FSIZE: c_int = 1;
+            pub const RLIMIT_DATA: c_int = 2;
+            pub const RLIMIT_STACK: c_int = 3;
+            pub const RLIMIT_CORE: c_int = 4;
+            pub const RLIMIT_RSS: c_int = 5;
+            pub const RLIMIT_MEMLOCK: c_int = 6;
+            pub const RLIMIT_NPROC: c_int = 7;
+            pub const RLIMIT_NOFILE: c_int = 8;
+            pub const RLIMIT_SBSIZE: c_int = 9;
+            pub const RLIMIT_VMEM: c_int = 10;
+            pub const RLIMIT_AS: c_int = RLIMIT_VMEM;
+            pub const RLIMIT_NPTS: c_int = 11;
+            pub const RLIMIT_SWAP: c_int = 12;
+            pub const RLIMIT_KQUEUES: c_int = 13;
+
+            pub const RLIM_NLIMITS: rlim_t = 14;
+            pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff;
+
+            pub const RUSAGE_SELF: c_int = 0;
+            pub const RUSAGE_CHILDREN: c_int = -1;
+            pub const RUSAGE_THREAD: c_int = 1;
+        }
+        pub mod posix08 {
+        }
+        pub mod bsd44 {
+            use types::os::arch::c95::c_int;
+
+            pub const MADV_NORMAL : c_int = 0;
+            pub const MADV_RANDOM : c_int = 1;
+            pub const MADV_SEQUENTIAL : c_int = 2;
+            pub const MADV_WILLNEED : c_int = 3;
+            pub const MADV_DONTNEED : c_int = 4;
+            pub const MADV_FREE : c_int = 5;
+            pub const MADV_NOSYNC : c_int = 6;
+            pub const MADV_AUTOSYNC : c_int = 7;
+            pub const MADV_NOCORE : c_int = 8;
+            pub const MADV_CORE : c_int = 9;
+            pub const MADV_PROTECT : c_int = 10;
+
+            pub const MINCORE_INCORE : c_int =  0x1;
+            pub const MINCORE_REFERENCED : c_int = 0x2;
+            pub const MINCORE_MODIFIED : c_int = 0x4;
+            pub const MINCORE_REFERENCED_OTHER : c_int = 0x8;
+            pub const MINCORE_MODIFIED_OTHER : c_int = 0x10;
+            pub const MINCORE_SUPER : c_int = 0x20;
+
+            pub const AF_INET: c_int = 2;
+            pub const AF_INET6: c_int = 28;
+            pub const AF_UNIX: c_int = 1;
+            pub const SOCK_STREAM: c_int = 1;
+            pub const SOCK_DGRAM: c_int = 2;
+            pub const SOCK_RAW: c_int = 3;
+            pub const IPPROTO_TCP: c_int = 6;
+            pub const IPPROTO_IP: c_int = 0;
+            pub const IPPROTO_IPV6: c_int = 41;
+            pub const IP_MULTICAST_TTL: c_int = 10;
+            pub const IP_MULTICAST_LOOP: c_int = 11;
+            pub const IP_TTL: c_int = 4;
+            pub const IP_HDRINCL: c_int = 2;
+            pub const IP_ADD_MEMBERSHIP: c_int = 12;
+            pub const IP_DROP_MEMBERSHIP: c_int = 13;
+            pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
+            pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
+
+            pub const TCP_NODELAY: c_int = 1;
+            pub const TCP_KEEPIDLE: c_int = 256;
+            pub const SOL_SOCKET: c_int = 0xffff;
+            pub const SO_DEBUG: c_int = 0x01;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
+            pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
+
+            pub const IFF_LOOPBACK: c_int = 0x8;
+
+            pub const SHUT_RD: c_int = 0;
+            pub const SHUT_WR: c_int = 1;
+            pub const SHUT_RDWR: c_int = 2;
+        }
+        pub mod extra {
+            use types::os::arch::c95::c_int;
+
+            pub const O_SYNC : c_int = 128;
+            pub const O_NONBLOCK : c_int = 4;
+            pub const CTL_KERN: c_int = 1;
+            pub const KERN_PROC: c_int = 14;
+            #[cfg(target_os = "freebsd")]
+            pub const KERN_PROC_PATHNAME: c_int = 12;
+            #[cfg(target_os = "dragonfly")]
+            pub const KERN_PROC_PATHNAME: c_int = 9;
+
+            pub const MAP_COPY : c_int = 0x0002;
+            pub const MAP_RENAME : c_int = 0x0020;
+            pub const MAP_NORESERVE : c_int = 0x0040;
+            pub const MAP_HASSEMAPHORE : c_int = 0x0200;
+            pub const MAP_STACK : c_int = 0x0400;
+            pub const MAP_NOSYNC : c_int = 0x0800;
+            pub const MAP_NOCORE : c_int = 0x020000;
+
+            pub const IPPROTO_RAW : c_int = 255;
+        }
+        pub mod sysconf {
+            use types::os::arch::c95::c_int;
+
+            pub const _SC_ARG_MAX : c_int = 1;
+            pub const _SC_CHILD_MAX : c_int = 2;
+            pub const _SC_CLK_TCK : c_int = 3;
+            pub const _SC_NGROUPS_MAX : c_int = 4;
+            pub const _SC_OPEN_MAX : c_int = 5;
+            pub const _SC_JOB_CONTROL : c_int = 6;
+            pub const _SC_SAVED_IDS : c_int = 7;
+            pub const _SC_VERSION : c_int = 8;
+            pub const _SC_BC_BASE_MAX : c_int = 9;
+            pub const _SC_BC_DIM_MAX : c_int = 10;
+            pub const _SC_BC_SCALE_MAX : c_int = 11;
+            pub const _SC_BC_STRING_MAX : c_int = 12;
+            pub const _SC_COLL_WEIGHTS_MAX : c_int = 13;
+            pub const _SC_EXPR_NEST_MAX : c_int = 14;
+            pub const _SC_LINE_MAX : c_int = 15;
+            pub const _SC_RE_DUP_MAX : c_int = 16;
+            pub const _SC_2_VERSION : c_int = 17;
+            pub const _SC_2_C_BIND : c_int = 18;
+            pub const _SC_2_C_DEV : c_int = 19;
+            pub const _SC_2_CHAR_TERM : c_int = 20;
+            pub const _SC_2_FORT_DEV : c_int = 21;
+            pub const _SC_2_FORT_RUN : c_int = 22;
+            pub const _SC_2_LOCALEDEF : c_int = 23;
+            pub const _SC_2_SW_DEV : c_int = 24;
+            pub const _SC_2_UPE : c_int = 25;
+            pub const _SC_STREAM_MAX : c_int = 26;
+            pub const _SC_TZNAME_MAX : c_int = 27;
+            pub const _SC_ASYNCHRONOUS_IO : c_int = 28;
+            pub const _SC_MAPPED_FILES : c_int = 29;
+            pub const _SC_MEMLOCK : c_int = 30;
+            pub const _SC_MEMLOCK_RANGE : c_int = 31;
+            pub const _SC_MEMORY_PROTECTION : c_int = 32;
+            pub const _SC_MESSAGE_PASSING : c_int = 33;
+            pub const _SC_PRIORITIZED_IO : c_int = 34;
+            pub const _SC_PRIORITY_SCHEDULING : c_int = 35;
+            pub const _SC_REALTIME_SIGNALS : c_int = 36;
+            pub const _SC_SEMAPHORES : c_int = 37;
+            pub const _SC_FSYNC : c_int = 38;
+            pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 39;
+            pub const _SC_SYNCHRONIZED_IO : c_int = 40;
+            pub const _SC_TIMERS : c_int = 41;
+            pub const _SC_AIO_LISTIO_MAX : c_int = 42;
+            pub const _SC_AIO_MAX : c_int = 43;
+            pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44;
+            pub const _SC_DELAYTIMER_MAX : c_int = 45;
+            pub const _SC_MQ_OPEN_MAX : c_int = 46;
+            pub const _SC_PAGESIZE : c_int = 47;
+            pub const _SC_RTSIG_MAX : c_int = 48;
+            pub const _SC_SEM_NSEMS_MAX : c_int = 49;
+            pub const _SC_SEM_VALUE_MAX : c_int = 50;
+            pub const _SC_SIGQUEUE_MAX : c_int = 51;
+            pub const _SC_TIMER_MAX : c_int = 52;
+        }
+    }
+
+    #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+    pub mod os {
+        pub mod c95 {
+            use types::os::arch::c95::{c_int, c_uint};
+
+            pub const EXIT_FAILURE : c_int = 1;
+            pub const EXIT_SUCCESS : c_int = 0;
+            pub const RAND_MAX : c_int = 2147483647;
+            pub const EOF : c_int = -1;
+            pub const SEEK_SET : c_int = 0;
+            pub const SEEK_CUR : c_int = 1;
+            pub const SEEK_END : c_int = 2;
+            pub const _IOFBF : c_int = 0;
+            pub const _IONBF : c_int = 2;
+            pub const _IOLBF : c_int = 1;
+            pub const BUFSIZ : c_uint = 1024;
+            pub const FOPEN_MAX : c_uint = 20;
+            pub const FILENAME_MAX : c_uint = 1024;
+            pub const L_tmpnam : c_uint = 1024;
+            pub const TMP_MAX : c_uint = 308915776;
+        }
+        pub mod c99 {
+        }
+        pub mod posix88 {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::c_int;
+            use types::os::arch::posix88::mode_t;
+
+            pub const O_RDONLY : c_int = 0;
+            pub const O_WRONLY : c_int = 1;
+            pub const O_RDWR : c_int = 2;
+            pub const O_APPEND : c_int = 8;
+            pub const O_CREAT : c_int = 512;
+            pub const O_EXCL : c_int = 2048;
+            pub const O_NOCTTY : c_int = 32768;
+            pub const O_TRUNC : c_int = 1024;
+            pub const S_IFIFO : mode_t = 4096;
+            pub const S_IFCHR : mode_t = 8192;
+            pub const S_IFBLK : mode_t = 24576;
+            pub const S_IFDIR : mode_t = 16384;
+            pub const S_IFREG : mode_t = 32768;
+            pub const S_IFLNK : mode_t = 40960;
+            pub const S_IFMT : mode_t = 61440;
+            pub const S_IEXEC : mode_t = 64;
+            pub const S_IWRITE : mode_t = 128;
+            pub const S_IREAD : mode_t = 256;
+            pub const S_IRWXU : mode_t = 448;
+            pub const S_IXUSR : mode_t = 64;
+            pub const S_IWUSR : mode_t = 128;
+            pub const S_IRUSR : mode_t = 256;
+            pub const S_IRWXG : mode_t = 56;
+            pub const S_IXGRP : mode_t = 8;
+            pub const S_IWGRP : mode_t = 16;
+            pub const S_IRGRP : mode_t = 32;
+            pub const S_IRWXO : mode_t = 7;
+            pub const S_IXOTH : mode_t = 1;
+            pub const S_IWOTH : mode_t = 2;
+            pub const S_IROTH : mode_t = 4;
+            pub const F_OK : c_int = 0;
+            pub const R_OK : c_int = 4;
+            pub const W_OK : c_int = 2;
+            pub const X_OK : c_int = 1;
+            pub const STDIN_FILENO : c_int = 0;
+            pub const STDOUT_FILENO : c_int = 1;
+            pub const STDERR_FILENO : c_int = 2;
+            pub const F_LOCK : c_int = 1;
+            pub const F_TEST : c_int = 3;
+            pub const F_TLOCK : c_int = 2;
+            pub const F_ULOCK : c_int = 0;
+            pub const SIGHUP : c_int = 1;
+            pub const SIGINT : c_int = 2;
+            pub const SIGQUIT : c_int = 3;
+            pub const SIGILL : c_int = 4;
+            pub const SIGABRT : c_int = 6;
+            pub const SIGFPE : c_int = 8;
+            pub const SIGKILL : c_int = 9;
+            pub const SIGSEGV : c_int = 11;
+            pub const SIGPIPE : c_int = 13;
+            pub const SIGALRM : c_int = 14;
+            pub const SIGTERM : c_int = 15;
+
+            pub const PROT_NONE : c_int = 0;
+            pub const PROT_READ : c_int = 1;
+            pub const PROT_WRITE : c_int = 2;
+            pub const PROT_EXEC : c_int = 4;
+
+            pub const MAP_FILE : c_int = 0x0000;
+            pub const MAP_SHARED : c_int = 0x0001;
+            pub const MAP_PRIVATE : c_int = 0x0002;
+            pub const MAP_FIXED : c_int = 0x0010;
+            pub const MAP_ANON : c_int = 0x1000;
+
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
+
+            pub const MCL_CURRENT : c_int = 0x0001;
+            pub const MCL_FUTURE : c_int = 0x0002;
+
+            pub const MS_ASYNC : c_int = 0x0001;
+            pub const MS_SYNC : c_int = 0x0002;
+            pub const MS_INVALIDATE : c_int = 0x0004;
+
+            pub const EPERM : c_int = 1;
+            pub const ENOENT : c_int = 2;
+            pub const ESRCH : c_int = 3;
+            pub const EINTR : c_int = 4;
+            pub const EIO : c_int = 5;
+            pub const ENXIO : c_int = 6;
+            pub const E2BIG : c_int = 7;
+            pub const ENOEXEC : c_int = 8;
+            pub const EBADF : c_int = 9;
+            pub const ECHILD : c_int = 10;
+            pub const EDEADLK : c_int = 11;
+            pub const ENOMEM : c_int = 12;
+            pub const EACCES : c_int = 13;
+            pub const EFAULT : c_int = 14;
+            pub const ENOTBLK : c_int = 15;
+            pub const EBUSY : c_int = 16;
+            pub const EEXIST : c_int = 17;
+            pub const EXDEV : c_int = 18;
+            pub const ENODEV : c_int = 19;
+            pub const ENOTDIR : c_int = 20;
+            pub const EISDIR : c_int = 21;
+            pub const EINVAL : c_int = 22;
+            pub const ENFILE : c_int = 23;
+            pub const EMFILE : c_int = 24;
+            pub const ENOTTY : c_int = 25;
+            pub const ETXTBSY : c_int = 26;
+            pub const EFBIG : c_int = 27;
+            pub const ENOSPC : c_int = 28;
+            pub const ESPIPE : c_int = 29;
+            pub const EROFS : c_int = 30;
+            pub const EMLINK : c_int = 31;
+            pub const EPIPE : c_int = 32;
+            pub const EDOM : c_int = 33;
+            pub const ERANGE : c_int = 34;
+            pub const EAGAIN : c_int = 35;
+            pub const EWOULDBLOCK : c_int = 35;
+            pub const EINPROGRESS : c_int = 36;
+            pub const EALREADY : c_int = 37;
+            pub const ENOTSOCK : c_int = 38;
+            pub const EDESTADDRREQ : c_int = 39;
+            pub const EMSGSIZE : c_int = 40;
+            pub const EPROTOTYPE : c_int = 41;
+            pub const ENOPROTOOPT : c_int = 42;
+            pub const EPROTONOSUPPORT : c_int = 43;
+            pub const ESOCKTNOSUPPORT : c_int = 44;
+            pub const EOPNOTSUPP : c_int = 45;
+            pub const EPFNOSUPPORT : c_int = 46;
+            pub const EAFNOSUPPORT : c_int = 47;
+            pub const EADDRINUSE : c_int = 48;
+            pub const EADDRNOTAVAIL : c_int = 49;
+            pub const ENETDOWN : c_int = 50;
+            pub const ENETUNREACH : c_int = 51;
+            pub const ENETRESET : c_int = 52;
+            pub const ECONNABORTED : c_int = 53;
+            pub const ECONNRESET : c_int = 54;
+            pub const ENOBUFS : c_int = 55;
+            pub const EISCONN : c_int = 56;
+            pub const ENOTCONN : c_int = 57;
+            pub const ESHUTDOWN : c_int = 58;
+            pub const ETOOMANYREFS : c_int = 59;
+            pub const ETIMEDOUT : c_int = 60;
+            pub const ECONNREFUSED : c_int = 61;
+            pub const ELOOP : c_int = 62;
+            pub const ENAMETOOLONG : c_int = 63;
+            pub const EHOSTDOWN : c_int = 64;
+            pub const EHOSTUNREACH : c_int = 65;
+            pub const ENOTEMPTY : c_int = 66;
+            pub const EPROCLIM : c_int = 67;
+            pub const EUSERS : c_int = 68;
+            pub const EDQUOT : c_int = 69;
+            pub const ESTALE : c_int = 70;
+            pub const EREMOTE : c_int = 71;
+            pub const EBADRPC : c_int = 72;
+            pub const ERPCMISMATCH : c_int = 73;
+            pub const EPROGUNAVAIL : c_int = 74;
+            pub const EPROGMISMATCH : c_int = 75;
+            pub const EPROCUNAVAIL : c_int = 76;
+            pub const ENOLCK : c_int = 77;
+            pub const ENOSYS : c_int = 78;
+            pub const EFTYPE : c_int = 79;
+            pub const EAUTH : c_int = 80;
+            pub const ENEEDAUTH : c_int = 81;
+            pub const EIPSEC : c_int = 82;
+            pub const ENOATTR : c_int = 83;
+            pub const EILSEQ : c_int = 84;
+            pub const ENOMEDIUM : c_int = 85;
+            pub const EMEDIUMTYPE : c_int = 86;
+            pub const EOVERFLOW : c_int = 87;
+            pub const ECANCELED : c_int = 88;
+            pub const EIDRM : c_int = 89;
+            pub const ENOMSG : c_int = 90;
+            pub const ENOTSUP : c_int = 91;
+            pub const ELAST : c_int = 91; // must be equal to largest errno
+        }
+        pub mod posix01 {
+            use types::os::arch::c95::{c_int, size_t};
+            use types::os::common::posix01::rlim_t;
+
+            pub const F_DUPFD : c_int = 0;
+            pub const F_GETFD : c_int = 1;
+            pub const F_SETFD : c_int = 2;
+            pub const F_GETFL : c_int = 3;
+            pub const F_SETFL : c_int = 4;
+            pub const F_GETOWN : c_int = 5;
+            pub const F_SETOWN : c_int = 6;
+            pub const F_GETLK : c_int = 7;
+            pub const F_SETLK : c_int = 8;
+            pub const F_SETLKW : c_int = 9;
+            pub const F_DUPFD_CLOEXEC : c_int = 10;
+
+            pub const SIGTRAP : c_int = 5;
+            pub const SIG_IGN: size_t = 1;
+
+            pub const GLOB_APPEND   : c_int = 0x0001;
+            pub const GLOB_DOOFFS   : c_int = 0x0002;
+            pub const GLOB_ERR      : c_int = 0x0004;
+            pub const GLOB_MARK     : c_int = 0x0008;
+            pub const GLOB_NOCHECK  : c_int = 0x0010;
+            pub const GLOB_NOSORT   : c_int = 0x0020;
+            pub const GLOB_NOESCAPE : c_int = 0x1000;
+
+            pub const GLOB_NOSPACE  : c_int = -1;
+            pub const GLOB_ABORTED  : c_int = -2;
+            pub const GLOB_NOMATCH  : c_int = -3;
+            pub const GLOB_NOSYS : c_int = -4;
+
+            pub const POSIX_MADV_NORMAL : c_int = 0;
+            pub const POSIX_MADV_RANDOM : c_int = 1;
+            pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
+            pub const POSIX_MADV_WILLNEED : c_int = 3;
+            pub const POSIX_MADV_DONTNEED : c_int = 4;
+
+            pub const _SC_IOV_MAX : c_int = 51;
+            pub const _SC_GETGR_R_SIZE_MAX : c_int = 100;
+            pub const _SC_GETPW_R_SIZE_MAX : c_int = 101;
+            pub const _SC_LOGIN_NAME_MAX : c_int = 102;
+            pub const _SC_MQ_PRIO_MAX : c_int = 59;
+            pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
+            pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
+            pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 80;
+            pub const _SC_THREAD_KEYS_MAX : c_int = 81;
+            pub const _SC_THREAD_PRIO_INHERIT : c_int = 82;
+            pub const _SC_THREAD_PRIO_PROTECT : c_int = 83;
+            pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 84;
+            pub const _SC_THREAD_PROCESS_SHARED : c_int = 85;
+            pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 103;
+            pub const _SC_THREAD_STACK_MIN : c_int = 89;
+            pub const _SC_THREAD_THREADS_MAX : c_int = 90;
+            pub const _SC_THREADS : c_int = 91;
+            pub const _SC_TTY_NAME_MAX : c_int = 107;
+            pub const _SC_ATEXIT_MAX : c_int = 46;
+            pub const _SC_XOPEN_CRYPT : c_int = 117;
+            pub const _SC_XOPEN_ENH_I18N : c_int = 118;
+            pub const _SC_XOPEN_LEGACY : c_int = 119;
+            pub const _SC_XOPEN_REALTIME : c_int = 120;
+            pub const _SC_XOPEN_REALTIME_THREADS : c_int = 121;
+            pub const _SC_XOPEN_SHM : c_int = 30;
+            pub const _SC_XOPEN_UNIX : c_int = 123;
+            pub const _SC_XOPEN_VERSION : c_int = 125;
+
+            pub const PTHREAD_CREATE_JOINABLE : c_int = 0;
+            pub const PTHREAD_CREATE_DETACHED : c_int = 1;
+            pub const PTHREAD_STACK_MIN : size_t = 2048;
+
+            pub const CLOCK_REALTIME : c_int = 0;
+            pub const CLOCK_MONOTONIC : c_int = 3;
+
+            pub const RLIMIT_CPU: c_int = 0;
+            pub const RLIMIT_FSIZE: c_int = 1;
+            pub const RLIMIT_DATA: c_int = 2;
+            pub const RLIMIT_STACK: c_int = 3;
+            pub const RLIMIT_CORE: c_int = 4;
+            pub const RLIMIT_RSS: c_int = 5;
+            pub const RLIMIT_MEMLOCK: c_int = 6;
+            pub const RLIMIT_NPROC: c_int = 7;
+            pub const RLIMIT_NOFILE: c_int = 8;
+            pub const RLIM_NLIMITS: c_int = 9;
+
+            pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff;
+            pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY;
+            pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY;
+
+            pub const RUSAGE_SELF: c_int = 0;
+            pub const RUSAGE_CHILDREN: c_int = -1;
+            pub const RUSAGE_THREAD: c_int = 1;
+        }
+        pub mod posix08 {
+        }
+        pub mod bsd44 {
+            use types::os::arch::c95::c_int;
+
+            pub const MADV_NORMAL : c_int = 0;
+            pub const MADV_RANDOM : c_int = 1;
+            pub const MADV_SEQUENTIAL : c_int = 2;
+            pub const MADV_WILLNEED : c_int = 3;
+            pub const MADV_DONTNEED : c_int = 4;
+            pub const MADV_FREE : c_int = 6;
+
+            pub const AF_UNIX: c_int = 1;
+            pub const AF_INET: c_int = 2;
+            pub const AF_INET6: c_int = 24;
+            pub const SOCK_STREAM: c_int = 1;
+            pub const SOCK_DGRAM: c_int = 2;
+            pub const SOCK_RAW: c_int = 3;
+            pub const IPPROTO_TCP: c_int = 6;
+            pub const IPPROTO_IP: c_int = 0;
+            pub const IPPROTO_IPV6: c_int = 41;
+            pub const IP_MULTICAST_TTL: c_int = 10;
+            pub const IP_MULTICAST_LOOP: c_int = 11;
+            pub const IP_TTL: c_int = 4;
+            pub const IP_HDRINCL: c_int = 2;
+            pub const IP_ADD_MEMBERSHIP: c_int = 12;
+            pub const IP_DROP_MEMBERSHIP: c_int = 13;
+            pub const IPV6_ADD_MEMBERSHIP: c_int = 12; // don't exist
+            pub const IPV6_DROP_MEMBERSHIP: c_int = 13; // don't exist
+
+            pub const TCP_NODELAY: c_int = 0x01;
+            pub const SOL_SOCKET: c_int = 0xffff;
+            pub const SO_DEBUG: c_int = 0x01;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
+            pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
+
+            pub const IFF_LOOPBACK: c_int = 0x8;
+
+            pub const SHUT_RD: c_int = 0;
+            pub const SHUT_WR: c_int = 1;
+            pub const SHUT_RDWR: c_int = 2;
+        }
+        pub mod extra {
+            use types::os::arch::c95::c_int;
+
+            pub const O_DSYNC : c_int = 128; // same as SYNC
+            pub const O_SYNC : c_int = 128;
+            pub const O_NONBLOCK : c_int = 4;
+            pub const CTL_KERN : c_int = 1;
+            pub const KERN_PROC : c_int = 66;
+
+            pub const MAP_COPY : c_int = 0x0002;
+            pub const MAP_RENAME : c_int = 0x0000;
+            pub const MAP_NORESERVE : c_int = 0x0000;
+            pub const MAP_NOEXTEND : c_int = 0x0000;
+            pub const MAP_HASSEMAPHORE : c_int = 0x0000;
+
+            pub const IPPROTO_RAW : c_int = 255;
+
+            pub const PATH_MAX: c_int = 1024;
+        }
+        pub mod sysconf {
+            use types::os::arch::c95::c_int;
+
+            pub const _SC_ARG_MAX : c_int = 1;
+            pub const _SC_CHILD_MAX : c_int = 2;
+            pub const _SC_CLK_TCK : c_int = 3;
+            pub const _SC_NGROUPS_MAX : c_int = 4;
+            pub const _SC_OPEN_MAX : c_int = 5;
+            pub const _SC_JOB_CONTROL : c_int = 6;
+            pub const _SC_SAVED_IDS : c_int = 7;
+            pub const _SC_VERSION : c_int = 8;
+            pub const _SC_BC_BASE_MAX : c_int = 9;
+            pub const _SC_BC_DIM_MAX : c_int = 10;
+            pub const _SC_BC_SCALE_MAX : c_int = 11;
+            pub const _SC_BC_STRING_MAX : c_int = 12;
+            pub const _SC_COLL_WEIGHTS_MAX : c_int = 13;
+            pub const _SC_EXPR_NEST_MAX : c_int = 14;
+            pub const _SC_LINE_MAX : c_int = 15;
+            pub const _SC_RE_DUP_MAX : c_int = 16;
+            pub const _SC_2_VERSION : c_int = 17;
+            pub const _SC_2_C_BIND : c_int = 18;
+            pub const _SC_2_C_DEV : c_int = 19;
+            pub const _SC_2_CHAR_TERM : c_int = 20;
+            pub const _SC_2_FORT_DEV : c_int = 21;
+            pub const _SC_2_FORT_RUN : c_int = 22;
+            pub const _SC_2_LOCALEDEF : c_int = 23;
+            pub const _SC_2_SW_DEV : c_int = 24;
+            pub const _SC_2_UPE : c_int = 25;
+            pub const _SC_STREAM_MAX : c_int = 26;
+            pub const _SC_TZNAME_MAX : c_int = 27;
+            pub const _SC_PAGESIZE : c_int = 28;
+            pub const _SC_FSYNC : c_int = 29;
+            pub const _SC_SEM_NSEMS_MAX : c_int = 31;
+            pub const _SC_SEM_VALUE_MAX : c_int = 32;
+            pub const _SC_AIO_LISTIO_MAX : c_int = 42;
+            pub const _SC_AIO_MAX : c_int = 43;
+            pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44;
+            pub const _SC_ASYNCHRONOUS_IO : c_int = 45;
+            pub const _SC_DELAYTIMER_MAX : c_int = 50;
+            pub const _SC_MAPPED_FILES : c_int = 53;
+            pub const _SC_MEMLOCK : c_int = 54;
+            pub const _SC_MEMLOCK_RANGE : c_int = 55;
+            pub const _SC_MEMORY_PROTECTION : c_int = 56;
+            pub const _SC_MESSAGE_PASSING : c_int = 57;
+            pub const _SC_MQ_OPEN_MAX : c_int = 58;
+            pub const _SC_PRIORITIZED_IO : c_int = 60;
+            pub const _SC_PRIORITY_SCHEDULING : c_int = 61;
+            pub const _SC_REALTIME_SIGNALS : c_int = 64;
+            pub const _SC_RTSIG_MAX : c_int = 66;
+            pub const _SC_SEMAPHORES : c_int = 67;
+            pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 68;
+            pub const _SC_SIGQUEUE_MAX : c_int = 70;
+            pub const _SC_SYNCHRONIZED_IO : c_int = 75;
+            pub const _SC_TIMER_MAX : c_int = 93;
+            pub const _SC_TIMERS : c_int = 94;
+        }
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub mod os {
+        pub mod c95 {
+            use types::os::arch::c95::{c_int, c_uint};
+
+            pub const EXIT_FAILURE : c_int = 1;
+            pub const EXIT_SUCCESS : c_int = 0;
+            pub const RAND_MAX : c_int = 2147483647;
+            pub const EOF : c_int = -1;
+            pub const SEEK_SET : c_int = 0;
+            pub const SEEK_CUR : c_int = 1;
+            pub const SEEK_END : c_int = 2;
+            pub const _IOFBF : c_int = 0;
+            pub const _IONBF : c_int = 2;
+            pub const _IOLBF : c_int = 1;
+            pub const BUFSIZ : c_uint = 1024;
+            pub const FOPEN_MAX : c_uint = 20;
+            pub const FILENAME_MAX : c_uint = 1024;
+            pub const L_tmpnam : c_uint = 1024;
+            pub const TMP_MAX : c_uint = 308915776;
+        }
+        pub mod c99 {
+        }
+        pub mod posix88 {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::c_int;
+            use types::os::arch::posix88::mode_t;
+
+            pub const O_RDONLY : c_int = 0;
+            pub const O_WRONLY : c_int = 1;
+            pub const O_RDWR : c_int = 2;
+            pub const O_APPEND : c_int = 8;
+            pub const O_CREAT : c_int = 512;
+            pub const O_EXCL : c_int = 2048;
+            pub const O_NOCTTY : c_int = 131072;
+            pub const O_TRUNC : c_int = 1024;
+            pub const S_IFIFO : mode_t = 4096;
+            pub const S_IFCHR : mode_t = 8192;
+            pub const S_IFBLK : mode_t = 24576;
+            pub const S_IFDIR : mode_t = 16384;
+            pub const S_IFREG : mode_t = 32768;
+            pub const S_IFLNK : mode_t = 40960;
+            pub const S_IFMT : mode_t = 61440;
+            pub const S_IEXEC : mode_t = 64;
+            pub const S_IWRITE : mode_t = 128;
+            pub const S_IREAD : mode_t = 256;
+            pub const S_IRWXU : mode_t = 448;
+            pub const S_IXUSR : mode_t = 64;
+            pub const S_IWUSR : mode_t = 128;
+            pub const S_IRUSR : mode_t = 256;
+            pub const S_IRWXG : mode_t = 56;
+            pub const S_IXGRP : mode_t = 8;
+            pub const S_IWGRP : mode_t = 16;
+            pub const S_IRGRP : mode_t = 32;
+            pub const S_IRWXO : mode_t = 7;
+            pub const S_IXOTH : mode_t = 1;
+            pub const S_IWOTH : mode_t = 2;
+            pub const S_IROTH : mode_t = 4;
+            pub const F_OK : c_int = 0;
+            pub const R_OK : c_int = 4;
+            pub const W_OK : c_int = 2;
+            pub const X_OK : c_int = 1;
+            pub const STDIN_FILENO : c_int = 0;
+            pub const STDOUT_FILENO : c_int = 1;
+            pub const STDERR_FILENO : c_int = 2;
+            pub const F_LOCK : c_int = 1;
+            pub const F_TEST : c_int = 3;
+            pub const F_TLOCK : c_int = 2;
+            pub const F_ULOCK : c_int = 0;
+            pub const SIGHUP : c_int = 1;
+            pub const SIGINT : c_int = 2;
+            pub const SIGQUIT : c_int = 3;
+            pub const SIGILL : c_int = 4;
+            pub const SIGABRT : c_int = 6;
+            pub const SIGFPE : c_int = 8;
+            pub const SIGKILL : c_int = 9;
+            pub const SIGSEGV : c_int = 11;
+            pub const SIGPIPE : c_int = 13;
+            pub const SIGALRM : c_int = 14;
+            pub const SIGTERM : c_int = 15;
+
+            pub const PROT_NONE : c_int = 0;
+            pub const PROT_READ : c_int = 1;
+            pub const PROT_WRITE : c_int = 2;
+            pub const PROT_EXEC : c_int = 4;
+
+            pub const MAP_FILE : c_int = 0x0000;
+            pub const MAP_SHARED : c_int = 0x0001;
+            pub const MAP_PRIVATE : c_int = 0x0002;
+            pub const MAP_FIXED : c_int = 0x0010;
+            pub const MAP_ANON : c_int = 0x1000;
+
+            pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
+
+            pub const MCL_CURRENT : c_int = 0x0001;
+            pub const MCL_FUTURE : c_int = 0x0002;
+
+            pub const MS_ASYNC : c_int = 0x0001;
+            pub const MS_INVALIDATE : c_int = 0x0002;
+            pub const MS_SYNC : c_int = 0x0010;
+
+            pub const MS_KILLPAGES : c_int = 0x0004;
+            pub const MS_DEACTIVATE : c_int = 0x0008;
+
+            pub const EPERM : c_int = 1;
+            pub const ENOENT : c_int = 2;
+            pub const ESRCH : c_int = 3;
+            pub const EINTR : c_int = 4;
+            pub const EIO : c_int = 5;
+            pub const ENXIO : c_int = 6;
+            pub const E2BIG : c_int = 7;
+            pub const ENOEXEC : c_int = 8;
+            pub const EBADF : c_int = 9;
+            pub const ECHILD : c_int = 10;
+            pub const EDEADLK : c_int = 11;
+            pub const ENOMEM : c_int = 12;
+            pub const EACCES : c_int = 13;
+            pub const EFAULT : c_int = 14;
+            pub const ENOTBLK : c_int = 15;
+            pub const EBUSY : c_int = 16;
+            pub const EEXIST : c_int = 17;
+            pub const EXDEV : c_int = 18;
+            pub const ENODEV : c_int = 19;
+            pub const ENOTDIR : c_int = 20;
+            pub const EISDIR : c_int = 21;
+            pub const EINVAL : c_int = 22;
+            pub const ENFILE : c_int = 23;
+            pub const EMFILE : c_int = 24;
+            pub const ENOTTY : c_int = 25;
+            pub const ETXTBSY : c_int = 26;
+            pub const EFBIG : c_int = 27;
+            pub const ENOSPC : c_int = 28;
+            pub const ESPIPE : c_int = 29;
+            pub const EROFS : c_int = 30;
+            pub const EMLINK : c_int = 31;
+            pub const EPIPE : c_int = 32;
+            pub const EDOM : c_int = 33;
+            pub const ERANGE : c_int = 34;
+            pub const EAGAIN : c_int = 35;
+            pub const EWOULDBLOCK : c_int = EAGAIN;
+            pub const EINPROGRESS : c_int = 36;
+            pub const EALREADY : c_int = 37;
+            pub const ENOTSOCK : c_int = 38;
+            pub const EDESTADDRREQ : c_int = 39;
+            pub const EMSGSIZE : c_int = 40;
+            pub const EPROTOTYPE : c_int = 41;
+            pub const ENOPROTOOPT : c_int = 42;
+            pub const EPROTONOSUPPORT : c_int = 43;
+            pub const ESOCKTNOSUPPORT : c_int = 44;
+            pub const ENOTSUP : c_int = 45;
+            pub const EPFNOSUPPORT : c_int = 46;
+            pub const EAFNOSUPPORT : c_int = 47;
+            pub const EADDRINUSE : c_int = 48;
+            pub const EADDRNOTAVAIL : c_int = 49;
+            pub const ENETDOWN : c_int = 50;
+            pub const ENETUNREACH : c_int = 51;
+            pub const ENETRESET : c_int = 52;
+            pub const ECONNABORTED : c_int = 53;
+            pub const ECONNRESET : c_int = 54;
+            pub const ENOBUFS : c_int = 55;
+            pub const EISCONN : c_int = 56;
+            pub const ENOTCONN : c_int = 57;
+            pub const ESHUTDOWN : c_int = 58;
+            pub const ETOOMANYREFS : c_int = 59;
+            pub const ETIMEDOUT : c_int = 60;
+            pub const ECONNREFUSED : c_int = 61;
+            pub const ELOOP : c_int = 62;
+            pub const ENAMETOOLONG : c_int = 63;
+            pub const EHOSTDOWN : c_int = 64;
+            pub const EHOSTUNREACH : c_int = 65;
+            pub const ENOTEMPTY : c_int = 66;
+            pub const EPROCLIM : c_int = 67;
+            pub const EUSERS : c_int = 68;
+            pub const EDQUOT : c_int = 69;
+            pub const ESTALE : c_int = 70;
+            pub const EREMOTE : c_int = 71;
+            pub const EBADRPC : c_int = 72;
+            pub const ERPCMISMATCH : c_int = 73;
+            pub const EPROGUNAVAIL : c_int = 74;
+            pub const EPROGMISMATCH : c_int = 75;
+            pub const EPROCUNAVAIL : c_int = 76;
+            pub const ENOLCK : c_int = 77;
+            pub const ENOSYS : c_int = 78;
+            pub const EFTYPE : c_int = 79;
+            pub const EAUTH : c_int = 80;
+            pub const ENEEDAUTH : c_int = 81;
+            pub const EPWROFF : c_int = 82;
+            pub const EDEVERR : c_int = 83;
+            pub const EOVERFLOW : c_int = 84;
+            pub const EBADEXEC : c_int = 85;
+            pub const EBADARCH : c_int = 86;
+            pub const ESHLIBVERS : c_int = 87;
+            pub const EBADMACHO : c_int = 88;
+            pub const ECANCELED : c_int = 89;
+            pub const EIDRM : c_int = 90;
+            pub const ENOMSG : c_int = 91;
+            pub const EILSEQ : c_int = 92;
+            pub const ENOATTR : c_int = 93;
+            pub const EBADMSG : c_int = 94;
+            pub const EMULTIHOP : c_int = 95;
+            pub const ENODATA : c_int = 96;
+            pub const ENOLINK : c_int = 97;
+            pub const ENOSR : c_int = 98;
+            pub const ENOSTR : c_int = 99;
+            pub const EPROTO : c_int = 100;
+            pub const ETIME : c_int = 101;
+            pub const EOPNOTSUPP : c_int = 102;
+            pub const ENOPOLICY : c_int = 103;
+            pub const ENOTRECOVERABLE : c_int = 104;
+            pub const EOWNERDEAD : c_int = 105;
+            pub const EQFULL : c_int = 106;
+            pub const ELAST : c_int = 106;
+        }
+        pub mod posix01 {
+            use types::os::arch::c95::{c_int, size_t};
+            use types::os::common::posix01::rlim_t;
+
+            pub const F_DUPFD : c_int = 0;
+            pub const F_GETFD : c_int = 1;
+            pub const F_SETFD : c_int = 2;
+            pub const F_GETFL : c_int = 3;
+            pub const F_SETFL : c_int = 4;
+
+            pub const SIGTRAP : c_int = 5;
+            pub const SIG_IGN: size_t = 1;
+
+            pub const GLOB_APPEND   : c_int = 0x0001;
+            pub const GLOB_DOOFFS   : c_int = 0x0002;
+            pub const GLOB_ERR      : c_int = 0x0004;
+            pub const GLOB_MARK     : c_int = 0x0008;
+            pub const GLOB_NOCHECK  : c_int = 0x0010;
+            pub const GLOB_NOSORT   : c_int = 0x0020;
+            pub const GLOB_NOESCAPE : c_int = 0x2000;
+
+            pub const GLOB_NOSPACE  : c_int = -1;
+            pub const GLOB_ABORTED  : c_int = -2;
+            pub const GLOB_NOMATCH  : c_int = -3;
+
+            pub const POSIX_MADV_NORMAL : c_int = 0;
+            pub const POSIX_MADV_RANDOM : c_int = 1;
+            pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
+            pub const POSIX_MADV_WILLNEED : c_int = 3;
+            pub const POSIX_MADV_DONTNEED : c_int = 4;
+
+            pub const _SC_IOV_MAX : c_int = 56;
+            pub const _SC_GETGR_R_SIZE_MAX : c_int = 70;
+            pub const _SC_GETPW_R_SIZE_MAX : c_int = 71;
+            pub const _SC_LOGIN_NAME_MAX : c_int = 73;
+            pub const _SC_MQ_PRIO_MAX : c_int = 75;
+            pub const _SC_THREAD_ATTR_STACKADDR : c_int = 82;
+            pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 83;
+            pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85;
+            pub const _SC_THREAD_KEYS_MAX : c_int = 86;
+            pub const _SC_THREAD_PRIO_INHERIT : c_int = 87;
+            pub const _SC_THREAD_PRIO_PROTECT : c_int = 88;
+            pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89;
+            pub const _SC_THREAD_PROCESS_SHARED : c_int = 90;
+            pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 91;
+            pub const _SC_THREAD_STACK_MIN : c_int = 93;
+            pub const _SC_THREAD_THREADS_MAX : c_int = 94;
+            pub const _SC_THREADS : c_int = 96;
+            pub const _SC_TTY_NAME_MAX : c_int = 101;
+            pub const _SC_ATEXIT_MAX : c_int = 107;
+            pub const _SC_XOPEN_CRYPT : c_int = 108;
+            pub const _SC_XOPEN_ENH_I18N : c_int = 109;
+            pub const _SC_XOPEN_LEGACY : c_int = 110;
+            pub const _SC_XOPEN_REALTIME : c_int = 111;
+            pub const _SC_XOPEN_REALTIME_THREADS : c_int = 112;
+            pub const _SC_XOPEN_SHM : c_int = 113;
+            pub const _SC_XOPEN_UNIX : c_int = 115;
+            pub const _SC_XOPEN_VERSION : c_int = 116;
+            pub const _SC_XOPEN_XCU_VERSION : c_int = 121;
+
+            pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
+            pub const PTHREAD_CREATE_DETACHED: c_int = 2;
+            pub const PTHREAD_STACK_MIN: size_t = 8192;
+
+            pub const RLIMIT_CPU: c_int = 0;
+            pub const RLIMIT_FSIZE: c_int = 1;
+            pub const RLIMIT_DATA: c_int = 2;
+            pub const RLIMIT_STACK: c_int = 3;
+            pub const RLIMIT_CORE: c_int = 4;
+            pub const RLIMIT_AS: c_int = 5;
+            pub const RLIMIT_MEMLOCK: c_int = 6;
+            pub const RLIMIT_NPROC: c_int = 7;
+            pub const RLIMIT_NOFILE: c_int = 8;
+            pub const RLIM_NLIMITS: c_int = 9;
+            pub const _RLIMIT_POSIX_FLAG: c_int = 0x1000;
+
+            pub const RLIM_INFINITY: rlim_t = 0xffff_ffff_ffff_ffff;
+
+            pub const RUSAGE_SELF: c_int = 0;
+            pub const RUSAGE_CHILDREN: c_int = -1;
+            pub const RUSAGE_THREAD: c_int = 1;
+        }
+        pub mod posix08 {
+        }
+        pub mod bsd44 {
+            use types::os::arch::c95::c_int;
+
+            pub const MADV_NORMAL : c_int = 0;
+            pub const MADV_RANDOM : c_int = 1;
+            pub const MADV_SEQUENTIAL : c_int = 2;
+            pub const MADV_WILLNEED : c_int = 3;
+            pub const MADV_DONTNEED : c_int = 4;
+            pub const MADV_FREE : c_int = 5;
+            pub const MADV_ZERO_WIRED_PAGES : c_int = 6;
+            pub const MADV_FREE_REUSABLE : c_int = 7;
+            pub const MADV_FREE_REUSE : c_int = 8;
+            pub const MADV_CAN_REUSE : c_int = 9;
+
+            pub const MINCORE_INCORE : c_int =  0x1;
+            pub const MINCORE_REFERENCED : c_int = 0x2;
+            pub const MINCORE_MODIFIED : c_int = 0x4;
+            pub const MINCORE_REFERENCED_OTHER : c_int = 0x8;
+            pub const MINCORE_MODIFIED_OTHER : c_int = 0x10;
+
+            pub const AF_UNIX: c_int = 1;
+            pub const AF_INET: c_int = 2;
+            pub const AF_INET6: c_int = 30;
+            pub const SOCK_STREAM: c_int = 1;
+            pub const SOCK_DGRAM: c_int = 2;
+            pub const SOCK_RAW: c_int = 3;
+            pub const IPPROTO_TCP: c_int = 6;
+            pub const IPPROTO_IP: c_int = 0;
+            pub const IPPROTO_IPV6: c_int = 41;
+            pub const IP_MULTICAST_TTL: c_int = 10;
+            pub const IP_MULTICAST_LOOP: c_int = 11;
+            pub const IP_TTL: c_int = 4;
+            pub const IP_HDRINCL: c_int = 2;
+            pub const IP_ADD_MEMBERSHIP: c_int = 12;
+            pub const IP_DROP_MEMBERSHIP: c_int = 13;
+            pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
+            pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
+
+            pub const TCP_NODELAY: c_int = 0x01;
+            pub const TCP_KEEPALIVE: c_int = 0x10;
+            pub const SOL_SOCKET: c_int = 0xffff;
+
+            pub const SO_DEBUG: c_int = 0x01;
+            pub const SO_ACCEPTCONN: c_int = 0x0002;
+            pub const SO_REUSEADDR: c_int = 0x0004;
+            pub const SO_KEEPALIVE: c_int = 0x0008;
+            pub const SO_DONTROUTE: c_int = 0x0010;
+            pub const SO_BROADCAST: c_int = 0x0020;
+            pub const SO_USELOOPBACK: c_int = 0x0040;
+            pub const SO_LINGER: c_int = 0x0080;
+            pub const SO_OOBINLINE: c_int = 0x0100;
+            pub const SO_REUSEPORT: c_int = 0x0200;
+            pub const SO_SNDBUF: c_int = 0x1001;
+            pub const SO_RCVBUF: c_int = 0x1002;
+            pub const SO_SNDLOWAT: c_int = 0x1003;
+            pub const SO_RCVLOWAT: c_int = 0x1004;
+            pub const SO_SNDTIMEO: c_int = 0x1005;
+            pub const SO_RCVTIMEO: c_int = 0x1006;
+            pub const SO_ERROR: c_int = 0x1007;
+            pub const SO_TYPE: c_int = 0x1008;
+
+            pub const IFF_LOOPBACK: c_int = 0x8;
+
+            pub const SHUT_RD: c_int = 0;
+            pub const SHUT_WR: c_int = 1;
+            pub const SHUT_RDWR: c_int = 2;
+        }
+        pub mod extra {
+            use types::os::arch::c95::c_int;
+
+            pub const O_DSYNC : c_int = 4194304;
+            pub const O_SYNC : c_int = 128;
+            pub const O_NONBLOCK : c_int = 4;
+            pub const F_FULLFSYNC : c_int = 51;
+
+            pub const MAP_COPY : c_int = 0x0002;
+            pub const MAP_RENAME : c_int = 0x0020;
+            pub const MAP_NORESERVE : c_int = 0x0040;
+            pub const MAP_NOEXTEND : c_int = 0x0100;
+            pub const MAP_HASSEMAPHORE : c_int = 0x0200;
+            pub const MAP_NOCACHE : c_int = 0x0400;
+            pub const MAP_JIT : c_int = 0x0800;
+            pub const MAP_STACK : c_int = 0;
+
+            pub const IPPROTO_RAW : c_int = 255;
+
+            pub const SO_NREAD: c_int = 0x1020;
+            pub const SO_NKE: c_int = 0x1021;
+            pub const SO_NOSIGPIPE: c_int = 0x1022;
+            pub const SO_NOADDRERR: c_int = 0x1023;
+            pub const SO_NWRITE: c_int = 0x1024;
+            pub const SO_DONTTRUNC: c_int = 0x2000;
+            pub const SO_WANTMORE: c_int = 0x4000;
+            pub const SO_WANTOOBFLAG: c_int = 0x8000;
+        }
+        pub mod sysconf {
+            use types::os::arch::c95::c_int;
+
+            pub const _SC_ARG_MAX : c_int = 1;
+            pub const _SC_CHILD_MAX : c_int = 2;
+            pub const _SC_CLK_TCK : c_int = 3;
+            pub const _SC_NGROUPS_MAX : c_int = 4;
+            pub const _SC_OPEN_MAX : c_int = 5;
+            pub const _SC_JOB_CONTROL : c_int = 6;
+            pub const _SC_SAVED_IDS : c_int = 7;
+            pub const _SC_VERSION : c_int = 8;
+            pub const _SC_BC_BASE_MAX : c_int = 9;
+            pub const _SC_BC_DIM_MAX : c_int = 10;
+            pub const _SC_BC_SCALE_MAX : c_int = 11;
+            pub const _SC_BC_STRING_MAX : c_int = 12;
+            pub const _SC_COLL_WEIGHTS_MAX : c_int = 13;
+            pub const _SC_EXPR_NEST_MAX : c_int = 14;
+            pub const _SC_LINE_MAX : c_int = 15;
+            pub const _SC_RE_DUP_MAX : c_int = 16;
+            pub const _SC_2_VERSION : c_int = 17;
+            pub const _SC_2_C_BIND : c_int = 18;
+            pub const _SC_2_C_DEV : c_int = 19;
+            pub const _SC_2_CHAR_TERM : c_int = 20;
+            pub const _SC_2_FORT_DEV : c_int = 21;
+            pub const _SC_2_FORT_RUN : c_int = 22;
+            pub const _SC_2_LOCALEDEF : c_int = 23;
+            pub const _SC_2_SW_DEV : c_int = 24;
+            pub const _SC_2_UPE : c_int = 25;
+            pub const _SC_STREAM_MAX : c_int = 26;
+            pub const _SC_TZNAME_MAX : c_int = 27;
+            pub const _SC_ASYNCHRONOUS_IO : c_int = 28;
+            pub const _SC_PAGESIZE : c_int = 29;
+            pub const _SC_MEMLOCK : c_int = 30;
+            pub const _SC_MEMLOCK_RANGE : c_int = 31;
+            pub const _SC_MEMORY_PROTECTION : c_int = 32;
+            pub const _SC_MESSAGE_PASSING : c_int = 33;
+            pub const _SC_PRIORITIZED_IO : c_int = 34;
+            pub const _SC_PRIORITY_SCHEDULING : c_int = 35;
+            pub const _SC_REALTIME_SIGNALS : c_int = 36;
+            pub const _SC_SEMAPHORES : c_int = 37;
+            pub const _SC_FSYNC : c_int = 38;
+            pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 39;
+            pub const _SC_SYNCHRONIZED_IO : c_int = 40;
+            pub const _SC_TIMERS : c_int = 41;
+            pub const _SC_AIO_LISTIO_MAX : c_int = 42;
+            pub const _SC_AIO_MAX : c_int = 43;
+            pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44;
+            pub const _SC_DELAYTIMER_MAX : c_int = 45;
+            pub const _SC_MQ_OPEN_MAX : c_int = 46;
+            pub const _SC_MAPPED_FILES : c_int = 47;
+            pub const _SC_RTSIG_MAX : c_int = 48;
+            pub const _SC_SEM_NSEMS_MAX : c_int = 49;
+            pub const _SC_SEM_VALUE_MAX : c_int = 50;
+            pub const _SC_SIGQUEUE_MAX : c_int = 51;
+            pub const _SC_TIMER_MAX : c_int = 52;
+            pub const _SC_NPROCESSORS_CONF : c_int = 57;
+            pub const _SC_NPROCESSORS_ONLN : c_int = 58;
+            pub const _SC_2_PBS : c_int = 59;
+            pub const _SC_2_PBS_ACCOUNTING : c_int = 60;
+            pub const _SC_2_PBS_CHECKPOINT : c_int = 61;
+            pub const _SC_2_PBS_LOCATE : c_int = 62;
+            pub const _SC_2_PBS_MESSAGE : c_int = 63;
+            pub const _SC_2_PBS_TRACK : c_int = 64;
+            pub const _SC_ADVISORY_INFO : c_int = 65;
+            pub const _SC_BARRIERS : c_int = 66;
+            pub const _SC_CLOCK_SELECTION : c_int = 67;
+            pub const _SC_CPUTIME : c_int = 68;
+            pub const _SC_FILE_LOCKING : c_int = 69;
+            pub const _SC_HOST_NAME_MAX : c_int = 72;
+            pub const _SC_MONOTONIC_CLOCK : c_int = 74;
+            pub const _SC_READER_WRITER_LOCKS : c_int = 76;
+            pub const _SC_REGEXP : c_int = 77;
+            pub const _SC_SHELL : c_int = 78;
+            pub const _SC_SPAWN : c_int = 79;
+            pub const _SC_SPIN_LOCKS : c_int = 80;
+            pub const _SC_SPORADIC_SERVER : c_int = 81;
+            pub const _SC_THREAD_CPUTIME : c_int = 84;
+            pub const _SC_THREAD_SPORADIC_SERVER : c_int = 92;
+            pub const _SC_TIMEOUTS : c_int = 95;
+            pub const _SC_TRACE : c_int = 97;
+            pub const _SC_TRACE_EVENT_FILTER : c_int = 98;
+            pub const _SC_TRACE_INHERIT : c_int = 99;
+            pub const _SC_TRACE_LOG : c_int = 100;
+            pub const _SC_TYPED_MEMORY_OBJECTS : c_int = 102;
+            pub const _SC_V6_ILP32_OFF32 : c_int = 103;
+            pub const _SC_V6_ILP32_OFFBIG : c_int = 104;
+            pub const _SC_V6_LP64_OFF64 : c_int = 105;
+            pub const _SC_V6_LPBIG_OFFBIG : c_int = 106;
+            pub const _SC_IPV6 : c_int = 118;
+            pub const _SC_RAW_SOCKETS : c_int = 119;
+            pub const _SC_SYMLOOP_MAX : c_int = 120;
+            pub const _SC_PAGE_SIZE : c_int = _SC_PAGESIZE;
+            pub const _SC_XOPEN_STREAMS : c_int = 114;
+            pub const _SC_XBS5_ILP32_OFF32 : c_int = 122;
+            pub const _SC_XBS5_ILP32_OFFBIG : c_int = 123;
+            pub const _SC_XBS5_LP64_OFF64 : c_int = 124;
+            pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 125;
+            pub const _SC_SS_REPL_MAX : c_int = 126;
+            pub const _SC_TRACE_EVENT_NAME_MAX : c_int = 127;
+            pub const _SC_TRACE_NAME_MAX : c_int = 128;
+            pub const _SC_TRACE_SYS_MAX : c_int = 129;
+            pub const _SC_TRACE_USER_EVENT_MAX : c_int = 130;
+            pub const _SC_PASS_MAX : c_int = 131;
+        }
+    }
+}
+
+
+pub mod funcs {
+    // Thankfully most of c95 is universally available and does not vary by OS
+    // or anything. The same is not true of POSIX.
+
+    pub mod c95 {
+        pub mod ctype {
+            use types::os::arch::c95::{c_char, c_int};
+
+            extern {
+                pub fn isalnum(c: c_int) -> c_int;
+                pub fn isalpha(c: c_int) -> c_int;
+                pub fn iscntrl(c: c_int) -> c_int;
+                pub fn isdigit(c: c_int) -> c_int;
+                pub fn isgraph(c: c_int) -> c_int;
+                pub fn islower(c: c_int) -> c_int;
+                pub fn isprint(c: c_int) -> c_int;
+                pub fn ispunct(c: c_int) -> c_int;
+                pub fn isspace(c: c_int) -> c_int;
+                pub fn isupper(c: c_int) -> c_int;
+                pub fn isxdigit(c: c_int) -> c_int;
+                pub fn tolower(c: c_char) -> c_char;
+                pub fn toupper(c: c_char) -> c_char;
+            }
+        }
+
+        pub mod stdio {
+            use types::common::c95::{FILE, c_void, fpos_t};
+            use types::os::arch::c95::{c_char, c_int, c_long, size_t};
+
+            extern {
+                pub fn fopen(filename: *const c_char,
+                             mode: *const c_char) -> *mut FILE;
+                pub fn freopen(filename: *const c_char, mode: *const c_char,
+                               file: *mut FILE)
+                               -> *mut FILE;
+                pub fn fflush(file: *mut FILE) -> c_int;
+                pub fn fclose(file: *mut FILE) -> c_int;
+                pub fn remove(filename: *const c_char) -> c_int;
+                pub fn rename(oldname: *const c_char,
+                              newname: *const c_char) -> c_int;
+                pub fn tmpfile() -> *mut FILE;
+                pub fn setvbuf(stream: *mut FILE,
+                               buffer: *mut c_char,
+                               mode: c_int,
+                               size: size_t)
+                               -> c_int;
+                pub fn setbuf(stream: *mut FILE, buf: *mut c_char);
+                // Omitted: printf and scanf variants.
+                pub fn fgetc(stream: *mut FILE) -> c_int;
+                pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE)
+                             -> *mut c_char;
+                pub fn fputc(c: c_int, stream: *mut FILE) -> c_int;
+                pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int;
+                // Omitted: getc, getchar (might be macros).
+
+                // Omitted: gets, so ridiculously unsafe that it should not
+                // survive.
+
+                // Omitted: putc, putchar (might be macros).
+                pub fn puts(s: *const c_char) -> c_int;
+                pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int;
+                pub fn fread(ptr: *mut c_void,
+                             size: size_t,
+                             nobj: size_t,
+                             stream: *mut FILE)
+                             -> size_t;
+                pub fn fwrite(ptr: *const c_void,
+                              size: size_t,
+                              nobj: size_t,
+                              stream: *mut FILE)
+                              -> size_t;
+                pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int)
+                             -> c_int;
+                pub fn ftell(stream: *mut FILE) -> c_long;
+                pub fn rewind(stream: *mut FILE);
+                pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
+                pub fn fsetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
+                pub fn feof(stream: *mut FILE) -> c_int;
+                pub fn ferror(stream: *mut FILE) -> c_int;
+                pub fn perror(s: *const c_char);
+            }
+        }
+
+        pub mod stdlib {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::{c_char, c_double, c_int};
+            use types::os::arch::c95::{c_long, c_uint, c_ulong};
+            use types::os::arch::c95::{size_t};
+
+            extern {
+                pub fn abs(i: c_int) -> c_int;
+                pub fn labs(i: c_long) -> c_long;
+                // Omitted: div, ldiv (return pub type incomplete).
+                pub fn atof(s: *const c_char) -> c_double;
+                pub fn atoi(s: *const c_char) -> c_int;
+                pub fn strtod(s: *const c_char,
+                              endp: *mut *mut c_char) -> c_double;
+                pub fn strtol(s: *const c_char,
+                              endp: *mut *mut c_char, base: c_int) -> c_long;
+                pub fn strtoul(s: *const c_char, endp: *mut *mut c_char,
+                               base: c_int) -> c_ulong;
+                pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void;
+                pub fn malloc(size: size_t) -> *mut c_void;
+                pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
+                pub fn free(p: *mut c_void);
+
+                /// Exits the running program in a possibly dangerous manner.
+                ///
+                /// # Unsafety
+                ///
+                /// While this forces your program to exit, it does so in a way that has
+                /// consequences. This will skip all unwinding code, which means that anything
+                /// relying on unwinding for cleanup (such as flushing and closing a buffer to a
+                /// file) may act in an unexpected way.
+                ///
+                /// # Examples
+                ///
+                /// ```no_run,ignore
+                /// extern crate libc;
+                ///
+                /// fn main() {
+                ///     unsafe {
+                ///         libc::exit(1);
+                ///     }
+                /// }
+                /// ```
+                pub fn exit(status: c_int) -> !;
+                pub fn _exit(status: c_int) -> !;
+                pub fn atexit(cb: extern fn()) -> c_int;
+                pub fn system(s: *const c_char) -> c_int;
+                pub fn getenv(s: *const c_char) -> *mut c_char;
+                // Omitted: bsearch, qsort
+                pub fn rand() -> c_int;
+                pub fn srand(seed: c_uint);
+            }
+        }
+
+        pub mod string {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::{c_char, c_int, size_t};
+            use types::os::arch::c95::{wchar_t};
+
+            extern {
+                pub fn strcpy(dst: *mut c_char,
+                              src: *const c_char) -> *mut c_char;
+                pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t)
+                               -> *mut c_char;
+                pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char;
+                pub fn strncat(s: *mut c_char, ct: *const c_char,
+                               n: size_t) -> *mut c_char;
+                pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
+                pub fn strncmp(cs: *const c_char, ct: *const c_char,
+                               n: size_t) -> c_int;
+                pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
+                pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char;
+                pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char;
+                pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t;
+                pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t;
+                pub fn strpbrk(cs: *const c_char,
+                               ct: *const c_char) -> *mut c_char;
+                pub fn strstr(cs: *const c_char,
+                              ct: *const c_char) -> *mut c_char;
+                pub fn strlen(cs: *const c_char) -> size_t;
+                pub fn strerror(n: c_int) -> *mut c_char;
+                pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char;
+                pub fn strxfrm(s: *mut c_char, ct: *const c_char,
+                               n: size_t) -> size_t;
+                pub fn wcslen(buf: *const wchar_t) -> size_t;
+
+                // Omitted: memcpy, memmove, memset (provided by LLVM)
+
+                // These are fine to execute on the Rust stack. They must be,
+                // in fact, because LLVM generates calls to them!
+                pub fn memcmp(cx: *const c_void, ct: *const c_void,
+                              n: size_t) -> c_int;
+                pub fn memchr(cx: *const c_void, c: c_int,
+                              n: size_t) -> *mut c_void;
+            }
+        }
+    }
+
+    // Microsoft helpfully underscore-qualifies all of its POSIX-like symbols
+    // to make sure you don't use them accidentally. It also randomly deviates
+    // from the exact signatures you might otherwise expect, and omits much,
+    // so be careful when trying to write portable code; it won't always work
+    // with the same POSIX functions and types as other platforms.
+
+    #[cfg(target_os = "windows")]
+    pub mod posix88 {
+        pub mod stat_ {
+            use types::os::common::posix01::{stat, utimbuf};
+            use types::os::arch::c95::{c_int, c_char, wchar_t};
+
+            extern {
+                #[link_name = "_chmod"]
+                pub fn chmod(path: *const c_char, mode: c_int) -> c_int;
+                #[link_name = "_wchmod"]
+                pub fn wchmod(path: *const wchar_t, mode: c_int) -> c_int;
+                #[link_name = "_mkdir"]
+                pub fn mkdir(path: *const c_char) -> c_int;
+                #[link_name = "_wrmdir"]
+                pub fn wrmdir(path: *const wchar_t) -> c_int;
+                #[link_name = "_fstat64"]
+                pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
+                #[link_name = "_stat64"]
+                pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
+                #[link_name = "_wstat64"]
+                pub fn wstat(path: *const wchar_t, buf: *mut stat) -> c_int;
+                #[link_name = "_wutime64"]
+                pub fn wutime(file: *const wchar_t, buf: *mut utimbuf) -> c_int;
+            }
+        }
+
+        pub mod stdio {
+            use types::common::c95::FILE;
+            use types::os::arch::c95::{c_int, c_char};
+
+            extern {
+                #[link_name = "_popen"]
+                pub fn popen(command: *const c_char,
+                             mode: *const c_char) -> *mut FILE;
+                #[link_name = "_pclose"]
+                pub fn pclose(stream: *mut FILE) -> c_int;
+                #[link_name = "_fdopen"]
+                pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE;
+                #[link_name = "_fileno"]
+                pub fn fileno(stream: *mut FILE) -> c_int;
+            }
+        }
+
+        pub mod fcntl {
+            use types::os::arch::c95::{c_int, c_char, wchar_t};
+            extern {
+                #[link_name = "_open"]
+                pub fn open(path: *const c_char, oflag: c_int, mode: c_int)
+                            -> c_int;
+                #[link_name = "_wopen"]
+                pub fn wopen(path: *const wchar_t, oflag: c_int, mode: c_int)
+                            -> c_int;
+                #[link_name = "_creat"]
+                pub fn creat(path: *const c_char, mode: c_int) -> c_int;
+            }
+        }
+
+        pub mod dirent {
+            // Not supplied at all.
+        }
+
+        pub mod unistd {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::{c_int, c_uint, c_char,
+                                             c_long, size_t};
+            use types::os::arch::c99::intptr_t;
+
+            extern {
+                #[link_name = "_access"]
+                pub fn access(path: *const c_char, amode: c_int) -> c_int;
+                #[link_name = "_chdir"]
+                pub fn chdir(dir: *const c_char) -> c_int;
+                #[link_name = "_close"]
+                pub fn close(fd: c_int) -> c_int;
+                #[link_name = "_dup"]
+                pub fn dup(fd: c_int) -> c_int;
+                #[link_name = "_dup2"]
+                pub fn dup2(src: c_int, dst: c_int) -> c_int;
+                #[link_name = "_execv"]
+                pub fn execv(prog: *const c_char,
+                             argv: *mut *const c_char) -> intptr_t;
+                #[link_name = "_execve"]
+                pub fn execve(prog: *const c_char, argv: *mut *const c_char,
+                              envp: *mut *const c_char)
+                              -> c_int;
+                #[link_name = "_execvp"]
+                pub fn execvp(c: *const c_char,
+                              argv: *mut *const c_char) -> c_int;
+                #[link_name = "_execvpe"]
+                pub fn execvpe(c: *const c_char, argv: *mut *const c_char,
+                               envp: *mut *const c_char) -> c_int;
+                #[link_name = "_getcwd"]
+                pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
+                #[link_name = "_getpid"]
+                pub fn getpid() -> c_int;
+                #[link_name = "_isatty"]
+                pub fn isatty(fd: c_int) -> c_int;
+                #[link_name = "_lseek"]
+                pub fn lseek(fd: c_int, offset: c_long, origin: c_int)
+                             -> c_long;
+                #[link_name = "_pipe"]
+                pub fn pipe(fds: *mut c_int, psize: c_uint, textmode: c_int)
+                            -> c_int;
+                #[link_name = "_read"]
+                pub fn read(fd: c_int, buf: *mut c_void, count: c_uint)
+                            -> c_int;
+                #[link_name = "_rmdir"]
+                pub fn rmdir(path: *const c_char) -> c_int;
+                #[link_name = "_unlink"]
+                pub fn unlink(c: *const c_char) -> c_int;
+                #[link_name = "_write"]
+                pub fn write(fd: c_int, buf: *const c_void,
+                             count: c_uint) -> c_int;
+            }
+        }
+
+        pub mod mman {
+        }
+    }
+
+    #[cfg(any(target_os = "linux",
+              target_os = "android",
+              target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd",
+              target_os = "dragonfly",
+              target_os = "bitrig",
+              target_os = "openbsd",
+              target_os = "nacl"))]
+    pub mod posix88 {
+        pub mod stat_ {
+            use types::os::arch::c95::{c_char, c_int};
+            use types::os::arch::posix01::stat;
+            use types::os::arch::posix88::mode_t;
+
+            extern {
+                pub fn chmod(path: *const c_char, mode: mode_t) -> c_int;
+                pub fn fchmod(fd: c_int, mode: mode_t) -> c_int;
+
+                #[cfg(any(target_os = "linux",
+                          target_os = "freebsd",
+                          target_os = "dragonfly",
+                          target_os = "bitrig",
+                          target_os = "openbsd",
+                          target_os = "android",
+                          target_os = "ios",
+                          target_os = "nacl"))]
+                pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
+
+                #[cfg(target_os = "macos")]
+                #[link_name = "fstat64"]
+                pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
+
+                pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int;
+                #[cfg(not(target_os = "nacl"))]
+                pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int;
+
+                #[cfg(any(target_os = "linux",
+                          target_os = "freebsd",
+                          target_os = "dragonfly",
+                          target_os = "bitrig",
+                          target_os = "openbsd",
+                          target_os = "android",
+                          target_os = "ios",
+                          target_os = "nacl"))]
+                pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
+
+                #[cfg(target_os = "macos")]
+                #[link_name = "stat64"]
+                pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
+            }
+        }
+
+        pub mod stdio {
+            use types::common::c95::FILE;
+            use types::os::arch::c95::{c_char, c_int};
+
+            extern {
+                pub fn popen(command: *const c_char,
+                             mode: *const c_char) -> *mut FILE;
+                pub fn pclose(stream: *mut FILE) -> c_int;
+                pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE;
+                pub fn fileno(stream: *mut FILE) -> c_int;
+            }
+        }
+
+        pub mod fcntl {
+            use types::os::arch::c95::{c_char, c_int};
+            use types::os::arch::posix88::mode_t;
+
+            mod open_shim {
+                extern {
+                    #[cfg(any(target_os = "macos",
+                              target_os = "ios"))]
+                    pub fn open(path: *const ::c_char, oflag: ::c_int, ...)
+                                -> ::c_int;
+
+                    #[cfg(not(any(target_os = "macos",
+                                  target_os = "ios")))]
+                    pub fn open(path: *const ::c_char, oflag: ::c_int, mode: ::mode_t)
+                                -> ::c_int;
+                }
+            }
+
+            #[cfg(any(target_os = "macos",
+                      target_os = "ios"))]
+            #[inline]
+            pub unsafe extern fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
+                use types::os::arch::c95::c_uint;
+                open_shim::open(path, oflag, mode as c_uint)
+            }
+
+            #[cfg(not(any(target_os = "macos",
+                          target_os = "ios")))]
+            #[inline]
+            pub unsafe extern fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
+                open_shim::open(path, oflag, mode)
+            }
+
+            extern {
+                pub fn creat(path: *const c_char, mode: mode_t) -> c_int;
+                pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int;
+            }
+        }
+
+        pub mod dirent {
+            use types::common::posix88::{DIR, dirent_t};
+            use types::os::arch::c95::{c_char, c_int, c_long};
+
+            // NB: On OS X opendir and readdir have two versions,
+            // one for 32-bit kernelspace and one for 64.
+            // We should be linking to the 64-bit ones, called
+            // opendir$INODE64, etc. but for some reason rustc
+            // doesn't link it correctly on i686, so we're going
+            // through a C function that mysteriously does work.
+
+            extern {
+                #[link_name="rust_opendir"]
+                pub fn opendir(dirname: *const c_char) -> *mut DIR;
+                #[link_name="rust_readdir_r"]
+                pub fn readdir_r(dirp: *mut DIR, entry: *mut dirent_t,
+                                  result: *mut *mut dirent_t) -> c_int;
+            }
+
+            extern {
+                pub fn closedir(dirp: *mut DIR) -> c_int;
+                pub fn rewinddir(dirp: *mut DIR);
+                pub fn seekdir(dirp: *mut DIR, loc: c_long);
+                pub fn telldir(dirp: *mut DIR) -> c_long;
+            }
+        }
+
+        pub mod unistd {
+            use types::common::c95::c_void;
+            use types::os::arch::c95::{c_char, c_int, c_long, c_uint};
+            use types::os::arch::c95::{size_t};
+            use types::os::common::posix01::timespec;
+            use types::os::arch::posix01::utimbuf;
+            use types::os::arch::posix88::{gid_t, off_t, pid_t};
+            use types::os::arch::posix88::{ssize_t, uid_t};
+
+            pub const _PC_NAME_MAX: c_int = 4;
+
+            #[cfg(not(target_os = "nacl"))]
+            extern {
+                pub fn access(path: *const c_char, amode: c_int) -> c_int;
+                pub fn alarm(seconds: c_uint) -> c_uint;
+                pub fn chdir(dir: *const c_char) -> c_int;
+                pub fn chown(path: *const c_char, uid: uid_t,
+                             gid: gid_t) -> c_int;
+                pub fn close(fd: c_int) -> c_int;
+                pub fn dup(fd: c_int) -> c_int;
+                pub fn dup2(src: c_int, dst: c_int) -> c_int;
+                pub fn execv(prog: *const c_char,
+                             argv: *mut *const c_char) -> c_int;
+                pub fn execve(prog: *const c_char, argv: *mut *const c_char,
+                              envp: *mut *const c_char)
+                              -> c_int;
+                pub fn execvp(c: *const c_char,
+                              argv: *mut *const c_char) -> c_int;
+                pub fn fork() -> pid_t;
+                pub fn fpathconf(filedes: c_int, name: c_int) -> c_long;
+                pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
+                pub fn getegid() -> gid_t;
+                pub fn geteuid() -> uid_t;
+                pub fn getgid() -> gid_t;
+                pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t)
+                                 -> c_int;
+                pub fn getlogin() -> *mut c_char;
+                pub fn getopt(argc: c_int, argv: *mut *const c_char,
+                              optstr: *const c_char) -> c_int;
+                pub fn getpgrp() -> pid_t;
+                pub fn getpid() -> pid_t;
+                pub fn getppid() -> pid_t;
+                pub fn getuid() -> uid_t;
+                pub fn getsid(pid: pid_t) -> pid_t;
+                pub fn isatty(fd: c_int) -> c_int;
+                pub fn link(src: *const c_char, dst: *const c_char) -> c_int;
+                pub fn lseek(fd: c_int, offset: off_t, whence: c_int)
+                             -> off_t;
+                pub fn pathconf(path: *mut c_char, name: c_int) -> c_long;
+                pub fn pause() -> c_int;
+                pub fn pipe(fds: *mut c_int) -> c_int;
+                pub fn read(fd: c_int, buf: *mut c_void, count: size_t)
+                            -> ssize_t;
+                pub fn rmdir(path: *const c_char) -> c_int;
+                pub fn setgid(gid: gid_t) -> c_int;
+                pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int;
+                pub fn setsid() -> pid_t;
+                pub fn setuid(uid: uid_t) -> c_int;
+                pub fn sleep(secs: c_uint) -> c_uint;
+                pub fn usleep(secs: c_uint) -> c_int;
+                pub fn nanosleep(rqtp: *const timespec,
+                                 rmtp: *mut timespec) -> c_int;
+                pub fn sysconf(name: c_int) -> c_long;
+                pub fn tcgetpgrp(fd: c_int) -> pid_t;
+                pub fn ttyname(fd: c_int) -> *mut c_char;
+                pub fn unlink(c: *const c_char) -> c_int;
+                pub fn wait(status: *const c_int) -> pid_t;
+                pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int)
+                               -> pid_t;
+                pub fn write(fd: c_int, buf: *const c_void, count: size_t)
+                             -> ssize_t;
+                pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
+                             offset: off_t) -> ssize_t;
+                pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t,
+                              offset: off_t) -> ssize_t;
+                pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int;
+            }
+            #[cfg(target_os = "nacl")]
+            extern {
+                pub fn access(path: *const c_char, amode: c_int) -> c_int;
+                pub fn chdir(dir: *const c_char) -> c_int;
+                pub fn chown(path: *const c_char, uid: uid_t,
+                             gid: gid_t) -> c_int;
+                pub fn close(fd: c_int) -> c_int;
+                pub fn dup(fd: c_int) -> c_int;
+                pub fn dup2(src: c_int, dst: c_int) -> c_int;
+                pub fn execv(prog: *const c_char,
+                             argv: *mut *const c_char) -> c_int;
+                pub fn execve(prog: *const c_char, argv: *mut *const c_char,
+                              envp: *mut *const c_char)
+                              -> c_int;
+                pub fn execvp(c: *const c_char,
+                              argv: *mut *const c_char) -> c_int;
+                pub fn fork() -> pid_t;
+                pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
+                pub fn getegid() -> gid_t;
+                pub fn geteuid() -> uid_t;
+                pub fn getgid() -> gid_t;
+                pub fn getlogin() -> *mut c_char;
+                pub fn getopt(argc: c_int, argv: *mut *const c_char,
+                              optstr: *const c_char) -> c_int;
+                pub fn getuid() -> uid_t;
+                pub fn getsid(pid: pid_t) -> pid_t;
+                pub fn isatty(fd: c_int) -> c_int;
+                pub fn link(src: *const c_char, dst: *const c_char) -> c_int;
+                pub fn lseek(fd: c_int, offset: off_t, whence: c_int)
+                             -> off_t;
+                pub fn pipe(fds: *mut c_int) -> c_int;
+                pub fn read(fd: c_int, buf: *mut c_void, count: size_t)
+                            -> ssize_t;
+                pub fn rmdir(path: *const c_char) -> c_int;
+                pub fn setgid(gid: gid_t) -> c_int;
+                pub fn setuid(uid: uid_t) -> c_int;
+                pub fn sleep(secs: c_uint) -> c_uint;
+                pub fn usleep(secs: c_uint) -> c_int;
+                pub fn nanosleep(rqtp: *const timespec,
+                                 rmtp: *mut timespec) -> c_int;
+                pub fn sysconf(name: c_int) -> c_long;
+                pub fn ttyname(fd: c_int) -> *mut c_char;
+                pub fn unlink(c: *const c_char) -> c_int;
+                pub fn wait(status: *const c_int) -> pid_t;
+                pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int)
+                               -> pid_t;
+                pub fn write(fd: c_int, buf: *const c_void, count: size_t)
+                             -> ssize_t;
+                pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
+                             offset: off_t) -> ssize_t;
+                pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t,
+                              offset: off_t) -> ssize_t;
+                pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int;
+            }
+        }
+
+        pub mod signal {
+            use types::os::arch::c95::{c_int};
+            use types::os::arch::posix88::{pid_t};
+
+            extern {
+                pub fn kill(pid: pid_t, sig: c_int) -> c_int;
+            }
+        }
+
+        pub mod mman {
+            use types::common::c95::{c_void};
+            use types::os::arch::c95::{size_t, c_int, c_char};
+            use types::os::arch::posix88::{mode_t, off_t};
+
+            #[cfg(not(target_os = "nacl"))]
+            extern {
+                pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
+                pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
+                pub fn mlockall(flags: c_int) -> c_int;
+                pub fn munlockall() -> c_int;
+
+                pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int)
+                                -> c_int;
+
+                pub fn msync(addr: *mut c_void, len: size_t, flags: c_int)
+                             -> c_int;
+                pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t)
+                                -> c_int;
+                pub fn shm_unlink(name: *const c_char) -> c_int;
+            }
+
+            extern {
+                pub fn mmap(addr: *mut c_void,
+                            len: size_t,
+                            prot: c_int,
+                            flags: c_int,
+                            fd: c_int,
+                            offset: off_t)
+                            -> *mut c_void;
+                pub fn munmap(addr: *mut c_void, len: size_t) -> c_int;
+
+            }
+        }
+
+        pub mod net {
+            use types::os::arch::c95::{c_char, c_uint};
+
+            extern {
+                pub fn if_nametoindex(ifname: *const c_char) -> c_uint;
+            }
+        }
+
+    }
+
+    #[cfg(any(target_os = "linux",
+              target_os = "android",
+              target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd",
+              target_os = "dragonfly",
+              target_os = "bitrig",
+              target_os = "openbsd",
+              target_os = "nacl"))]
+    pub mod posix01 {
+        pub mod stat_ {
+            use types::os::arch::c95::{c_char, c_int};
+            use types::os::arch::posix01::stat;
+
+            extern {
+                #[cfg(any(target_os = "linux",
+                          target_os = "freebsd",
+                          target_os = "dragonfly",
+                          target_os = "bitrig",
+                          target_os = "openbsd",
+                          target_os = "android",
+                          target_os = "ios",
+                          target_os = "nacl"))]
+                pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int;
+
+                #[cfg(target_os = "macos")]
+                #[link_name = "lstat64"]
+                pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int;
+            }
+        }
+
+        pub mod unistd {
+            use types::os::arch::c95::{c_char, c_int, size_t};
+            use types::os::arch::posix88::{ssize_t, off_t};
+
+            extern {
+                pub fn readlink(path: *const c_char,
+                                buf: *mut c_char,
+                                bufsz: size_t)
+                                -> ssize_t;
+
+                pub fn fsync(fd: c_int) -> c_int;
+
+                #[cfg(any(target_os = "linux", target_os = "android"))]
+                pub fn fdatasync(fd: c_int) -> c_int;
+
+                pub fn setenv(name: *const c_char, val: *const c_char,
+                              overwrite: c_int) -> c_int;
+                pub fn unsetenv(name: *const c_char) -> c_int;
+                pub fn putenv(string: *mut c_char) -> c_int;
+
+                pub fn symlink(path1: *const c_char,
+                               path2: *const c_char) -> c_int;
+
+                pub fn ftruncate(fd: c_int, length: off_t) -> c_int;
+            }
+        }
+
+        pub mod signal {
+            use types::os::arch::c95::c_int;
+            use types::os::common::posix01::sighandler_t;
+
+            #[cfg(not(all(target_os = "android", target_arch = "arm")))]
+            extern {
+                pub fn signal(signum: c_int,
+                              handler: sighandler_t) -> sighandler_t;
+            }
+
+            #[cfg(all(target_os = "android", target_arch = "arm"))]
+            extern {
+                #[link_name = "bsd_signal"]
+                pub fn signal(signum: c_int,
+                              handler: sighandler_t) -> sighandler_t;
+            }
+        }
+
+        pub mod glob {
+            use types::os::arch::c95::{c_char, c_int};
+            use types::os::common::posix01::{glob_t};
+
+            extern {
+                pub fn glob(pattern: *const c_char,
+                            flags: c_int,
+                            errfunc: ::core::option::Option<extern "C" fn(epath: *const c_char,
+                                                              errno: c_int) -> c_int>,
+                            pglob: *mut glob_t);
+                pub fn globfree(pglob: *mut glob_t);
+            }
+        }
+
+        pub mod mman {
+            use types::common::c95::{c_void};
+            use types::os::arch::c95::{c_int, size_t};
+
+            #[cfg(not(target_os = "nacl"))]
+            extern {
+                pub fn posix_madvise(addr: *mut c_void,
+                                     len: size_t,
+                                     advice: c_int)
+                                     -> c_int;
+            }
+        }
+
+        pub mod resource {
+            use types::os::arch::c95::c_int;
+            use types::os::common::posix01::rlimit;
+            use types::os::common::bsd43::rusage;
+            extern {
+                pub fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int;
+                pub fn setrlimit(resource: c_int, rlim: *const rlimit) -> c_int;
+                pub fn getrusage(resource: c_int, usage: *mut rusage) -> c_int;
+
+            }
+        }
+    }
+
+    #[cfg(target_os = "windows")]
+    pub mod posix01 {
+        pub mod stat_ {
+        }
+
+        pub mod unistd {
+        }
+
+        pub mod glob {
+        }
+
+        pub mod mman {
+        }
+
+        pub mod net {
+        }
+    }
+
+
+    #[cfg(any(target_os = "windows",
+              target_os = "linux",
+              target_os = "android",
+              target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd",
+              target_os = "dragonfly",
+              target_os = "bitrig",
+              target_os = "openbsd",
+              target_os = "nacl"))]
+    pub mod posix08 {
+        pub mod unistd {
+        }
+    }
+
+    #[cfg(not(windows))]
+    pub mod bsd43 {
+        use types::common::c95::{c_void};
+        use types::os::common::bsd44::{socklen_t, sockaddr, ifaddrs};
+        use types::os::arch::c95::{c_int, size_t};
+        use types::os::arch::posix88::ssize_t;
+
+        extern "system" {
+            pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int;
+            pub fn connect(socket: c_int, address: *const sockaddr,
+                           len: socklen_t) -> c_int;
+            pub fn bind(socket: c_int, address: *const sockaddr,
+                        address_len: socklen_t) -> c_int;
+            pub fn listen(socket: c_int, backlog: c_int) -> c_int;
+            pub fn accept(socket: c_int, address: *mut sockaddr,
+                          address_len: *mut socklen_t) -> c_int;
+            pub fn getpeername(socket: c_int, address: *mut sockaddr,
+                               address_len: *mut socklen_t) -> c_int;
+            pub fn getsockname(socket: c_int, address: *mut sockaddr,
+                               address_len: *mut socklen_t) -> c_int;
+            pub fn setsockopt(socket: c_int, level: c_int, name: c_int,
+                              value: *const c_void,
+                              option_len: socklen_t) -> c_int;
+            pub fn recv(socket: c_int, buf: *mut c_void, len: size_t,
+                        flags: c_int) -> ssize_t;
+            pub fn send(socket: c_int, buf: *const c_void, len: size_t,
+                        flags: c_int) -> ssize_t;
+            pub fn recvfrom(socket: c_int, buf: *mut c_void, len: size_t,
+                            flags: c_int, addr: *mut sockaddr,
+                            addrlen: *mut socklen_t) -> ssize_t;
+            pub fn sendto(socket: c_int, buf: *const c_void, len: size_t,
+                          flags: c_int, addr: *const sockaddr,
+                          addrlen: socklen_t) -> ssize_t;
+            pub fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int;
+            pub fn freeifaddrs(ifa: *mut ifaddrs);
+            pub fn shutdown(socket: c_int, how: c_int) -> c_int;
+        }
+    }
+
+    #[cfg(windows)]
+    pub mod bsd43 {
+        use types::common::c95::{c_void};
+        use types::os::common::bsd44::{socklen_t, sockaddr, SOCKET};
+        use types::os::arch::c95::c_int;
+        use types::os::arch::posix88::ssize_t;
+
+        extern "system" {
+            pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> SOCKET;
+            pub fn connect(socket: SOCKET, address: *const sockaddr,
+                           len: socklen_t) -> c_int;
+            pub fn bind(socket: SOCKET, address: *const sockaddr,
+                        address_len: socklen_t) -> c_int;
+            pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
+            pub fn accept(socket: SOCKET, address: *mut sockaddr,
+                          address_len: *mut socklen_t) -> SOCKET;
+            pub fn getpeername(socket: SOCKET, address: *mut sockaddr,
+                               address_len: *mut socklen_t) -> c_int;
+            pub fn getsockname(socket: SOCKET, address: *mut sockaddr,
+                               address_len: *mut socklen_t) -> c_int;
+            pub fn setsockopt(socket: SOCKET, level: c_int, name: c_int,
+                              value: *const c_void,
+                              option_len: socklen_t) -> c_int;
+            pub fn closesocket(socket: SOCKET) -> c_int;
+            pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int,
+                        flags: c_int) -> c_int;
+            pub fn send(socket: SOCKET, buf: *const c_void, len: c_int,
+                        flags: c_int) -> c_int;
+            pub fn recvfrom(socket: SOCKET, buf: *mut c_void, len: c_int,
+                            flags: c_int, addr: *mut sockaddr,
+                            addrlen: *mut c_int) -> ssize_t;
+            pub fn sendto(socket: SOCKET, buf: *const c_void, len: c_int,
+                          flags: c_int, addr: *const sockaddr,
+                          addrlen: c_int) -> c_int;
+            pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
+        }
+    }
+
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd",
+              target_os = "dragonfly",
+              target_os = "bitrig",
+              target_os = "openbsd"))]
+    pub mod bsd44 {
+        use types::common::c95::{c_void};
+        use types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, c_ulong, size_t};
+
+        extern {
+            pub fn ioctl(d: c_int, request: c_ulong, ...) -> c_int;
+            pub fn sysctl(name: *mut c_int,
+                          namelen: c_uint,
+                          oldp: *mut c_void,
+                          oldlenp: *mut size_t,
+                          newp: *mut c_void,
+                          newlen: size_t)
+                          -> c_int;
+            pub fn sysctlbyname(name: *const c_char,
+                                oldp: *mut c_void,
+                                oldlenp: *mut size_t,
+                                newp: *mut c_void,
+                                newlen: size_t)
+                                -> c_int;
+            pub fn sysctlnametomib(name: *const c_char,
+                                   mibp: *mut c_int,
+                                   sizep: *mut size_t)
+                                   -> c_int;
+            pub fn getdtablesize() -> c_int;
+            pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int)
+                           -> c_int;
+            pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar)
+                           -> c_int;
+            pub fn realpath(pathname: *const c_char, resolved: *mut c_char)
+                            -> *mut c_char;
+        }
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    pub mod bsd44 {
+        use types::common::c95::{c_void};
+        use types::os::arch::c95::{c_uchar, c_int, size_t};
+
+        extern {
+            #[cfg(not(all(target_os = "android", target_arch = "aarch64")))]
+            pub fn getdtablesize() -> c_int;
+            pub fn ioctl(d: c_int, request: c_int, ...) -> c_int;
+            pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int)
+                           -> c_int;
+            pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar)
+                           -> c_int;
+        }
+    }
+
+    #[cfg(target_os = "nacl")]
+    pub mod bsd44 {
+        use types::os::arch::c95::c_int;
+        extern {
+            pub fn getdtablesize() -> c_int;
+        }
+    }
+
+    #[cfg(target_os = "windows")]
+    pub mod bsd44 {
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub mod extra {
+        use types::os::arch::c95::{c_char, c_int};
+
+        extern {
+            pub fn _NSGetExecutablePath(buf: *mut c_char, bufsize: *mut u32)
+                                        -> c_int;
+        }
+    }
+
+    #[cfg(any(target_os = "freebsd",
+              target_os = "dragonfly",
+              target_os = "bitrig",
+              target_os = "openbsd"))]
+    pub mod extra {
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))]
+    pub mod extra {
+    }
+
+
+    #[cfg(target_os = "windows")]
+    pub mod extra {
+
+        pub mod kernel32 {
+            use types::os::arch::c95::{c_uint};
+            use types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE,
+                                               LPCWSTR, LPWSTR,
+                                               LPWCH, LPDWORD, LPVOID,
+                                               LPCVOID, LPOVERLAPPED,
+                                               LPSECURITY_ATTRIBUTES,
+                                               LPSTARTUPINFO,
+                                               LPPROCESS_INFORMATION,
+                                               LPMEMORY_BASIC_INFORMATION,
+                                               LPSYSTEM_INFO, HANDLE, LPHANDLE,
+                                               LARGE_INTEGER, PLARGE_INTEGER,
+                                               LPFILETIME, LPWIN32_FIND_DATAW};
+
+            extern "system" {
+                pub fn GetEnvironmentVariableW(n: LPCWSTR,
+                                               v: LPWSTR,
+                                               nsize: DWORD)
+                                               -> DWORD;
+                pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
+                                               -> BOOL;
+                pub fn GetEnvironmentStringsW() -> LPWCH;
+                pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL;
+                pub fn GetModuleFileNameW(hModule: HMODULE,
+                                          lpFilename: LPWSTR,
+                                          nSize: DWORD)
+                                          -> DWORD;
+                pub fn CreateDirectoryW(lpPathName: LPCWSTR,
+                                        lpSecurityAttributes:
+                                        LPSECURITY_ATTRIBUTES)
+                                        -> BOOL;
+                pub fn CopyFileW(lpExistingFileName: LPCWSTR,
+                                 lpNewFileName: LPCWSTR,
+                                 bFailIfExists: BOOL)
+                                 -> BOOL;
+                pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
+                pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+                pub fn GetCurrentDirectoryW(nBufferLength: DWORD,
+                                            lpBuffer: LPWSTR)
+                                            -> DWORD;
+                pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+                pub fn GetLastError() -> DWORD;
+                pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW)
+                                      -> HANDLE;
+                pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW)
+                                     -> BOOL;
+                pub fn FindClose(findFile: HANDLE) -> BOOL;
+                pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+                                       hSourceHandle: HANDLE,
+                                       hTargetProcessHandle: HANDLE,
+                                       lpTargetHandle: LPHANDLE,
+                                       dwDesiredAccess: DWORD,
+                                       bInheritHandle: BOOL,
+                                       dwOptions: DWORD)
+                                       -> BOOL;
+                pub fn CloseHandle(hObject: HANDLE) -> BOOL;
+                pub fn OpenProcess(dwDesiredAccess: DWORD,
+                                   bInheritHandle: BOOL,
+                                   dwProcessId: DWORD)
+                                   -> HANDLE;
+                pub fn GetCurrentProcess() -> HANDLE;
+                pub fn CreateProcessW(lpApplicationName: LPCWSTR,
+                                      lpCommandLine: LPWSTR,
+                                      lpProcessAttributes:
+                                      LPSECURITY_ATTRIBUTES,
+                                      lpThreadAttributes:
+                                      LPSECURITY_ATTRIBUTES,
+                                      bInheritHandles: BOOL,
+                                      dwCreationFlags: DWORD,
+                                      lpEnvironment: LPVOID,
+                                      lpCurrentDirectory: LPCWSTR,
+                                      lpStartupInfo: LPSTARTUPINFO,
+                                      lpProcessInformation:
+                                      LPPROCESS_INFORMATION)
+                                      -> BOOL;
+                pub fn WaitForSingleObject(hHandle: HANDLE,
+                                           dwMilliseconds: DWORD)
+                                           -> DWORD;
+                pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint)
+                                        -> BOOL;
+                pub fn GetExitCodeProcess(hProcess: HANDLE,
+                                          lpExitCode: LPDWORD)
+                                          -> BOOL;
+                pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
+                pub fn VirtualAlloc(lpAddress: LPVOID,
+                                    dwSize: SIZE_T,
+                                    flAllocationType: DWORD,
+                                    flProtect: DWORD)
+                                    -> LPVOID;
+                pub fn VirtualFree(lpAddress: LPVOID,
+                                   dwSize: SIZE_T,
+                                   dwFreeType: DWORD)
+                                   -> BOOL;
+                pub fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
+                pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T)
+                                     -> BOOL;
+                pub fn VirtualProtect(lpAddress: LPVOID,
+                                      dwSize: SIZE_T,
+                                      flNewProtect: DWORD,
+                                      lpflOldProtect: LPDWORD)
+                                      -> BOOL;
+                pub fn VirtualQuery(lpAddress: LPCVOID,
+                                    lpBuffer: LPMEMORY_BASIC_INFORMATION,
+                                    dwLength: SIZE_T)
+                                    -> SIZE_T;
+                pub fn CreateFileMappingW(hFile: HANDLE,
+                                          lpAttributes: LPSECURITY_ATTRIBUTES,
+                                          flProtect: DWORD,
+                                          dwMaximumSizeHigh: DWORD,
+                                          dwMaximumSizeLow: DWORD,
+                                          lpName: LPCWSTR)
+                                          -> HANDLE;
+                pub fn MapViewOfFile(hFileMappingObject: HANDLE,
+                                     dwDesiredAccess: DWORD,
+                                     dwFileOffsetHigh: DWORD,
+                                     dwFileOffsetLow: DWORD,
+                                     dwNumberOfBytesToMap: SIZE_T)
+                                     -> LPVOID;
+                pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
+                pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
+                                   lpNewFileName: LPCWSTR,
+                                   dwFlags: DWORD) -> BOOL;
+                pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
+                                       lpTargetFileName: LPCWSTR,
+                                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+                                        -> BOOL;
+                pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL;
+                pub fn CreateFileW(lpFileName: LPCWSTR,
+                                   dwDesiredAccess: DWORD,
+                                   dwShareMode: DWORD,
+                                   lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+                                   dwCreationDisposition: DWORD,
+                                   dwFlagsAndAttributes: DWORD,
+                                   hTemplateFile: HANDLE) -> HANDLE;
+                pub fn ReadFile(hFile: HANDLE,
+                                lpBuffer: LPVOID,
+                                nNumberOfBytesToRead: DWORD,
+                                lpNumberOfBytesRead: LPDWORD,
+                                lpOverlapped: LPOVERLAPPED) -> BOOL;
+                pub fn WriteFile(hFile: HANDLE,
+                                 lpBuffer: LPVOID,
+                                 nNumberOfBytesToRead: DWORD,
+                                 lpNumberOfBytesRead: LPDWORD,
+                                 lpOverlapped: LPOVERLAPPED) -> BOOL;
+                pub fn SetFilePointerEx(hFile: HANDLE,
+                                        liDistanceToMove: LARGE_INTEGER,
+                                        lpNewFilePointer: PLARGE_INTEGER,
+                                        dwMoveMethod: DWORD) -> BOOL;
+                pub fn SetEndOfFile(hFile: HANDLE) -> BOOL;
+
+                pub fn GetSystemTimeAsFileTime(
+                            lpSystemTimeAsFileTime: LPFILETIME);
+
+                pub fn QueryPerformanceFrequency(
+                            lpFrequency: *mut LARGE_INTEGER) -> BOOL;
+                pub fn QueryPerformanceCounter(
+                            lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL;
+
+                pub fn GetCurrentProcessId() -> DWORD;
+                pub fn CreateNamedPipeW(
+                            lpName: LPCWSTR,
+                            dwOpenMode: DWORD,
+                            dwPipeMode: DWORD,
+                            nMaxInstances: DWORD,
+                            nOutBufferSize: DWORD,
+                            nInBufferSize: DWORD,
+                            nDefaultTimeOut: DWORD,
+                            lpSecurityAttributes: LPSECURITY_ATTRIBUTES
+                            ) -> HANDLE;
+                pub fn ConnectNamedPipe(hNamedPipe: HANDLE,
+                                        lpOverlapped: LPOVERLAPPED) -> BOOL;
+                pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR,
+                                      nTimeOut: DWORD) -> BOOL;
+                pub fn SetNamedPipeHandleState(hNamedPipe: HANDLE,
+                                               lpMode: LPDWORD,
+                                               lpMaxCollectionCount: LPDWORD,
+                                               lpCollectDataTimeout: LPDWORD)
+                                                            -> BOOL;
+                pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
+                                    bManualReset: BOOL,
+                                    bInitialState: BOOL,
+                                    lpName: LPCWSTR) -> HANDLE;
+                pub fn GetOverlappedResult(hFile: HANDLE,
+                                           lpOverlapped: LPOVERLAPPED,
+                                           lpNumberOfBytesTransferred: LPDWORD,
+                                           bWait: BOOL) -> BOOL;
+                pub fn DisconnectNamedPipe(hNamedPipe: HANDLE) -> BOOL;
+            }
+        }
+
+        pub mod msvcrt {
+            use types::os::arch::c95::{c_int, c_long};
+            use types::os::arch::c99::intptr_t;
+
+            extern {
+                #[link_name = "_commit"]
+                pub fn commit(fd: c_int) -> c_int;
+
+                #[link_name = "_get_osfhandle"]
+                pub fn get_osfhandle(fd: c_int) -> c_long;
+
+                #[link_name = "_open_osfhandle"]
+                pub fn open_osfhandle(osfhandle: intptr_t,
+                                      flags: c_int) -> c_int;
+            }
+        }
+
+        pub mod winsock {
+            use types::os::arch::c95::{c_int, c_long, c_ulong};
+            use types::os::common::bsd44::SOCKET;
+
+            extern "system" {
+                pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
+            }
+        }
+    }
+}
+
+#[doc(hidden)]
+pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly
+
+#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/log/lib.rs.html b/src/log/lib.rs.html new file mode 100644 index 0000000..78cbf86 --- /dev/null +++ b/src/log/lib.rs.html @@ -0,0 +1,1643 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A lightweight logging facade.
+//!
+//! A logging facade provides a single logging API that abstracts over the
+//! actual logging implementation. Libraries can use the logging API provided
+//! by this crate, and the consumer of those libraries can choose the logging
+//! framework that is most suitable for its use case.
+//!
+//! If no logging implementation is selected, the facade falls back to a "noop"
+//! implementation that ignores all log messages. The overhead in this case
+//! is very small - just an integer load, comparison and jump.
+//!
+//! A log request consists of a target, a level, and a body. A target is a
+//! string which defaults to the module path of the location of the log
+//! request, though that default may be overridden. Logger implementations
+//! typically use the target to filter requests based on some user
+//! configuration.
+//!
+//! # Use
+//!
+//! ## In libraries
+//!
+//! Libraries should link only to the `log` crate, and use the provided
+//! macros to log whatever information will be useful to downstream consumers.
+//!
+//! ### Examples
+//!
+//! ```rust
+//! # #![allow(unstable)]
+//! #[macro_use]
+//! extern crate log;
+//!
+//! # #[derive(Debug)] pub struct Yak(String);
+//! # impl Yak { fn shave(&self, _: u32) {} }
+//! # fn find_a_razor() -> Result<u32, u32> { Ok(1) }
+//! pub fn shave_the_yak(yak: &Yak) {
+//!     info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);
+//!
+//!     loop {
+//!         match find_a_razor() {
+//!             Ok(razor) => {
+//!                 info!("Razor located: {}", razor);
+//!                 yak.shave(razor);
+//!                 break;
+//!             }
+//!             Err(err) => {
+//!                 warn!("Unable to locate a razor: {}, retrying", err);
+//!             }
+//!         }
+//!     }
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! ## In executables
+//!
+//! Executables should chose a logging framework and initialize it early in the
+//! runtime of the program. Logging frameworks will typically include a
+//! function to do this. Any log messages generated before the framework is
+//! initialized will be ignored.
+//!
+//! The executable itself may use the `log` crate to log as well.
+//!
+//! ### Warning
+//!
+//! The logging system may only be initialized once.
+//!
+//! ### Examples
+//!
+//! ```rust,ignore
+//! #[macro_use]
+//! extern crate log;
+//! extern crate my_logger;
+//!
+//! fn main() {
+//!     my_logger::init();
+//!
+//!     info!("starting up");
+//!
+//!     // ...
+//! }
+//! ```
+//!
+//! # Logger implementations
+//!
+//! Loggers implement the `Log` trait. Here's a very basic example that simply
+//! logs all messages at the `Error`, `Warn` or `Info` levels to stdout:
+//!
+//! ```rust
+//! extern crate log;
+//!
+//! use log::{LogRecord, LogLevel, LogMetadata};
+//!
+//! struct SimpleLogger;
+//!
+//! impl log::Log for SimpleLogger {
+//!     fn enabled(&self, metadata: &LogMetadata) -> bool {
+//!         metadata.level() <= LogLevel::Info
+//!     }
+//!
+//!     fn log(&self, record: &LogRecord) {
+//!         if self.enabled(record.metadata()) {
+//!             println!("{} - {}", record.level(), record.args());
+//!         }
+//!     }
+//! }
+//!
+//! # fn main() {}
+//! ```
+//!
+//! Loggers are installed by calling the `set_logger` function. It takes a
+//! closure which is provided a `MaxLogLevel` token and returns a `Log` trait
+//! object. The `MaxLogLevel` token controls the global maximum log level. The
+//! logging facade uses this as an optimization to improve performance of log
+//! messages at levels that are disabled. In the case of our example logger,
+//! we'll want to set the maximum log level to `Info`, since we ignore any
+//! `Debug` or `Trace` level log messages. A logging framework should provide a
+//! function that wraps a call to `set_logger`, handling initialization of the
+//! logger:
+//!
+//! ```rust
+//! # extern crate log;
+//! # use log::{LogLevel, LogLevelFilter, SetLoggerError, LogMetadata};
+//! # struct SimpleLogger;
+//! # impl log::Log for SimpleLogger {
+//! #   fn enabled(&self, _: &LogMetadata) -> bool { false }
+//! #   fn log(&self, _: &log::LogRecord) {}
+//! # }
+//! # fn main() {}
+//! pub fn init() -> Result<(), SetLoggerError> {
+//!     log::set_logger(|max_log_level| {
+//!         max_log_level.set(LogLevelFilter::Info);
+//!         Box::new(SimpleLogger)
+//!     })
+//! }
+//! ```
+
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+       html_root_url = "http://doc.rust-lang.org/log/")]
+#![warn(missing_docs)]
+
+extern crate libc;
+
+use std::ascii::AsciiExt;
+use std::cmp;
+use std::error;
+use std::fmt;
+use std::mem;
+use std::ops::Deref;
+use std::str::FromStr;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+mod macros;
+
+// The setup here is a bit weird to make at_exit work.
+//
+// There are four different states that we care about: the logger's
+// uninitialized, the logger's initializing (set_logger's been called but
+// LOGGER hasn't actually been set yet), the logger's active, or the logger's
+// shutting down inside of at_exit.
+//
+// The LOGGER static is normally a Box<Box<Log>> with some special possible
+// values as well. The uninitialized and initializing states are represented by
+// the values 0 and 1 respectively. The shutting down state is also represented
+// by 1. Any other value is a valid pointer to the logger.
+//
+// The at_exit routine needs to make sure that no threads are actively logging
+// when it deallocates the logger. The number of actively logging threads is
+// tracked in the REFCOUNT static. The routine first sets LOGGER back to 1.
+// All logging calls past that point will immediately return without accessing
+// the logger. At that point, the at_exit routine just waits for the refcount
+// to reach 0 before deallocating the logger. Note that the refcount does not
+// necessarily monotonically decrease at this point, as new log calls still
+// increment and decrement it, but the interval in between is small enough that
+// the wait is really just for the active log calls to finish.
+static LOGGER: AtomicUsize = ATOMIC_USIZE_INIT;
+static REFCOUNT: AtomicUsize = ATOMIC_USIZE_INIT;
+
+const UNINITIALIZED: usize = 0;
+const INITIALIZING: usize = 1;
+
+static MAX_LOG_LEVEL_FILTER: AtomicUsize = ATOMIC_USIZE_INIT;
+
+static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
+                                             "DEBUG", "TRACE"];
+
+/// An enum representing the available verbosity levels of the logging framework
+///
+/// A `LogLevel` may be compared directly to a `LogLevelFilter`.
+#[repr(usize)]
+#[derive(Copy, Eq, Debug)]
+pub enum LogLevel {
+    /// The "error" level.
+    ///
+    /// Designates very serious errors.
+    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
+    /// The "warn" level.
+    ///
+    /// Designates hazardous situations.
+    Warn,
+    /// The "info" level.
+    ///
+    /// Designates useful information.
+    Info,
+    /// The "debug" level.
+    ///
+    /// Designates lower priority information.
+    Debug,
+    /// The "trace" level.
+    ///
+    /// Designates very low priority, often extremely verbose, information.
+    Trace,
+}
+
+impl Clone for LogLevel {
+    #[inline]
+    fn clone(&self) -> LogLevel {
+        *self
+    }
+}
+
+impl PartialEq for LogLevel {
+    #[inline]
+    fn eq(&self, other: &LogLevel) -> bool {
+        *self as usize == *other as usize
+    }
+}
+
+impl PartialEq<LogLevelFilter> for LogLevel {
+    #[inline]
+    fn eq(&self, other: &LogLevelFilter) -> bool {
+        *self as usize == *other as usize
+    }
+}
+
+impl PartialOrd for LogLevel {
+    #[inline]
+    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialOrd<LogLevelFilter> for LogLevel {
+    #[inline]
+    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
+        Some((*self as usize).cmp(&(*other as usize)))
+    }
+}
+
+impl Ord for LogLevel {
+    #[inline]
+    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
+        (*self as usize).cmp(&(*other as usize))
+    }
+}
+
+fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
+    match t {
+        Some(t) => Ok(t),
+        None => Err(e),
+    }
+}
+
+impl FromStr for LogLevel {
+    type Err = ();
+    fn from_str(level: &str) -> Result<LogLevel, ()> {
+        ok_or(LOG_LEVEL_NAMES.iter()
+                    .position(|&name| name.eq_ignore_ascii_case(level))
+                    .into_iter()
+                    .filter(|&idx| idx != 0)
+                    .map(|idx| LogLevel::from_usize(idx).unwrap())
+                    .next(), ())
+    }
+}
+
+impl fmt::Display for LogLevel {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.pad(LOG_LEVEL_NAMES[*self as usize])
+    }
+}
+
+impl LogLevel {
+    fn from_usize(u: usize) -> Option<LogLevel> {
+        match u {
+            1 => Some(LogLevel::Error),
+            2 => Some(LogLevel::Warn),
+            3 => Some(LogLevel::Info),
+            4 => Some(LogLevel::Debug),
+            5 => Some(LogLevel::Trace),
+            _ => None
+        }
+    }
+
+    /// Returns the most verbose logging level.
+    #[inline]
+    pub fn max() -> LogLevel {
+        LogLevel::Trace
+    }
+
+    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
+    #[inline]
+    pub fn to_log_level_filter(&self) -> LogLevelFilter {
+        LogLevelFilter::from_usize(*self as usize).unwrap()
+    }
+}
+
+/// An enum representing the available verbosity level filters of the logging
+/// framework.
+///
+/// A `LogLevelFilter` may be compared directly to a `LogLevel`.
+#[repr(usize)]
+#[derive(Copy, Eq, Debug)]
+pub enum LogLevelFilter {
+    /// A level lower than all log levels.
+    Off,
+    /// Corresponds to the `Error` log level.
+    Error,
+    /// Corresponds to the `Warn` log level.
+    Warn,
+    /// Corresponds to the `Trace` log level.
+    Info,
+    /// Corresponds to the `Debug` log level.
+    Debug,
+    /// Corresponds to the `Trace` log level.
+    Trace,
+}
+
+// Deriving generates terrible impls of these traits
+
+impl Clone for LogLevelFilter {
+    #[inline]
+    fn clone(&self) -> LogLevelFilter {
+        *self
+    }
+}
+
+impl PartialEq for LogLevelFilter {
+    #[inline]
+    fn eq(&self, other: &LogLevelFilter) -> bool {
+        *self as usize == *other as usize
+    }
+}
+
+impl PartialEq<LogLevel> for LogLevelFilter {
+    #[inline]
+    fn eq(&self, other: &LogLevel) -> bool {
+        other.eq(self)
+    }
+}
+
+impl PartialOrd for LogLevelFilter {
+    #[inline]
+    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialOrd<LogLevel> for LogLevelFilter {
+    #[inline]
+    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
+        other.partial_cmp(self).map(|x| x.reverse())
+    }
+}
+
+impl Ord for LogLevelFilter {
+    #[inline]
+    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
+        (*self as usize).cmp(&(*other as usize))
+    }
+}
+
+impl FromStr for LogLevelFilter {
+    type Err = ();
+    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
+        ok_or(LOG_LEVEL_NAMES.iter()
+                    .position(|&name| name.eq_ignore_ascii_case(level))
+                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
+    }
+}
+
+impl fmt::Display for LogLevelFilter {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "{}", LOG_LEVEL_NAMES[*self as usize])
+    }
+}
+
+impl LogLevelFilter {
+    fn from_usize(u: usize) -> Option<LogLevelFilter> {
+        match u {
+            0 => Some(LogLevelFilter::Off),
+            1 => Some(LogLevelFilter::Error),
+            2 => Some(LogLevelFilter::Warn),
+            3 => Some(LogLevelFilter::Info),
+            4 => Some(LogLevelFilter::Debug),
+            5 => Some(LogLevelFilter::Trace),
+            _ => None
+        }
+    }
+    /// Returns the most verbose logging level filter.
+    #[inline]
+    pub fn max() -> LogLevelFilter {
+        LogLevelFilter::Trace
+    }
+
+    /// Converts `self` to the equivalent `LogLevel`.
+    ///
+    /// Returns `None` if `self` is `LogLevelFilter::Off`.
+    #[inline]
+    pub fn to_log_level(&self) -> Option<LogLevel> {
+        LogLevel::from_usize(*self as usize)
+    }
+}
+
+/// The "payload" of a log message.
+pub struct LogRecord<'a> {
+    metadata: LogMetadata<'a>,
+    location: &'a LogLocation,
+    args: fmt::Arguments<'a>,
+}
+
+impl<'a> LogRecord<'a> {
+    /// The message body.
+    pub fn args(&self) -> &fmt::Arguments<'a> {
+        &self.args
+    }
+
+    /// Metadata about the log directive.
+    pub fn metadata(&self) -> &LogMetadata {
+        &self.metadata
+    }
+
+    /// The location of the log directive.
+    pub fn location(&self) -> &LogLocation {
+        self.location
+    }
+
+    /// The verbosity level of the message.
+    pub fn level(&self) -> LogLevel {
+        self.metadata.level()
+    }
+
+    /// The name of the target of the directive.
+    pub fn target(&self) -> &str {
+        self.metadata.target()
+    }
+}
+
+/// Metadata about a log message.
+pub struct LogMetadata<'a> {
+    level: LogLevel,
+    target: &'a str,
+}
+
+impl<'a> LogMetadata<'a> {
+    /// The verbosity level of the message.
+    pub fn level(&self) -> LogLevel {
+        self.level
+    }
+
+    /// The name of the target of the directive.
+    pub fn target(&self) -> &str {
+        self.target
+    }
+}
+
+/// A trait encapsulating the operations required of a logger
+pub trait Log: Sync+Send {
+    /// Determines if a log message with the specified metadata would be
+    /// logged.
+    ///
+    /// This is used by the `log_enabled!` macro to allow callers to avoid
+    /// expensive computation of log message arguments if the message would be
+    /// discarded anyway.
+    fn enabled(&self, metadata: &LogMetadata) -> bool;
+
+    /// Logs the `LogRecord`.
+    ///
+    /// Note that `enabled` is *not* necessarily called before this method.
+    /// Implementations of `log` should perform all necessary filtering
+    /// internally.
+    fn log(&self, record: &LogRecord);
+}
+
+/// The location of a log message.
+///
+/// # Warning
+///
+/// The fields of this struct are public so that they may be initialized by the
+/// `log!` macro. They are subject to change at any time and should never be
+/// accessed directly.
+#[derive(Copy, Clone, Debug)]
+pub struct LogLocation {
+    #[doc(hidden)]
+    pub __module_path: &'static str,
+    #[doc(hidden)]
+    pub __file: &'static str,
+    #[doc(hidden)]
+    pub __line: u32,
+}
+
+impl LogLocation {
+    /// The module path of the message.
+    pub fn module_path(&self) -> &str {
+        self.__module_path
+    }
+
+    /// The source file containing the message.
+    pub fn file(&self) -> &str {
+        self.__file
+    }
+
+    /// The line containing the message.
+    pub fn line(&self) -> u32 {
+        self.__line
+    }
+}
+
+/// A token providing read and write access to the global maximum log level
+/// filter.
+///
+/// The maximum log level is used as an optimization to avoid evaluating log
+/// messages that will be ignored by the logger. Any message with a level
+/// higher than the maximum log level filter will be ignored. A logger should
+/// make sure to keep the maximum log level filter in sync with its current
+/// configuration.
+#[allow(missing_copy_implementations)]
+pub struct MaxLogLevelFilter(());
+
+impl fmt::Debug for MaxLogLevelFilter {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "MaxLogLevelFilter")
+    }
+}
+
+impl MaxLogLevelFilter {
+    /// Gets the current maximum log level filter.
+    pub fn get(&self) -> LogLevelFilter {
+        max_log_level()
+    }
+
+    /// Sets the maximum log level.
+    pub fn set(&self, level: LogLevelFilter) {
+        MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::SeqCst)
+    }
+}
+
+/// Returns the current maximum log level.
+///
+/// The `log!`, `error!`, `warn!`, `info!`, `debug!`, and `trace!` macros check
+/// this value and discard any message logged at a higher level. The maximum
+/// log level is set by the `MaxLogLevel` token passed to loggers.
+#[inline(always)]
+pub fn max_log_level() -> LogLevelFilter {
+    unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) }
+}
+
+/// Sets the global logger.
+///
+/// The `make_logger` closure is passed a `MaxLogLevel` object, which the
+/// logger should use to keep the global maximum log level in sync with the
+/// highest log level that the logger will not ignore.
+///
+/// This function may only be called once in the lifetime of a program. Any log
+/// events that occur before the call to `set_logger` completes will be
+/// ignored.
+///
+/// This function does not typically need to be called manually. Logger
+/// implementations should provide an initialization method that calls
+/// `set_logger` internally.
+pub fn set_logger<M>(make_logger: M) -> Result<(), SetLoggerError>
+        where M: FnOnce(MaxLogLevelFilter) -> Box<Log> {
+    if LOGGER.compare_and_swap(UNINITIALIZED, INITIALIZING,
+                               Ordering::SeqCst) != UNINITIALIZED {
+        return Err(SetLoggerError(()));
+    }
+
+    let logger = Box::new(make_logger(MaxLogLevelFilter(())));
+    let logger = unsafe { mem::transmute::<Box<Box<Log>>, usize>(logger) };
+    LOGGER.store(logger, Ordering::SeqCst);
+
+    unsafe {
+        assert_eq!(libc::atexit(shutdown), 0);
+    }
+    return Ok(());
+
+    extern fn shutdown() {
+        // Set to INITIALIZING to prevent re-initialization after
+        let logger = LOGGER.swap(INITIALIZING, Ordering::SeqCst);
+
+        while REFCOUNT.load(Ordering::SeqCst) != 0 {
+            // FIXME add a sleep here when it doesn't involve timers
+        }
+
+        unsafe { mem::transmute::<usize, Box<Box<Log>>>(logger); }
+    }
+}
+
+/// The type returned by `set_logger` if `set_logger` has already been called.
+#[allow(missing_copy_implementations)]
+#[derive(Debug)]
+pub struct SetLoggerError(());
+
+impl fmt::Display for SetLoggerError {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "attempted to set a logger after the logging system \
+                     was already initialized")
+    }
+}
+
+impl error::Error for SetLoggerError {
+    fn description(&self) -> &str { "set_logger() called multiple times" }
+}
+
+struct LoggerGuard(usize);
+
+impl Drop for LoggerGuard {
+    fn drop(&mut self) {
+        REFCOUNT.fetch_sub(1, Ordering::SeqCst);
+    }
+}
+
+impl Deref for LoggerGuard {
+    type Target = Box<Log>;
+
+    fn deref(&self) -> &Box<Log+'static> {
+        unsafe { mem::transmute(self.0) }
+    }
+}
+
+fn logger() -> Option<LoggerGuard> {
+    REFCOUNT.fetch_add(1, Ordering::SeqCst);
+    let logger = LOGGER.load(Ordering::SeqCst);
+    if logger == UNINITIALIZED || logger == INITIALIZING {
+        REFCOUNT.fetch_sub(1, Ordering::SeqCst);
+        None
+    } else {
+        Some(LoggerGuard(logger))
+    }
+}
+
+// WARNING
+// This is not considered part of the crate's public API. It is subject to
+// change at any time.
+#[doc(hidden)]
+pub fn __enabled(level: LogLevel, target: &str) -> bool {
+    if let Some(logger) = logger() {
+        logger.enabled(&LogMetadata { level: level, target: target })
+    } else {
+        false
+    }
+}
+
+// WARNING
+// This is not considered part of the crate's public API. It is subject to
+// change at any time.
+#[doc(hidden)]
+pub fn __log(level: LogLevel, target: &str, loc: &LogLocation,
+             args: fmt::Arguments) {
+    if let Some(logger) = logger() {
+        let record = LogRecord {
+            metadata: LogMetadata {
+                level: level,
+                target: target,
+            },
+            location: loc,
+            args: args
+        };
+        logger.log(&record)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+     use std::error::Error;
+     use super::{LogLevel, LogLevelFilter, SetLoggerError};
+
+     #[test]
+     fn test_loglevelfilter_from_str() {
+         let tests = [
+             ("off",   Ok(LogLevelFilter::Off)),
+             ("error", Ok(LogLevelFilter::Error)),
+             ("warn",  Ok(LogLevelFilter::Warn)),
+             ("info",  Ok(LogLevelFilter::Info)),
+             ("debug", Ok(LogLevelFilter::Debug)),
+             ("trace", Ok(LogLevelFilter::Trace)),
+             ("OFF",   Ok(LogLevelFilter::Off)),
+             ("ERROR", Ok(LogLevelFilter::Error)),
+             ("WARN",  Ok(LogLevelFilter::Warn)),
+             ("INFO",  Ok(LogLevelFilter::Info)),
+             ("DEBUG", Ok(LogLevelFilter::Debug)),
+             ("TRACE", Ok(LogLevelFilter::Trace)),
+             ("asdf",  Err(())),
+         ];
+         for &(s, ref expected) in &tests {
+             assert_eq!(expected, &s.parse());
+         }
+     }
+
+     #[test]
+     fn test_loglevel_from_str() {
+         let tests = [
+             ("OFF",   Err(())),
+             ("error", Ok(LogLevel::Error)),
+             ("warn",  Ok(LogLevel::Warn)),
+             ("info",  Ok(LogLevel::Info)),
+             ("debug", Ok(LogLevel::Debug)),
+             ("trace", Ok(LogLevel::Trace)),
+             ("ERROR", Ok(LogLevel::Error)),
+             ("WARN",  Ok(LogLevel::Warn)),
+             ("INFO",  Ok(LogLevel::Info)),
+             ("DEBUG", Ok(LogLevel::Debug)),
+             ("TRACE", Ok(LogLevel::Trace)),
+             ("asdf",  Err(())),
+         ];
+         for &(s, ref expected) in &tests {
+             assert_eq!(expected, &s.parse());
+         }
+     }
+
+     #[test]
+     fn test_loglevel_show() {
+         assert_eq!("INFO", LogLevel::Info.to_string());
+         assert_eq!("ERROR", LogLevel::Error.to_string());
+     }
+
+     #[test]
+     fn test_loglevelfilter_show() {
+         assert_eq!("OFF", LogLevelFilter::Off.to_string());
+         assert_eq!("ERROR", LogLevelFilter::Error.to_string());
+     }
+
+     #[test]
+     fn test_cross_cmp() {
+         assert!(LogLevel::Debug > LogLevelFilter::Error);
+         assert!(LogLevelFilter::Warn < LogLevel::Trace);
+         assert!(LogLevelFilter::Off < LogLevel::Error);
+     }
+
+     #[test]
+     fn test_cross_eq() {
+         assert!(LogLevel::Error == LogLevelFilter::Error);
+         assert!(LogLevelFilter::Off != LogLevel::Error);
+         assert!(LogLevel::Trace == LogLevelFilter::Trace);
+     }
+
+     #[test]
+     fn test_to_log_level() {
+         assert_eq!(Some(LogLevel::Error), LogLevelFilter::Error.to_log_level());
+         assert_eq!(None, LogLevelFilter::Off.to_log_level());
+         assert_eq!(Some(LogLevel::Debug), LogLevelFilter::Debug.to_log_level());
+     }
+
+     #[test]
+     fn test_to_log_level_filter() {
+         assert_eq!(LogLevelFilter::Error, LogLevel::Error.to_log_level_filter());
+         assert_eq!(LogLevelFilter::Trace, LogLevel::Trace.to_log_level_filter());
+     }
+
+     #[test]
+     fn test_error_trait() {
+         let e = SetLoggerError(());
+         assert_eq!(e.description(), "set_logger() called multiple times");
+     }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/log/macros.rs.html b/src/log/macros.rs.html new file mode 100644 index 0000000..cd4dd2a --- /dev/null +++ b/src/log/macros.rs.html @@ -0,0 +1,387 @@ + + + + + + + + + + macros.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+/// The standard logging macro.
+///
+/// This macro will generically log with the specified `LogLevel` and `format!`
+/// based argument list.
+///
+/// The `log_level` cfg can be used to statically disable logging at various
+/// levels.
+#[macro_export]
+macro_rules! log {
+    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
+        static LOC: $crate::LogLocation = $crate::LogLocation {
+            __line: line!(),
+            __file: file!(),
+            __module_path: module_path!(),
+        };
+        let lvl = $lvl;
+        if !cfg!(log_level = "off") &&
+                (lvl <= $crate::LogLevel::Error || !cfg!(log_level = "error")) &&
+                (lvl <= $crate::LogLevel::Warn || !cfg!(log_level = "warn")) &&
+                (lvl <= $crate::LogLevel::Debug || !cfg!(log_level = "debug")) &&
+                (lvl <= $crate::LogLevel::Info || !cfg!(log_level = "info")) &&
+                lvl <= $crate::max_log_level() {
+            $crate::__log(lvl, $target, &LOC, format_args!($($arg)+))
+        }
+    });
+    ($lvl:expr, $($arg:tt)+) => (log!(target: module_path!(), $lvl, $($arg)+))
+}
+
+/// Logs a message at the error level.
+///
+/// Logging at this level is disabled if the `log_level = "off"` cfg is
+/// present.
+#[macro_export]
+macro_rules! error {
+    (target: $target:expr, $($arg:tt)*) => (
+        log!(target: $target, $crate::LogLevel::Error, $($arg)*);
+    );
+    ($($arg:tt)*) => (
+        log!($crate::LogLevel::Error, $($arg)*);
+    )
+}
+
+/// Logs a message at the warn level.
+///
+/// Logging at this level is disabled if any of the following cfgs are present:
+/// `log_level = "off"` or `log_level = "error"`.
+#[macro_export]
+macro_rules! warn {
+    (target: $target:expr, $($arg:tt)*) => (
+        log!(target: $target, $crate::LogLevel::Warn, $($arg)*);
+    );
+    ($($arg:tt)*) => (
+        log!($crate::LogLevel::Warn, $($arg)*);
+    )
+}
+
+/// Logs a message at the info level.
+///
+/// Logging at this level is disabled if any of the following cfgs are present:
+/// `log_level = "off"`, `log_level = "error"`, or
+/// `log_level = "warn"`.
+#[macro_export]
+macro_rules! info {
+    (target: $target:expr, $($arg:tt)*) => (
+        log!(target: $target, $crate::LogLevel::Info, $($arg)*);
+    );
+    ($($arg:tt)*) => (
+        log!($crate::LogLevel::Info, $($arg)*);
+    )
+}
+
+/// Logs a message at the debug level.
+///
+/// Logging at this level is disabled if any of the following cfgs are present:
+/// `log_level = "off"`, `log_level = "error"`, `log_level = "warn"`,
+/// or `log_level = "info"`.
+#[macro_export]
+macro_rules! debug {
+    (target: $target:expr, $($arg:tt)*) => (
+        log!(target: $target, $crate::LogLevel::Debug, $($arg)*);
+    );
+    ($($arg:tt)*) => (
+        log!($crate::LogLevel::Debug, $($arg)*);
+    )
+}
+
+/// Logs a message at the trace level.
+///
+/// Logging at this level is disabled if any of the following cfgs are present:
+/// `log_level = "off"`, `log_level = "error"`, `log_level = "warn"`,
+/// `log_level = "info"`, or `log_level = "debug"`.
+#[macro_export]
+macro_rules! trace {
+    (target: $target:expr, $($arg:tt)*) => (
+        log!(target: $target, $crate::LogLevel::Trace, $($arg)*);
+    );
+    ($($arg:tt)*) => (
+        log!($crate::LogLevel::Trace, $($arg)*);
+    )
+}
+
+/// Determines if a message logged at the specified level in that module will
+/// be logged.
+///
+/// This can be used to avoid expensive computation of log message arguments if
+/// the message would be ignored anyway.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate log;
+/// use log::LogLevel::Debug;
+///
+/// # fn foo() {
+/// if log_enabled!(Debug) {
+///     debug!("expensive debug data: {}", expensive_call());
+/// }
+/// # }
+/// # fn expensive_call() -> u32 { 0 }
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! log_enabled {
+    (target: $target:expr, $lvl:expr) => ({
+        let lvl = $lvl;
+        !cfg!(log_level = "off") &&
+            (lvl <= $crate::LogLevel::Error || !cfg!(log_level = "error")) &&
+            (lvl <= $crate::LogLevel::Warn || !cfg!(log_level = "warn")) &&
+            (lvl <= $crate::LogLevel::Debug || !cfg!(log_level = "debug")) &&
+            (lvl <= $crate::LogLevel::Info || !cfg!(log_level = "info")) &&
+            lvl <= $crate::max_log_level() &&
+            $crate::__enabled(lvl, $target)
+    });
+    ($lvl:expr) => (log_enabled!(target: module_path!(), $lvl))
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/memchr/lib.rs.html b/src/memchr/lib.rs.html new file mode 100644 index 0000000..0e3568c --- /dev/null +++ b/src/memchr/lib.rs.html @@ -0,0 +1,287 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+/*!
+This crate defines a single function, `memchr`, which exposes a safe interface
+to the corresponding function in `libc`.
+*/
+
+#![deny(missing_docs)]
+
+extern crate libc;
+
+use libc::funcs::c95::string;
+use libc::types::common::c95::c_void;
+use libc::types::os::arch::c95::{c_int, size_t};
+
+/// A safe interface to `memchr`.
+///
+/// Returns the index corresponding to the first occurrence of `needle` in
+/// `haystack`, or `None` if one is not found.
+///
+/// memchr reduces to super-optimized machine code at around an order of
+/// magnitude faster than `haystack.iter().position(|&b| b == needle)`.
+/// (See benchmarks.)
+///
+/// # Example
+///
+/// This shows how to find the first position of a byte in a byte string.
+///
+/// ```rust
+/// use memchr::memchr;
+///
+/// let haystack = b"the quick brown fox";
+/// assert_eq!(memchr(b'k', haystack), Some(8));
+/// ```
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    let p = unsafe {
+        string::memchr(
+            haystack.as_ptr() as *const c_void,
+            needle as c_int,
+            haystack.len() as size_t)
+    };
+    if p.is_null() {
+        None
+    } else {
+        Some(p as usize - (haystack.as_ptr() as usize))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    extern crate quickcheck;
+
+    use super::memchr;
+
+    #[test]
+    fn matches_one() {
+        assert_eq!(Some(0), memchr(b'a', b"a"));
+    }
+
+    #[test]
+    fn matches_begin() {
+        assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+    }
+
+    #[test]
+    fn matches_end() {
+        assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+    }
+
+    #[test]
+    fn matches_nul() {
+        assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+    }
+
+    #[test]
+    fn matches_past_nul() {
+        assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+    }
+
+    #[test]
+    fn no_match_empty() {
+        assert_eq!(None, memchr(b'a', b""));
+    }
+
+    #[test]
+    fn no_match() {
+        assert_eq!(None, memchr(b'a', b"xyz"));
+    }
+
+    #[test]
+    fn qc_never_fail() {
+        fn prop(needle: u8, haystack: Vec<u8>) -> bool {
+            memchr(needle, &haystack); true
+        }
+        quickcheck::quickcheck(prop as fn(u8, Vec<u8>) -> bool);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/asn1/mod.rs.html b/src/openssl/asn1/mod.rs.html new file mode 100644 index 0000000..5d7d165 --- /dev/null +++ b/src/openssl/asn1/mod.rs.html @@ -0,0 +1,195 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+use libc::{c_long};
+use std::ptr;
+
+use ffi;
+use ssl::error::{SslError};
+
+
+pub struct Asn1Time {
+    handle: *mut ffi::ASN1_TIME,
+    owned: bool
+}
+
+impl Asn1Time {
+    /// Wraps existing ASN1_TIME and takes ownership
+    pub fn new(handle: *mut ffi::ASN1_TIME) -> Asn1Time {
+        Asn1Time {
+            handle: handle,
+            owned: true
+        }
+    }
+
+    fn new_with_period(period: u64) -> Result<Asn1Time, SslError> {
+        ffi::init();
+
+        let handle = unsafe {
+            try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(),
+                                               period as c_long))
+        };
+        Ok(Asn1Time::new(handle))
+    }
+
+    /// Creates a new time on specified interval in days from now
+    pub fn days_from_now(days: u32) -> Result<Asn1Time, SslError> {
+        Asn1Time::new_with_period(days as u64 * 60 * 60 * 24)
+    }
+
+    /// Returns raw handle
+    pub unsafe fn get_handle(&self) -> *mut ffi::ASN1_TIME {
+        return self.handle
+    }
+}
+
+impl Drop for Asn1Time {
+    fn drop(&mut self) {
+        if self.owned {
+            unsafe { ffi::ASN1_TIME_free(self.handle) };
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/bio/mod.rs.html b/src/openssl/bio/mod.rs.html new file mode 100644 index 0000000..0d8a555 --- /dev/null +++ b/src/openssl/bio/mod.rs.html @@ -0,0 +1,309 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+use libc::{c_void, c_int};
+use std::io;
+use std::io::prelude::*;
+use std::ptr;
+use std::cmp;
+
+use ffi;
+use ssl::error::{SslError};
+
+pub struct MemBio {
+    bio: *mut ffi::BIO,
+    owned: bool
+}
+
+impl Drop for MemBio {
+    fn drop(&mut self) {
+        if self.owned {
+            unsafe {
+                ffi::BIO_free_all(self.bio);
+            }
+        }
+    }
+}
+
+impl MemBio {
+    /// Creates a new owned memory based BIO
+    pub fn new() -> Result<MemBio, SslError> {
+        ffi::init();
+
+        let bio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) };
+        try_ssl_null!(bio);
+
+        Ok(MemBio {
+            bio: bio,
+            owned: true
+        })
+    }
+
+    /// Returns a "borrow", i.e. it has no ownership
+    pub fn borrowed(bio: *mut ffi::BIO) -> MemBio {
+        MemBio {
+            bio: bio,
+            owned: false
+        }
+    }
+
+    /// Consumes current bio and returns wrapped value
+    /// Note that data ownership is lost and
+    /// should be managed manually
+    pub unsafe fn unwrap(mut self) -> *mut ffi::BIO {
+        self.owned = false;
+        self.bio
+    }
+
+    /// Temporarily gets wrapped value
+    pub unsafe fn get_handle(&self) -> *mut ffi::BIO {
+        self.bio
+    }
+
+    /// Sets the BIO's EOF state.
+    pub fn set_eof(&self, eof: bool) {
+        let v = if eof { 0 } else { -1 };
+        unsafe { ffi::BIO_set_mem_eof_return(self.bio, v); }
+    }
+}
+
+impl Read for MemBio {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+        let ret = unsafe {
+            ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, len)
+        };
+
+        if ret <= 0 {
+            let is_eof = unsafe { ffi::BIO_eof(self.bio) };
+            if is_eof {
+                Ok(0)
+            } else {
+                Err(io::Error::new(io::ErrorKind::Other,
+                                   SslError::get()))
+            }
+        } else {
+            Ok(ret as usize)
+        }
+    }
+}
+
+impl Write for MemBio {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+        let ret = unsafe {
+            ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, len)
+        };
+
+        if ret < 0 {
+                Err(io::Error::new(io::ErrorKind::Other,
+                                   SslError::get()))
+        } else {
+            Ok(ret as usize)
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/bn/mod.rs.html b/src/openssl/bn/mod.rs.html new file mode 100644 index 0000000..f57f83e --- /dev/null +++ b/src/openssl/bn/mod.rs.html @@ -0,0 +1,1305 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+
+use libc::{c_int, c_ulong, c_void};
+use std::ffi::{CStr, CString};
+use std::cmp::Ordering;
+use std::{fmt, ptr};
+
+use ffi;
+use ssl::error::SslError;
+
+pub struct BigNum(*mut ffi::BIGNUM);
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum RNGProperty {
+    MsbMaybeZero = -1,
+    MsbOne = 0,
+    TwoMsbOne = 1,
+}
+
+macro_rules! with_ctx(
+    ($name:ident, $action:block) => ({
+        let $name = ffi::BN_CTX_new();
+        if ($name).is_null() {
+            Err(SslError::get())
+        } else {
+            let r = $action;
+            ffi::BN_CTX_free($name);
+            r
+        }
+    });
+);
+
+macro_rules! with_bn(
+    ($name:ident, $action:block) => ({
+        let tmp = BigNum::new();
+        match tmp {
+            Ok($name) => {
+                if $action {
+                    Ok($name)
+                } else {
+                    Err(SslError::get())
+                }
+            },
+            Err(err) => Err(err),
+        }
+    });
+);
+
+macro_rules! with_bn_in_ctx(
+    ($name:ident, $ctx_name:ident, $action:block) => ({
+        let tmp = BigNum::new();
+        match tmp {
+            Ok($name) => {
+                let $ctx_name = ffi::BN_CTX_new();
+                if ($ctx_name).is_null() {
+                    Err(SslError::get())
+                } else {
+                    let r =
+                        if $action {
+                            Ok($name)
+                        } else {
+                            Err(SslError::get())
+                        };
+                    ffi::BN_CTX_free($ctx_name);
+                    r
+                }
+            },
+            Err(err) => Err(err),
+        }
+    });
+);
+
+impl BigNum {
+    pub fn new() -> Result<BigNum, SslError> {
+        unsafe {
+            ffi::init();
+
+            let v = try_ssl_null!(ffi::BN_new());
+            Ok(BigNum(v))
+        }
+    }
+
+    pub fn new_from(n: u64) -> Result<BigNum, SslError> {
+        BigNum::new().and_then(|v| unsafe {
+            try_ssl!(ffi::BN_set_word(v.raw(), n as c_ulong));
+            Ok(v)
+        })
+    }
+
+    pub fn from_dec_str(s: &str) -> Result<BigNum, SslError> {
+        BigNum::new().and_then(|v| unsafe {
+            let c_str = CString::new(s.as_bytes()).unwrap();
+            try_ssl!(ffi::BN_dec2bn(v.raw_ptr(), c_str.as_ptr()));
+            Ok(v)
+        })
+    }
+
+    pub fn from_hex_str(s: &str) -> Result<BigNum, SslError> {
+        BigNum::new().and_then(|v| unsafe {
+            let c_str = CString::new(s.as_bytes()).unwrap();
+            try_ssl!(ffi::BN_hex2bn(v.raw_ptr(), c_str.as_ptr()));
+            Ok(v)
+        })
+    }
+
+    pub fn new_from_slice(n: &[u8]) -> Result<BigNum, SslError> {
+        BigNum::new().and_then(|v| unsafe {
+            try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.raw()));
+            Ok(v)
+        })
+    }
+
+    pub fn checked_sqr(&self) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_sqr(r.raw(), self.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_nnmod(&self, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_nnmod(r.raw(), self.raw(), n.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod_add(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_mod_add(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod_sub(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_mod_sub(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod_mul(&self, a: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_mod_mul(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod_sqr(&self, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_mod_sqr(r.raw(), self.raw(), n.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_exp(&self, p: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_exp(r.raw(), self.raw(), p.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod_exp(&self, p: &BigNum, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_mod_exp(r.raw(), self.raw(), p.raw(), n.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod_inv(&self, n: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { !ffi::BN_mod_inverse(r.raw(), self.raw(), n.raw(), ctx).is_null() })
+        }
+    }
+
+    pub fn add_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+        unsafe {
+            if ffi::BN_add_word(self.raw(), w) == 1 {
+                Ok(())
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn sub_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+        unsafe {
+            if ffi::BN_sub_word(self.raw(), w) == 1 {
+                Ok(())
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn mul_word(&mut self, w: c_ulong) -> Result<(), SslError> {
+        unsafe {
+            if ffi::BN_mul_word(self.raw(), w) == 1 {
+                Ok(())
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn div_word(&mut self, w: c_ulong) -> Result<c_ulong, SslError> {
+        unsafe {
+            let result = ffi::BN_div_word(self.raw(), w);
+            if result != !0 as c_ulong {
+                Ok(result)
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn mod_word(&self, w: c_ulong) -> Result<c_ulong, SslError> {
+        unsafe {
+            let result = ffi::BN_mod_word(self.raw(), w);
+            if result != !0 as c_ulong {
+                Ok(result)
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn checked_gcd(&self, a: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_gcd(r.raw(), self.raw(), a.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_generate_prime(bits: i32, safe: bool, add: Option<&BigNum>, rem: Option<&BigNum>) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, {
+                let add_arg = add.map(|a| a.raw()).unwrap_or(ptr::null_mut());
+                let rem_arg = rem.map(|r| r.raw()).unwrap_or(ptr::null_mut());
+
+                ffi::BN_generate_prime_ex(r.raw(), bits as c_int, safe as c_int, add_arg, rem_arg, ptr::null()) == 1
+            })
+        }
+    }
+
+    pub fn is_prime(&self, checks: i32) -> Result<bool, SslError> {
+        unsafe {
+            with_ctx!(ctx, {
+                Ok(ffi::BN_is_prime_ex(self.raw(), checks as c_int, ctx, ptr::null()) == 1)
+            })
+        }
+    }
+
+    pub fn is_prime_fast(&self, checks: i32, do_trial_division: bool) -> Result<bool, SslError> {
+        unsafe {
+            with_ctx!(ctx, {
+                Ok(ffi::BN_is_prime_fasttest_ex(self.raw(), checks as c_int, ctx, do_trial_division as c_int, ptr::null()) == 1)
+            })
+        }
+    }
+
+    pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1 })
+        }
+    }
+
+    pub fn checked_new_pseudo_random(bits: i32, prop: RNGProperty, odd: bool) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_pseudo_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1 })
+        }
+    }
+
+    pub fn checked_rand_in_range(&self) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_rand_range(r.raw(), self.raw()) == 1 })
+        }
+    }
+
+    pub fn checked_pseudo_rand_in_range(&self) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_pseudo_rand_range(r.raw(), self.raw()) == 1 })
+        }
+    }
+
+    pub fn set_bit(&mut self, n: i32) -> Result<(), SslError> {
+        unsafe {
+            if ffi::BN_set_bit(self.raw(), n as c_int) == 1 {
+                Ok(())
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn clear_bit(&mut self, n: i32) -> Result<(), SslError> {
+        unsafe {
+            if ffi::BN_clear_bit(self.raw(), n as c_int) == 1 {
+                Ok(())
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn is_bit_set(&self, n: i32) -> bool {
+        unsafe {
+            ffi::BN_is_bit_set(self.raw(), n as c_int) == 1
+        }
+    }
+
+    pub fn mask_bits(&mut self, n: i32) -> Result<(), SslError> {
+        unsafe {
+            if ffi::BN_mask_bits(self.raw(), n as c_int) == 1 {
+                Ok(())
+            } else {
+                Err(SslError::get())
+            }
+        }
+    }
+
+    pub fn checked_shl1(&self) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn!(r, { ffi::BN_lshift1(r.raw(), self.raw()) == 1 })
+        }
+    }
+
+    pub fn checked_shr1(&self) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn!(r, { ffi::BN_rshift1(r.raw(), self.raw()) == 1 })
+        }
+    }
+
+    pub fn checked_add(&self, a: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn!(r, { ffi::BN_add(r.raw(), self.raw(), a.raw()) == 1 })
+        }
+    }
+
+    pub fn checked_sub(&self, a: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn!(r, { ffi::BN_sub(r.raw(), self.raw(), a.raw()) == 1 })
+        }
+    }
+
+    pub fn checked_mul(&self, a: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_mul(r.raw(), self.raw(), a.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_div(&self, a: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_div(r.raw(), ptr::null_mut(), self.raw(), a.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_mod(&self, a: &BigNum) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn_in_ctx!(r, ctx, { ffi::BN_div(ptr::null_mut(), r.raw(), self.raw(), a.raw(), ctx) == 1 })
+        }
+    }
+
+    pub fn checked_shl(&self, a: &i32) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn!(r, { ffi::BN_lshift(r.raw(), self.raw(), *a as c_int) == 1 })
+        }
+    }
+
+    pub fn checked_shr(&self, a: &i32) -> Result<BigNum, SslError> {
+        unsafe {
+            with_bn!(r, { ffi::BN_rshift(r.raw(), self.raw(), *a as c_int) == 1 })
+        }
+    }
+
+    pub fn negate(&mut self) {
+        unsafe {
+            ffi::BN_set_negative(self.raw(), !self.is_negative() as c_int)
+        }
+    }
+
+    pub fn abs_cmp(&self, oth: BigNum) -> Ordering {
+        unsafe {
+            let res = ffi::BN_ucmp(self.raw(), oth.raw()) as i32;
+            if res < 0 {
+                Ordering::Less
+            } else if res > 0 {
+                Ordering::Greater
+            } else {
+                Ordering::Equal
+            }
+        }
+    }
+
+    pub fn is_negative(&self) -> bool {
+        unsafe {
+            (*self.raw()).neg == 1
+        }
+    }
+
+    pub fn num_bits(&self) -> i32 {
+        unsafe {
+            ffi::BN_num_bits(self.raw()) as i32
+        }
+    }
+
+    pub fn num_bytes(&self) -> i32 {
+        (self.num_bits() + 7) / 8
+    }
+
+    unsafe fn raw(&self) -> *mut ffi::BIGNUM {
+        let BigNum(n) = *self;
+        n
+    }
+
+    unsafe fn raw_ptr(&self) -> *const *mut ffi::BIGNUM {
+        let BigNum(ref n) = *self;
+        n
+    }
+
+    pub fn to_vec(&self) -> Vec<u8> {
+        let size = self.num_bytes() as usize;
+        let mut v = Vec::with_capacity(size);
+        unsafe {
+            ffi::BN_bn2bin(self.raw(), v.as_mut_ptr());
+            v.set_len(size);
+        }
+        v
+    }
+
+    pub fn to_dec_str(&self) -> String {
+        unsafe {
+            let buf = ffi::BN_bn2dec(self.raw());
+            assert!(!buf.is_null());
+            let str = String::from_utf8(CStr::from_ptr(buf).to_bytes().to_vec()).unwrap();
+            ffi::CRYPTO_free(buf as *mut c_void);
+            str
+        }
+    }
+
+    pub fn to_hex_str(&self) -> String {
+        unsafe {
+            let buf = ffi::BN_bn2hex(self.raw());
+            assert!(!buf.is_null());
+            let str = String::from_utf8(CStr::from_ptr(buf).to_bytes().to_vec()).unwrap();
+            ffi::CRYPTO_free(buf as *mut c_void);
+            str
+        }
+    }
+}
+
+impl fmt::Debug for BigNum {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_dec_str())
+    }
+}
+
+impl Eq for BigNum { }
+impl PartialEq for BigNum {
+    fn eq(&self, oth: &BigNum) -> bool {
+        unsafe {
+            ffi::BN_cmp(self.raw(), oth.raw()) == 0
+        }
+    }
+}
+
+impl Ord for BigNum {
+    fn cmp(&self, oth: &BigNum) -> Ordering {
+        self.partial_cmp(oth).unwrap()
+    }
+}
+
+impl PartialOrd for BigNum {
+    fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
+        unsafe {
+            let v = ffi::BN_cmp(self.raw(), oth.raw());
+            let ret =
+                if v == 0 {
+                    Ordering::Equal
+                } else if v < 0 {
+                    Ordering::Less
+                } else {
+                    Ordering::Greater
+                };
+            Some(ret)
+        }
+    }
+}
+
+impl Drop for BigNum {
+    fn drop(&mut self) {
+        unsafe {
+            if !self.raw().is_null() {
+                ffi::BN_clear_free(self.raw());
+            }
+        }
+    }
+}
+
+pub mod unchecked {
+    use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub};
+    use ffi;
+    use super::{BigNum};
+
+    impl<'a> Add<&'a BigNum> for &'a BigNum {
+        type Output = BigNum;
+
+        fn add(self, oth: &'a BigNum) -> BigNum {
+            self.checked_add(oth).unwrap()
+        }
+    }
+
+    impl<'a> Sub<&'a BigNum> for &'a BigNum {
+        type Output = BigNum;
+
+        fn sub(self, oth: &'a BigNum) -> BigNum {
+            self.checked_sub(oth).unwrap()
+        }
+    }
+
+    impl<'a> Mul<&'a BigNum> for &'a BigNum {
+        type Output = BigNum;
+
+        fn mul(self, oth: &'a BigNum) -> BigNum {
+            self.checked_mul(oth).unwrap()
+        }
+    }
+
+    impl<'a> Div<&'a BigNum> for &'a BigNum {
+        type Output = BigNum;
+
+        fn div(self, oth: &'a BigNum) -> BigNum {
+            self.checked_div(oth).unwrap()
+        }
+    }
+
+    impl<'a> Rem<&'a BigNum> for &'a BigNum {
+        type Output = BigNum;
+
+        fn rem(self, oth: &'a BigNum) -> BigNum {
+            self.checked_mod(oth).unwrap()
+        }
+    }
+
+    impl<'a> Shl<i32> for &'a BigNum {
+        type Output = BigNum;
+
+        fn shl(self, n: i32) -> BigNum {
+            self.checked_shl(&n).unwrap()
+        }
+    }
+
+    impl<'a> Shr<i32> for &'a BigNum {
+        type Output = BigNum;
+
+        fn shr(self, n: i32) -> BigNum {
+            self.checked_shr(&n).unwrap()
+        }
+    }
+
+    impl Clone for BigNum {
+        fn clone(&self) -> BigNum {
+            unsafe {
+                let r = ffi::BN_dup(self.raw());
+                if r.is_null() {
+                    panic!("Unexpected null pointer from BN_dup(..)")
+                } else {
+                    BigNum(r)
+                }
+            }
+        }
+    }
+
+    impl Neg for BigNum {
+        type Output = BigNum;
+
+        fn neg(self) -> BigNum {
+            let mut n = self.clone();
+            n.negate();
+            n
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use bn::BigNum;
+
+    #[test]
+    fn test_to_from_slice() {
+        let v0 = BigNum::new_from(10203004_u64).unwrap();
+        let vec = v0.to_vec();
+        let v1 = BigNum::new_from_slice(&vec).unwrap();
+
+        assert!(v0 == v1);
+    }
+
+    #[test]
+    fn test_negation() {
+        let a = BigNum::new_from(909829283_u64).unwrap();
+
+        assert!(!a.is_negative());
+        assert!((-a).is_negative());
+    }
+
+
+    #[test]
+    fn test_prime_numbers() {
+        let a = BigNum::new_from(19029017_u64).unwrap();
+        let p = BigNum::checked_generate_prime(128, true, None, Some(&a)).unwrap();
+
+        assert!(p.is_prime(100).unwrap());
+        assert!(p.is_prime_fast(100, true).unwrap());
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/hash.rs.html b/src/openssl/crypto/hash.rs.html new file mode 100644 index 0000000..3acc27b --- /dev/null +++ b/src/openssl/crypto/hash.rs.html @@ -0,0 +1,773 @@ + + + + + + + + + + hash.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+
+use libc::c_uint;
+use std::iter::repeat;
+use std::io::prelude::*;
+use std::io;
+
+use ffi;
+
+/// Message digest (hash) type.
+#[derive(Copy, Clone)]
+pub enum Type {
+    MD5,
+    SHA1,
+    SHA224,
+    SHA256,
+    SHA384,
+    SHA512,
+    RIPEMD160
+}
+
+impl Type {
+    /// Returns the length of the message digest.
+    #[inline]
+    pub fn md_len(&self) -> usize {
+        use self::Type::*;
+        match *self {
+            MD5 => 16,
+            SHA1 => 20,
+            SHA224 => 28,
+            SHA256 => 32,
+            SHA384 => 48,
+            SHA512 => 64,
+            RIPEMD160 => 20,
+        }
+    }
+
+    /// Internal interface subject to removal.
+    #[inline]
+    pub fn evp_md(&self) -> *const ffi::EVP_MD {
+        unsafe {
+            use self::Type::*;
+            match *self {
+                MD5 => ffi::EVP_md5(),
+                SHA1 => ffi::EVP_sha1(),
+                SHA224 => ffi::EVP_sha224(),
+                SHA256 => ffi::EVP_sha256(),
+                SHA384 => ffi::EVP_sha384(),
+                SHA512 => ffi::EVP_sha512(),
+                RIPEMD160 => ffi::EVP_ripemd160(),
+            }
+        }
+    }
+}
+
+#[derive(PartialEq, Copy, Clone)]
+enum State {
+    Reset,
+    Updated,
+    Finalized,
+}
+
+use self::State::*;
+
+/// Provides message digest (hash) computation.
+///
+/// # Examples
+///
+/// Calculate a hash in one go.
+///
+/// ```
+/// use openssl::crypto::hash::{hash, Type};
+/// let data = b"\x42\xF4\x97\xE0";
+/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
+/// let res = hash(Type::MD5, data);
+/// assert_eq!(res, spec);
+/// ```
+///
+/// Use the `Write` trait to supply the input in chunks.
+///
+/// ```
+/// use std::io::prelude::*;
+/// use openssl::crypto::hash::{Hasher, Type};
+/// let data = [b"\x42\xF4", b"\x97\xE0"];
+/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
+/// let mut h = Hasher::new(Type::MD5);
+/// h.write_all(data[0]);
+/// h.write_all(data[1]);
+/// let res = h.finish();
+/// assert_eq!(res, spec);
+/// ```
+///
+/// # Warning
+///
+/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
+///
+/// Don't ever hash passwords, use `crypto::pkcs5` or bcrypt/scrypt instead.
+pub struct Hasher {
+    ctx: *mut ffi::EVP_MD_CTX,
+    md: *const ffi::EVP_MD,
+    type_: Type,
+    state: State,
+}
+
+impl Hasher {
+    /// Creates a new `Hasher` with the specified hash type.
+    pub fn new(ty: Type) -> Hasher {
+        ffi::init();
+
+        let ctx = unsafe {
+            let r = ffi::EVP_MD_CTX_create();
+            assert!(!r.is_null());
+            r
+        };
+        let md = ty.evp_md();
+
+        let mut h = Hasher { ctx: ctx, md: md, type_: ty, state: Finalized };
+        h.init();
+        h
+    }
+
+    #[inline]
+    fn init(&mut self) {
+        match self.state {
+            Reset => return,
+            Updated => { self.finalize(); },
+            Finalized => (),
+        }
+        unsafe {
+            let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _);
+            assert_eq!(r, 1);
+        }
+        self.state = Reset;
+    }
+
+    #[inline]
+    fn update(&mut self, data: &[u8]) {
+        if self.state == Finalized {
+            self.init();
+        }
+        unsafe {
+            let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(),
+                                          data.len() as c_uint);
+            assert_eq!(r, 1);
+        }
+        self.state = Updated;
+    }
+
+    #[inline]
+    fn finalize(&mut self) -> Vec<u8> {
+        if self.state == Finalized {
+            self.init();
+        }
+        let md_len = self.type_.md_len();
+        let mut res: Vec<u8> = repeat(0).take(md_len).collect();
+        unsafe {
+            let mut len = 0;
+            let r = ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len);
+            self.state = Finalized;
+            assert_eq!(len as usize, md_len);
+            assert_eq!(r, 1);
+        }
+        res
+    }
+
+    /// Returns the hash of the data written since creation or
+    /// the last `finish` and resets the hasher.
+    #[inline]
+    pub fn finish(&mut self) -> Vec<u8> {
+        self.finalize()
+    }
+}
+
+impl Write for Hasher {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.update(buf);
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Clone for Hasher {
+    fn clone(&self) -> Hasher {
+        let ctx = unsafe {
+            let ctx = ffi::EVP_MD_CTX_create();
+            assert!(!ctx.is_null());
+            let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
+            assert_eq!(r, 1);
+            ctx
+        };
+        Hasher { ctx: ctx, md: self.md, type_: self.type_, state: self.state }
+    }
+}
+
+impl Drop for Hasher {
+    fn drop(&mut self) {
+        unsafe {
+            if self.state != Finalized {
+                let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
+                let mut len = 0;
+                ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len);
+            }
+            ffi::EVP_MD_CTX_destroy(self.ctx);
+        }
+    }
+}
+
+/// Computes the hash of the `data` with the hash `t`.
+pub fn hash(t: Type, data: &[u8]) -> Vec<u8> {
+    let mut h = Hasher::new(t);
+    let _ = h.write_all(data);
+    h.finish()
+}
+
+#[cfg(test)]
+mod tests {
+    use serialize::hex::{FromHex, ToHex};
+    use super::{hash, Hasher, Type};
+    use std::io::prelude::*;
+
+    fn hash_test(hashtype: Type, hashtest: &(&str, &str)) {
+        let res = hash(hashtype, &*hashtest.0.from_hex().unwrap());
+        assert_eq!(res.to_hex(), hashtest.1);
+    }
+
+    fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
+        let _ = h.write_all(&*hashtest.0.from_hex().unwrap());
+        let res = h.finish();
+        assert_eq!(res.to_hex(), hashtest.1);
+    }
+
+    // Test vectors from http://www.nsrl.nist.gov/testdata/
+    #[allow(non_upper_case_globals)]
+    const md5_tests: [(&'static str, &'static str); 13] = [
+        ("", "d41d8cd98f00b204e9800998ecf8427e"),
+        ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
+        ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
+        ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
+        ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
+        ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
+        ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
+        ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
+        ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
+        ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
+        ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
+        ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
+        ("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")
+    ];
+
+    #[test]
+    fn test_md5() {
+        for test in md5_tests.iter() {
+            hash_test(Type::MD5, test);
+        }
+    }
+
+    #[test]
+    fn test_md5_recycle() {
+        let mut h = Hasher::new(Type::MD5);
+        for test in md5_tests.iter() {
+            hash_recycle_test(&mut h, test);
+        }
+    }
+
+    #[test]
+    fn test_finish_twice() {
+        let mut h = Hasher::new(Type::MD5);
+        let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap());
+        let _ = h.finish();
+        let res = h.finish();
+        let null = hash(Type::MD5, &[]);
+        assert_eq!(res, null);
+    }
+
+    #[test]
+    fn test_clone() {
+        let i = 7;
+        let inp = md5_tests[i].0.from_hex().unwrap();
+        assert!(inp.len() > 2);
+        let p = inp.len() / 2;
+        let h0 = Hasher::new(Type::MD5);
+
+        println!("Clone a new hasher");
+        let mut h1 = h0.clone();
+        let _ = h1.write_all(&inp[..p]);
+        {
+            println!("Clone an updated hasher");
+            let mut h2 = h1.clone();
+            let _ = h2.write_all(&inp[p..]);
+            let res = h2.finish();
+            assert_eq!(res.to_hex(), md5_tests[i].1);
+        }
+        let _ = h1.write_all(&inp[p..]);
+        let res = h1.finish();
+        assert_eq!(res.to_hex(), md5_tests[i].1);
+
+        println!("Clone a finished hasher");
+        let mut h3 = h1.clone();
+        let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap());
+        let res = h3.finish();
+        assert_eq!(res.to_hex(), md5_tests[i + 1].1);
+    }
+
+    #[test]
+    fn test_sha1() {
+        let tests = [
+            ("616263", "a9993e364706816aba3e25717850c26c9cd0d89d"),
+            ];
+
+        for test in tests.iter() {
+            hash_test(Type::SHA1, test);
+        }
+    }
+
+    #[test]
+    fn test_sha256() {
+        let tests = [
+            ("616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
+            ];
+
+        for test in tests.iter() {
+            hash_test(Type::SHA256, test);
+        }
+    }
+
+    #[test]
+    fn test_ripemd160() {
+        let tests = [
+            ("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")
+            ];
+
+        for test in tests.iter() {
+            hash_test(Type::RIPEMD160, test);
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/hmac.rs.html b/src/openssl/crypto/hmac.rs.html new file mode 100644 index 0000000..e63ec32 --- /dev/null +++ b/src/openssl/crypto/hmac.rs.html @@ -0,0 +1,1053 @@ + + + + + + + + + + hmac.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+
+/*
+ * Copyright 2013 Jack Lloyd
+ *
+ * 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.
+ */
+
+use libc::{c_int, c_uint};
+use std::iter::repeat;
+use std::io;
+use std::io::prelude::*;
+
+use crypto::hash::Type;
+use ffi;
+
+#[derive(PartialEq, Copy, Clone)]
+enum State {
+    Reset,
+    Updated,
+    Finalized,
+}
+
+use self::State::*;
+
+/// Provides HMAC computation.
+///
+/// # Examples
+///
+/// Calculate a HMAC in one go.
+///
+/// ```
+/// use openssl::crypto::hash::Type;
+/// use openssl::crypto::hmac::hmac;
+/// let key = b"Jefe";
+/// let data = b"what do ya want for nothing?";
+/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
+/// let res = hmac(Type::MD5, key, data);
+/// assert_eq!(res, spec);
+/// ```
+///
+/// Use the `Write` trait to supply the input in chunks.
+///
+/// ```
+/// use std::io::prelude::*;
+/// use openssl::crypto::hash::Type;
+/// use openssl::crypto::hmac::HMAC;
+/// let key = b"Jefe";
+/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
+/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
+/// let mut h = HMAC::new(Type::MD5, &*key);
+/// h.write_all(data[0]);
+/// h.write_all(data[1]);
+/// let res = h.finish();
+/// assert_eq!(res, spec);
+/// ```
+pub struct HMAC {
+    ctx: ffi::HMAC_CTX,
+    type_: Type,
+    state: State,
+}
+
+impl HMAC {
+    /// Creates a new `HMAC` with the specified hash type using the `key`.
+    pub fn new(ty: Type, key: &[u8]) -> HMAC {
+        ffi::init();
+
+        let ctx = unsafe {
+            let mut ctx = ::std::mem::uninitialized();
+            ffi::HMAC_CTX_init(&mut ctx);
+            ctx
+        };
+        let md = ty.evp_md();
+
+        let mut h = HMAC { ctx: ctx, type_: ty, state: Finalized };
+        h.init_once(md, key);
+        h
+    }
+
+    #[inline]
+    fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) {
+        unsafe {
+            let r = ffi::HMAC_Init_ex_shim(&mut self.ctx,
+                                           key.as_ptr(), key.len() as c_int,
+                                           md, 0 as *const _);
+            assert_eq!(r, 1);
+        }
+        self.state = Reset;
+    }
+
+    #[inline]
+    fn init(&mut self) {
+        match self.state {
+            Reset => return,
+            Updated => { self.finalize(); },
+            Finalized => (),
+        }
+        // If the key and/or md is not supplied it's reused from the last time
+        // avoiding redundant initializations
+        unsafe {
+            let r = ffi::HMAC_Init_ex_shim(&mut self.ctx,
+                                           0 as *const _, 0,
+                                           0 as *const _, 0 as *const _);
+            assert_eq!(r, 1);
+        }
+        self.state = Reset;
+    }
+
+    #[inline]
+    fn update(&mut self, data: &[u8]) {
+        if self.state == Finalized {
+            self.init();
+        }
+        unsafe {
+            let r = ffi::HMAC_Update_shim(&mut self.ctx, data.as_ptr(), data.len() as c_uint);
+            assert_eq!(r, 1);
+        }
+        self.state = Updated;
+    }
+
+    #[inline]
+    fn finalize(&mut self) -> Vec<u8> {
+        if self.state == Finalized {
+            self.init();
+        }
+        let md_len = self.type_.md_len();
+        let mut res: Vec<u8> = repeat(0).take(md_len).collect();
+        unsafe {
+            let mut len = 0;
+            let r = ffi::HMAC_Final_shim(&mut self.ctx, res.as_mut_ptr(), &mut len);
+            self.state = Finalized;
+            assert_eq!(len as usize, md_len);
+            assert_eq!(r, 1);
+        }
+        res
+    }
+
+    /// Returns the hash of the data written since creation or
+    /// the last `finish` and resets the hasher.
+    #[inline]
+    pub fn finish(&mut self) -> Vec<u8> {
+        self.finalize()
+    }
+}
+
+impl Write for HMAC {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.update(buf);
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Clone for HMAC {
+    fn clone(&self) -> HMAC {
+        let mut ctx: ffi::HMAC_CTX;
+        unsafe {
+            ctx = ::std::mem::uninitialized();
+            let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx);
+            assert_eq!(r, 1);
+        }
+        HMAC { ctx: ctx, type_: self.type_, state: self.state }
+    }
+}
+
+impl Drop for HMAC {
+    fn drop(&mut self) {
+        unsafe {
+            if self.state != Finalized {
+                let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
+                let mut len = 0;
+                ffi::HMAC_Final_shim(&mut self.ctx, buf.as_mut_ptr(), &mut len);
+            }
+            ffi::HMAC_CTX_cleanup(&mut self.ctx);
+        }
+    }
+}
+
+/// Computes the HMAC of the `data` with the hash `t` and `key`.
+pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Vec<u8> {
+    let mut h = HMAC::new(t, key);
+    let _ = h.write_all(data);
+    h.finish()
+}
+
+#[cfg(test)]
+mod tests {
+    use std::iter::repeat;
+    use serialize::hex::FromHex;
+    use crypto::hash::Type;
+    use crypto::hash::Type::*;
+    use super::{hmac, HMAC};
+    use std::io::prelude::*;
+
+    fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
+        for &(ref key, ref data, ref res) in tests.iter() {
+            assert_eq!(hmac(ty, &**key, &**data), *res);
+        }
+    }
+
+    fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
+        let &(_, ref data, ref res) = test;
+        let _ = h.write_all(&**data);
+        assert_eq!(h.finish(), *res);
+    }
+
+    #[test]
+    fn test_hmac_md5() {
+        // test vectors from RFC 2202
+        let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] = [
+            (repeat(0x0b_u8).take(16).collect(), b"Hi There".to_vec(),
+             "9294727a3638bb1c13f48ef8158bfc9d".from_hex().unwrap()),
+            (b"Jefe".to_vec(),
+             b"what do ya want for nothing?".to_vec(),
+             "750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(16).collect(), repeat(0xdd_u8).take(50).collect(),
+             "56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()),
+            ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
+             repeat(0xcd_u8).take(50).collect(),
+             "697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()),
+            (repeat(0x0c_u8).take(16).collect(),
+             b"Test With Truncation".to_vec(),
+             "56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+             "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key \
+               and Larger Than One Block-Size Data".to_vec(),
+             "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())
+        ];
+
+        test_hmac(MD5, &tests);
+    }
+
+    #[test]
+    fn test_hmac_md5_recycle() {
+        let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] = [
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+             "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key \
+               and Larger Than One Block-Size Data".to_vec(),
+             "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())
+        ];
+
+        let mut h = HMAC::new(MD5, &*tests[0].0);
+        for i in 0..100usize {
+            let test = &tests[i % 2];
+            test_hmac_recycle(&mut h, test);
+        }
+    }
+
+    #[test]
+    fn test_finish_twice() {
+        let test: (Vec<u8>, Vec<u8>, Vec<u8>) =
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+             "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
+
+        let mut h = HMAC::new(Type::MD5, &*test.0);
+        let _ = h.write_all(&*test.1);
+        let _ = h.finish();
+        let res = h.finish();
+        let null = hmac(Type::MD5, &*test.0, &[]);
+        assert_eq!(res, null);
+    }
+
+    #[test]
+    fn test_clone() {
+        let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] = [
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+             "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key \
+               and Larger Than One Block-Size Data".to_vec(),
+             "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap()),
+        ];
+        let p = tests[0].0.len() / 2;
+        let h0 = HMAC::new(Type::MD5, &*tests[0].0);
+
+        println!("Clone a new hmac");
+        let mut h1 = h0.clone();
+        let _ = h1.write_all(&tests[0].1[..p]);
+        {
+            println!("Clone an updated hmac");
+            let mut h2 = h1.clone();
+            let _ = h2.write_all(&tests[0].1[p..]);
+            let res = h2.finish();
+            assert_eq!(res, tests[0].2);
+        }
+        let _ = h1.write_all(&tests[0].1[p..]);
+        let res = h1.finish();
+        assert_eq!(res, tests[0].2);
+
+        println!("Clone a finished hmac");
+        let mut h3 = h1.clone();
+        let _ = h3.write_all(&*tests[1].1);
+        let res = h3.finish();
+        assert_eq!(res, tests[1].2);
+    }
+
+    #[test]
+    fn test_hmac_sha1() {
+        // test vectors from RFC 2202
+        let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 7] = [
+            (repeat(0x0b_u8).take(20).collect(), b"Hi There".to_vec(),
+             "b617318655057264e28bc0b6fb378c8ef146be00".from_hex().unwrap()),
+            (b"Jefe".to_vec(),
+             b"what do ya want for nothing?".to_vec(),
+             "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(20).collect(), repeat(0xdd_u8).take(50).collect(),
+             "125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()),
+            ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
+             repeat(0xcd_u8).take(50).collect(),
+             "4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()),
+            (repeat(0x0c_u8).take(20).collect(),
+             b"Test With Truncation".to_vec(),
+             "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+             "aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key \
+               and Larger Than One Block-Size Data".to_vec(),
+             "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())
+        ];
+
+        test_hmac(SHA1, &tests);
+    }
+
+    #[test]
+    fn test_hmac_sha1_recycle() {
+        let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] = [
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
+             "aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()),
+            (repeat(0xaa_u8).take(80).collect(),
+             b"Test Using Larger Than Block-Size Key \
+               and Larger Than One Block-Size Data".to_vec(),
+             "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())
+        ];
+
+        let mut h = HMAC::new(SHA1, &*tests[0].0);
+        for i in 0..100usize {
+            let test = &tests[i % 2];
+            test_hmac_recycle(&mut h, test);
+        }
+    }
+
+
+
+    fn test_sha2(ty: Type, results: &[Vec<u8>]) {
+        // test vectors from RFC 4231
+        let tests: [(Vec<u8>, Vec<u8>); 6] = [
+            (repeat(0xb_u8).take(20).collect(), b"Hi There".to_vec()),
+            (b"Jefe".to_vec(),
+             b"what do ya want for nothing?".to_vec()),
+            (repeat(0xaa_u8).take(20).collect(), repeat(0xdd_u8).take(50).collect()),
+            ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(),
+             repeat(0xcd_u8).take(50).collect()),
+            (repeat(0xaa_u8).take(131).collect(),
+             b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec()),
+            (repeat(0xaa_u8).take(131).collect(),
+             b"This is a test using a larger than block-size key and a \
+               larger than block-size data. The key needs to be hashed \
+               before being used by the HMAC algorithm.".to_vec())
+        ];
+
+        for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) {
+            assert_eq!(hmac(ty, &**key, &**data), *res);
+        }
+
+        // recycle test
+        let mut h = HMAC::new(ty, &*tests[5].0);
+        for i in 0..100usize {
+            let test = &tests[4 + i % 2];
+            let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());
+            test_hmac_recycle(&mut h, &tup);
+        }
+    }
+
+    #[test]
+    fn test_hmac_sha224() {
+        let results = [
+            "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22".from_hex().unwrap(),
+            "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44".from_hex().unwrap(),
+            "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea".from_hex().unwrap(),
+            "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a".from_hex().unwrap(),
+            "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e".from_hex().unwrap(),
+            "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1".from_hex().unwrap()
+        ];
+        test_sha2(SHA224, &results);
+    }
+
+    #[test]
+    fn test_hmac_sha256() {
+        let results = [
+            "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7".from_hex().unwrap(),
+            "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843".from_hex().unwrap(),
+            "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe".from_hex().unwrap(),
+            "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b".from_hex().unwrap(),
+            "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54".from_hex().unwrap(),
+            "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2".from_hex().unwrap()
+        ];
+        test_sha2(SHA256, &results);
+    }
+
+    #[test]
+    fn test_hmac_sha384() {
+        let results = [
+            "afd03944d84895626b0825f4ab46907f\
+             15f9dadbe4101ec682aa034c7cebc59c\
+             faea9ea9076ede7f4af152e8b2fa9cb6".from_hex().unwrap(),
+            "af45d2e376484031617f78d2b58a6b1b\
+             9c7ef464f5a01b47e42ec3736322445e\
+             8e2240ca5e69e2c78b3239ecfab21649".from_hex().unwrap(),
+            "88062608d3e6ad8a0aa2ace014c8a86f\
+             0aa635d947ac9febe83ef4e55966144b\
+             2a5ab39dc13814b94e3ab6e101a34f27".from_hex().unwrap(),
+            "3e8a69b7783c25851933ab6290af6ca7\
+             7a9981480850009cc5577c6e1f573b4e\
+             6801dd23c4a7d679ccf8a386c674cffb".from_hex().unwrap(),
+            "4ece084485813e9088d2c63a041bc5b4\
+             4f9ef1012a2b588f3cd11f05033ac4c6\
+             0c2ef6ab4030fe8296248df163f44952".from_hex().unwrap(),
+            "6617178e941f020d351e2f254e8fd32c\
+             602420feb0b8fb9adccebb82461e99c5\
+             a678cc31e799176d3860e6110c46523e".from_hex().unwrap()
+        ];
+        test_sha2(SHA384, &results);
+    }
+
+    #[test]
+    fn test_hmac_sha512() {
+        let results = [
+            "87aa7cdea5ef619d4ff0b4241a1d6cb0\
+             2379f4e2ce4ec2787ad0b30545e17cde\
+             daa833b7d6b8a702038b274eaea3f4e4\
+             be9d914eeb61f1702e696c203a126854".from_hex().unwrap(),
+            "164b7a7bfcf819e2e395fbe73b56e0a3\
+             87bd64222e831fd610270cd7ea250554\
+             9758bf75c05a994a6d034f65f8f0e6fd\
+             caeab1a34d4a6b4b636e070a38bce737".from_hex().unwrap(),
+            "fa73b0089d56a284efb0f0756c890be9\
+             b1b5dbdd8ee81a3655f83e33b2279d39\
+             bf3e848279a722c806b485a47e67c807\
+             b946a337bee8942674278859e13292fb".from_hex().unwrap(),
+            "b0ba465637458c6990e5a8c5f61d4af7\
+             e576d97ff94b872de76f8050361ee3db\
+             a91ca5c11aa25eb4d679275cc5788063\
+             a5f19741120c4f2de2adebeb10a298dd".from_hex().unwrap(),
+            "80b24263c7c1a3ebb71493c1dd7be8b4\
+             9b46d1f41b4aeec1121b013783f8f352\
+             6b56d037e05f2598bd0fd2215d6a1e52\
+             95e64f73f63f0aec8b915a985d786598".from_hex().unwrap(),
+            "e37b6a775dc87dbaa4dfa9f96e5e3ffd\
+             debd71f8867289865df5a32d20cdc944\
+             b6022cac3c4982b10d5eeb55c3e4de15\
+             134676fb6de0446065c97440fa8c6a58".from_hex().unwrap()
+        ];
+        test_sha2(SHA512, &results);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/memcmp.rs.html b/src/openssl/crypto/memcmp.rs.html new file mode 100644 index 0000000..ecc2b6d --- /dev/null +++ b/src/openssl/crypto/memcmp.rs.html @@ -0,0 +1,175 @@ + + + + + + + + + + memcmp.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+use libc::size_t;
+use ffi;
+
+/// Returns `true` iff `a` and `b` contain the same bytes.
+///
+/// This operation takes an amount of time dependent on the length of the two
+/// arrays given, but is independent of the contents of a and b.
+///
+/// # Failure
+///
+/// This function will panic the current task if `a` and `b` do not have the same
+/// length.
+pub fn eq(a: &[u8], b: &[u8]) -> bool {
+    assert!(a.len() == b.len());
+    let ret = unsafe {
+        ffi::CRYPTO_memcmp(a.as_ptr() as *const _,
+                           b.as_ptr() as *const _,
+                           a.len() as size_t)
+    };
+    ret == 0
+}
+
+#[cfg(test)]
+mod tests {
+    use super::eq;
+
+    #[test]
+    fn test_eq() {
+        assert!(eq(&[], &[]));
+        assert!(eq(&[1], &[1]));
+        assert!(!eq(&[1, 2, 3], &[1, 2, 4]));
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_diff_lens() {
+        eq(&[], &[1]);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/mod.rs.html b/src/openssl/crypto/mod.rs.html new file mode 100644 index 0000000..47e1c77 --- /dev/null +++ b/src/openssl/crypto/mod.rs.html @@ -0,0 +1,145 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+
+/*
+ * Copyright 2011 Google Inc.
+ *           2013 Jack Lloyd
+ *
+ * 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.
+ */
+
+pub mod hash;
+pub mod hmac;
+pub mod pkcs5;
+pub mod pkey;
+pub mod rand;
+pub mod symm;
+pub mod memcmp;
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/pkcs5.rs.html b/src/openssl/crypto/pkcs5.rs.html new file mode 100644 index 0000000..5ac11c1 --- /dev/null +++ b/src/openssl/crypto/pkcs5.rs.html @@ -0,0 +1,335 @@ + + + + + + + + + + pkcs5.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+use libc::c_int;
+use ffi;
+
+/// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm.
+pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: usize, keylen: usize) -> Vec<u8> {
+    unsafe {
+        assert!(iter >= 1);
+        assert!(keylen >= 1);
+
+        let mut out = Vec::with_capacity(keylen);
+
+        ffi::init();
+
+        let r = ffi::PKCS5_PBKDF2_HMAC_SHA1(
+                pass.as_ptr(), pass.len() as c_int,
+                salt.as_ptr(), salt.len() as c_int,
+                iter as c_int, keylen as c_int,
+                out.as_mut_ptr());
+
+        if r != 1 { panic!(); }
+
+        out.set_len(keylen);
+
+        out
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // Test vectors from
+    // http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
+    #[test]
+    fn test_pbkdf2_hmac_sha1() {
+        assert_eq!(
+            super::pbkdf2_hmac_sha1(
+                "password",
+                "salt".as_bytes(),
+                1,
+                20
+            ),
+            vec!(
+                0x0c_u8, 0x60_u8, 0xc8_u8, 0x0f_u8, 0x96_u8, 0x1f_u8, 0x0e_u8,
+                0x71_u8, 0xf3_u8, 0xa9_u8, 0xb5_u8, 0x24_u8, 0xaf_u8, 0x60_u8,
+                0x12_u8, 0x06_u8, 0x2f_u8, 0xe0_u8, 0x37_u8, 0xa6_u8
+            )
+        );
+
+        assert_eq!(
+            super::pbkdf2_hmac_sha1(
+                "password",
+                "salt".as_bytes(),
+                2,
+                20
+            ),
+            vec!(
+                0xea_u8, 0x6c_u8, 0x01_u8, 0x4d_u8, 0xc7_u8, 0x2d_u8, 0x6f_u8,
+                0x8c_u8, 0xcd_u8, 0x1e_u8, 0xd9_u8, 0x2a_u8, 0xce_u8, 0x1d_u8,
+                0x41_u8, 0xf0_u8, 0xd8_u8, 0xde_u8, 0x89_u8, 0x57_u8
+            )
+        );
+
+        assert_eq!(
+            super::pbkdf2_hmac_sha1(
+                "password",
+                "salt".as_bytes(),
+                4096,
+                20
+            ),
+            vec!(
+                0x4b_u8, 0x00_u8, 0x79_u8, 0x01_u8, 0xb7_u8, 0x65_u8, 0x48_u8,
+                0x9a_u8, 0xbe_u8, 0xad_u8, 0x49_u8, 0xd9_u8, 0x26_u8, 0xf7_u8,
+                0x21_u8, 0xd0_u8, 0x65_u8, 0xa4_u8, 0x29_u8, 0xc1_u8
+            )
+        );
+
+        assert_eq!(
+            super::pbkdf2_hmac_sha1(
+                "password",
+                "salt".as_bytes(),
+                16777216,
+                20
+            ),
+            vec!(
+                0xee_u8, 0xfe_u8, 0x3d_u8, 0x61_u8, 0xcd_u8, 0x4d_u8, 0xa4_u8,
+                0xe4_u8, 0xe9_u8, 0x94_u8, 0x5b_u8, 0x3d_u8, 0x6b_u8, 0xa2_u8,
+                0x15_u8, 0x8c_u8, 0x26_u8, 0x34_u8, 0xe9_u8, 0x84_u8
+            )
+        );
+
+        assert_eq!(
+            super::pbkdf2_hmac_sha1(
+                "passwordPASSWORDpassword",
+                "saltSALTsaltSALTsaltSALTsaltSALTsalt".as_bytes(),
+                4096,
+                25
+            ),
+            vec!(
+                0x3d_u8, 0x2e_u8, 0xec_u8, 0x4f_u8, 0xe4_u8, 0x1c_u8, 0x84_u8,
+                0x9b_u8, 0x80_u8, 0xc8_u8, 0xd8_u8, 0x36_u8, 0x62_u8, 0xc0_u8,
+                0xe4_u8, 0x4a_u8, 0x8b_u8, 0x29_u8, 0x1a_u8, 0x96_u8, 0x4c_u8,
+                0xf2_u8, 0xf0_u8, 0x70_u8, 0x38_u8
+            )
+        );
+
+        assert_eq!(
+            super::pbkdf2_hmac_sha1(
+                "pass\x00word",
+                "sa\x00lt".as_bytes(),
+                4096,
+                16
+            ),
+            vec!(
+                0x56_u8, 0xfa_u8, 0x6a_u8, 0xa7_u8, 0x55_u8, 0x48_u8, 0x09_u8,
+                0x9d_u8, 0xcc_u8, 0x37_u8, 0xd7_u8, 0xf0_u8, 0x34_u8, 0x25_u8,
+                0xe0_u8, 0xc3_u8
+            )
+        );
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/pkey.rs.html b/src/openssl/crypto/pkey.rs.html new file mode 100644 index 0000000..4b93f74 --- /dev/null +++ b/src/openssl/crypto/pkey.rs.html @@ -0,0 +1,1103 @@ + + + + + + + + + + pkey.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+
+use libc::{c_int, c_uint, c_ulong};
+use std::io;
+use std::io::prelude::*;
+use std::iter::repeat;
+use std::mem;
+use std::ptr;
+use bio::{MemBio};
+use crypto::hash;
+use crypto::hash::Type as HashType;
+use ffi;
+use ssl::error::{SslError, StreamError};
+
+#[derive(Copy, Clone)]
+pub enum Parts {
+    Neither,
+    Public,
+    Both
+}
+
+/// Represents a role an asymmetric key might be appropriate for.
+#[derive(Copy, Clone)]
+pub enum Role {
+    Encrypt,
+    Decrypt,
+    Sign,
+    Verify
+}
+
+/// Type of encryption padding to use.
+#[derive(Copy, Clone)]
+pub enum EncryptionPadding {
+    OAEP,
+    PKCS1v15
+}
+
+fn openssl_padding_code(padding: EncryptionPadding) -> c_int {
+    match padding {
+        EncryptionPadding::OAEP => 4,
+        EncryptionPadding::PKCS1v15 => 1
+    }
+}
+
+fn openssl_hash_nid(hash: HashType) -> c_int {
+    match hash {
+        HashType::MD5       => 4,   // NID_md5,
+        HashType::SHA1      => 64,  // NID_sha1
+        HashType::SHA224    => 675, // NID_sha224
+        HashType::SHA256    => 672, // NID_sha256
+        HashType::SHA384    => 673, // NID_sha384
+        HashType::SHA512    => 674, // NID_sha512
+        HashType::RIPEMD160 => 117, // NID_ripemd160
+    }
+}
+
+pub struct PKey {
+    evp: *mut ffi::EVP_PKEY,
+    parts: Parts,
+}
+
+/// Represents a public key, optionally with a private key attached.
+impl PKey {
+    pub fn new() -> PKey {
+        unsafe {
+            ffi::init();
+
+            PKey {
+                evp: ffi::EVP_PKEY_new(),
+                parts: Parts::Neither,
+            }
+        }
+    }
+
+    pub fn from_handle(handle: *mut ffi::EVP_PKEY, parts: Parts) -> PKey {
+        ffi::init();
+        assert!(!handle.is_null());
+
+        PKey {
+            evp: handle,
+            parts: parts,
+        }
+    }
+
+    /// Reads private key from PEM, takes ownership of handle
+    pub fn private_key_from_pem<R>(reader: &mut R) -> Result<PKey, SslError> where R: Read {
+        let mut mem_bio = try!(MemBio::new());
+        try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+
+        unsafe {
+            let evp = try_ssl_null!(ffi::PEM_read_bio_PrivateKey(mem_bio.get_handle(),
+                                                                 ptr::null_mut(),
+                                                                 None, ptr::null_mut()));
+            Ok(PKey {
+                evp:   evp,
+                parts: Parts::Both,
+            })
+        }
+    }
+
+    fn _tostr(&self, f: unsafe extern "C" fn(*mut ffi::RSA, *const *mut u8) -> c_int) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = f(rsa, ptr::null());
+            if len < 0 as c_int { return vec!(); }
+            let mut s = repeat(0u8).take(len as usize).collect::<Vec<_>>();
+
+            let r = f(rsa, &s.as_mut_ptr());
+
+            s.truncate(r as usize);
+            s
+        }
+    }
+
+    fn _fromstr(&mut self, s: &[u8], f: unsafe extern "C" fn(*const *mut ffi::RSA, *const *const u8, c_uint) -> *mut ffi::RSA) {
+        unsafe {
+            let rsa = ptr::null_mut();
+            f(&rsa, &s.as_ptr(), s.len() as c_uint);
+            ffi::EVP_PKEY_set1_RSA(self.evp, rsa);
+        }
+    }
+
+    pub fn gen(&mut self, keysz: usize) {
+        unsafe {
+            let rsa = ffi::RSA_generate_key(
+                keysz as c_int,
+                65537 as c_ulong,
+                ptr::null(),
+                ptr::null()
+            );
+
+            // XXX: 6 == NID_rsaEncryption
+            ffi::EVP_PKEY_assign(
+                self.evp,
+                6 as c_int,
+                mem::transmute(rsa));
+
+            self.parts = Parts::Both;
+        }
+    }
+
+    /**
+     * Returns a serialized form of the public key, suitable for load_pub().
+     */
+    pub fn save_pub(&self) -> Vec<u8> {
+        self._tostr(ffi::i2d_RSA_PUBKEY)
+    }
+
+    /**
+     * Loads a serialized form of the public key, as produced by save_pub().
+     */
+    pub fn load_pub(&mut self, s: &[u8]) {
+        self._fromstr(s, ffi::d2i_RSA_PUBKEY);
+        self.parts = Parts::Public;
+    }
+
+    /**
+     * Returns a serialized form of the public and private keys, suitable for
+     * load_priv().
+     */
+    pub fn save_priv(&self) -> Vec<u8> {
+        self._tostr(ffi::i2d_RSAPrivateKey)
+    }
+    /**
+     * Loads a serialized form of the public and private keys, as produced by
+     * save_priv().
+     */
+    pub fn load_priv(&mut self, s: &[u8]) {
+        self._fromstr(s, ffi::d2i_RSAPrivateKey);
+        self.parts = Parts::Both;
+    }
+
+    /// Stores private key as a PEM
+    // FIXME: also add password and encryption
+    pub fn write_pem<W: Write>(&self, writer: &mut W/*, password: Option<String>*/) -> Result<(), SslError> {
+        let mut mem_bio = try!(MemBio::new());
+        unsafe {
+            try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(),
+                                                   ptr::null_mut(), -1, None, ptr::null_mut()));
+
+        }
+        let mut buf = vec![];
+        try!(mem_bio.read_to_end(&mut buf).map_err(StreamError));
+        writer.write_all(&buf).map_err(StreamError)
+    }
+
+    /**
+     * Returns the size of the public key modulus.
+     */
+    pub fn size(&self) -> usize {
+        unsafe {
+            ffi::RSA_size(ffi::EVP_PKEY_get1_RSA(self.evp)) as usize
+        }
+    }
+
+    /**
+     * Returns whether this pkey object can perform the specified role.
+     */
+    pub fn can(&self, r: Role) -> bool {
+        match r {
+            Role::Encrypt =>
+                match self.parts {
+                    Parts::Neither => false,
+                    _ => true,
+                },
+            Role::Verify =>
+                match self.parts {
+                    Parts::Neither => false,
+                    _ => true,
+                },
+            Role::Decrypt =>
+                match self.parts {
+                    Parts::Both => true,
+                    _ => false,
+                },
+            Role::Sign =>
+                match self.parts {
+                    Parts::Both => true,
+                    _ => false,
+                },
+        }
+    }
+
+    /**
+     * Returns the maximum amount of data that can be encrypted by an encrypt()
+     * call.
+     */
+    pub fn max_data(&self) -> usize {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+
+            // 41 comes from RSA_public_encrypt(3) for OAEP
+            len as usize - 41
+        }
+    }
+
+    pub fn encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+
+            assert!(s.len() < self.max_data());
+
+            let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
+
+            let rv = ffi::RSA_public_encrypt(
+                s.len() as c_int,
+                s.as_ptr(),
+                r.as_mut_ptr(),
+                rsa,
+                openssl_padding_code(padding));
+
+            if rv < 0 as c_int {
+                vec!()
+            } else {
+                r.truncate(rv as usize);
+                r
+            }
+        }
+    }
+
+    pub fn decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+
+            assert_eq!(s.len() as c_int, ffi::RSA_size(rsa));
+
+            let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
+
+            let rv = ffi::RSA_private_decrypt(
+                s.len() as c_int,
+                s.as_ptr(),
+                r.as_mut_ptr(),
+                rsa,
+                openssl_padding_code(padding));
+
+            if rv < 0 as c_int {
+                vec!()
+            } else {
+                r.truncate(rv as usize);
+                r
+            }
+        }
+    }
+
+    /**
+     * Encrypts data using OAEP padding, returning the encrypted data. The
+     * supplied data must not be larger than max_data().
+     */
+    pub fn encrypt(&self, s: &[u8]) -> Vec<u8> { self.encrypt_with_padding(s, EncryptionPadding::OAEP) }
+
+    /**
+     * Decrypts data, expecting OAEP padding, returning the decrypted data.
+     */
+    pub fn decrypt(&self, s: &[u8]) -> Vec<u8> { self.decrypt_with_padding(s, EncryptionPadding::OAEP) }
+
+    /**
+     * Signs data, using OpenSSL's default scheme and adding sha256 ASN.1 information to the
+     * signature.
+     * The bytes to sign must be the result of a sha256 hashing;
+     * returns the signature.
+     */
+    pub fn sign(&self, s: &[u8]) -> Vec<u8> { self.sign_with_hash(s, HashType::SHA256) }
+
+    /**
+     * Verifies a signature s (using OpenSSL's default scheme and sha256) on the SHA256 hash of a
+     * message.
+     * Returns true if the signature is valid, and false otherwise.
+     */
+    pub fn verify(&self, h: &[u8], s: &[u8]) -> bool { self.verify_with_hash(h, s, HashType::SHA256) }
+
+    /**
+     * Signs data, using OpenSSL's default scheme and add ASN.1 information for the given hash type to the
+     * signature.
+     * The bytes to sign must be the result of this type of hashing;
+     * returns the signature.
+     */
+    pub fn sign_with_hash(&self, s: &[u8], hash: hash::Type) -> Vec<u8> {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+            let len = ffi::RSA_size(rsa);
+            let mut r = repeat(0u8).take(len as usize + 1).collect::<Vec<_>>();
+
+            let mut len = 0;
+            let rv = ffi::RSA_sign(
+                openssl_hash_nid(hash),
+                s.as_ptr(),
+                s.len() as c_uint,
+                r.as_mut_ptr(),
+                &mut len,
+                rsa);
+
+            if rv < 0 as c_int {
+                vec!()
+            } else {
+                r.truncate(len as usize);
+                r
+            }
+        }
+    }
+
+    pub fn verify_with_hash(&self, h: &[u8], s: &[u8], hash: hash::Type) -> bool {
+        unsafe {
+            let rsa = ffi::EVP_PKEY_get1_RSA(self.evp);
+
+            let rv = ffi::RSA_verify(
+                openssl_hash_nid(hash),
+                h.as_ptr(),
+                h.len() as c_uint,
+                s.as_ptr(),
+                s.len() as c_uint,
+                rsa
+            );
+
+            rv == 1 as c_int
+        }
+    }
+
+    pub unsafe fn get_handle(&self) -> *mut ffi::EVP_PKEY {
+        return self.evp
+    }
+
+    pub fn public_eq(&self, other: &PKey) -> bool {
+        unsafe { ffi::EVP_PKEY_cmp(self.evp, other.evp) == 1 }
+    }
+}
+
+impl Drop for PKey {
+    fn drop(&mut self) {
+        unsafe {
+            ffi::EVP_PKEY_free(self.evp);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::path::Path;
+    use std::fs::File;
+    use crypto::hash::Type::{MD5, SHA1};
+
+    #[test]
+    fn test_gen_pub() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        assert_eq!(k0.save_pub(), k1.save_pub());
+        assert!(k0.public_eq(&k1));
+        assert_eq!(k0.size(), k1.size());
+        assert!(k0.can(super::Role::Encrypt));
+        assert!(k0.can(super::Role::Decrypt));
+        assert!(k0.can(super::Role::Verify));
+        assert!(k0.can(super::Role::Sign));
+        assert!(k1.can(super::Role::Encrypt));
+        assert!(!k1.can(super::Role::Decrypt));
+        assert!(k1.can(super::Role::Verify));
+        assert!(!k1.can(super::Role::Sign));
+    }
+
+    #[test]
+    fn test_gen_priv() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        k0.gen(512);
+        k1.load_priv(&k0.save_priv());
+        assert_eq!(k0.save_priv(), k1.save_priv());
+        assert!(k0.public_eq(&k1));
+        assert_eq!(k0.size(), k1.size());
+        assert!(k0.can(super::Role::Encrypt));
+        assert!(k0.can(super::Role::Decrypt));
+        assert!(k0.can(super::Role::Verify));
+        assert!(k0.can(super::Role::Sign));
+        assert!(k1.can(super::Role::Encrypt));
+        assert!(k1.can(super::Role::Decrypt));
+        assert!(k1.can(super::Role::Verify));
+        assert!(k1.can(super::Role::Sign));
+    }
+
+    #[test]
+    fn test_private_key_from_pem() {
+        let key_path = Path::new("test/key.pem");
+        let mut file = File::open(&key_path)
+            .ok()
+            .expect("Failed to open `test/key.pem`");
+
+        super::PKey::private_key_from_pem(&mut file).unwrap();
+    }
+
+    #[test]
+    fn test_encrypt() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        let emsg = k1.encrypt(&msg);
+        let dmsg = k0.decrypt(&emsg);
+        assert!(msg == dmsg);
+    }
+
+    #[test]
+    fn test_encrypt_pkcs() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        let emsg = k1.encrypt_with_padding(&msg, super::EncryptionPadding::PKCS1v15);
+        let dmsg = k0.decrypt_with_padding(&emsg, super::EncryptionPadding::PKCS1v15);
+        assert!(msg == dmsg);
+    }
+
+    #[test]
+    fn test_sign() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+        let sig = k0.sign(&msg);
+        let rv = k1.verify(&msg, &sig);
+        assert!(rv == true);
+    }
+
+    #[test]
+    fn test_sign_hashes() {
+        let mut k0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8);
+        k0.gen(512);
+        k1.load_pub(&k0.save_pub());
+
+        let sig = k0.sign_with_hash(&msg, MD5);
+
+        assert!(k1.verify_with_hash(&msg, &sig, MD5));
+        assert!(!k1.verify_with_hash(&msg, &sig, SHA1));
+    }
+
+    #[test]
+    fn test_eq() {
+        let mut k0 = super::PKey::new();
+        let mut p0 = super::PKey::new();
+        let mut k1 = super::PKey::new();
+        let mut p1 = super::PKey::new();
+        k0.gen(512);
+        k1.gen(512);
+        p0.load_pub(&k0.save_pub());
+        p1.load_pub(&k1.save_pub());
+
+        assert!(k0.public_eq(&k0));
+        assert!(k1.public_eq(&k1));
+        assert!(p0.public_eq(&p0));
+        assert!(p1.public_eq(&p1));
+        assert!(k0.public_eq(&p0));
+        assert!(k1.public_eq(&p1));
+
+        assert!(!k0.public_eq(&k1));
+        assert!(!p0.public_eq(&p1));
+        assert!(!k0.public_eq(&p1));
+        assert!(!p0.public_eq(&k1));
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/rand.rs.html b/src/openssl/crypto/rand.rs.html new file mode 100644 index 0000000..fd6f00a --- /dev/null +++ b/src/openssl/crypto/rand.rs.html @@ -0,0 +1,151 @@ + + + + + + + + + + rand.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+use libc::c_int;
+use ffi;
+
+pub fn rand_bytes(len: usize) -> Vec<u8> {
+    unsafe {
+        let mut out = Vec::with_capacity(len);
+
+        ffi::init();
+        let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int);
+        if r != 1 as c_int { panic!() }
+
+        out.set_len(len);
+
+        out
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::rand_bytes;
+
+    #[test]
+    fn test_rand_bytes() {
+        let bytes = rand_bytes(32);
+        println!("{:?}", bytes);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/crypto/symm.rs.html b/src/openssl/crypto/symm.rs.html new file mode 100644 index 0000000..5cbd394 --- /dev/null +++ b/src/openssl/crypto/symm.rs.html @@ -0,0 +1,721 @@ + + + + + + + + + + symm.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+
+use std::iter::repeat;
+use std::convert::AsRef;
+use libc::{c_int};
+
+use ffi;
+
+#[derive(Copy, Clone)]
+pub enum Mode {
+    Encrypt,
+    Decrypt,
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone)]
+pub enum Type {
+    AES_128_ECB,
+    AES_128_CBC,
+    /// Requires the `aes_xts` feature
+    #[cfg(feature = "aes_xts")]
+    AES_128_XTS,
+    // AES_128_CTR,
+    //AES_128_GCM,
+
+    AES_256_ECB,
+    AES_256_CBC,
+    /// Requires the `aes_xts` feature
+    #[cfg(feature = "aes_xts")]
+    AES_256_XTS,
+    // AES_256_CTR,
+    //AES_256_GCM,
+
+    RC4_128,
+}
+
+fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, u32, u32) {
+    unsafe {
+        match t {
+            Type::AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16, 16),
+            Type::AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16, 16),
+            #[cfg(feature = "aes_xts")]
+            Type::AES_128_XTS => (ffi::EVP_aes_128_xts(), 32, 16),
+            // AES_128_CTR => (EVP_aes_128_ctr(), 16, 0),
+            //AES_128_GCM => (EVP_aes_128_gcm(), 16, 16),
+
+            Type::AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32, 16),
+            Type::AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32, 16),
+            #[cfg(feature = "aes_xts")]
+            Type::AES_256_XTS => (ffi::EVP_aes_256_xts(), 64, 16),
+            // AES_256_CTR => (EVP_aes_256_ctr(), 32, 0),
+            //AES_256_GCM => (EVP_aes_256_gcm(), 32, 16),
+
+            Type::RC4_128 => (ffi::EVP_rc4(), 16, 0),
+        }
+    }
+}
+
+/// Represents a symmetric cipher context.
+pub struct Crypter {
+    evp: *const ffi::EVP_CIPHER,
+    ctx: *mut ffi::EVP_CIPHER_CTX,
+    keylen: u32,
+    blocksize: u32,
+}
+
+impl Crypter {
+    pub fn new(t: Type) -> Crypter {
+        ffi::init();
+
+        let ctx = unsafe { ffi::EVP_CIPHER_CTX_new() };
+        let (evp, keylen, blocksz) = evpc(t);
+        Crypter { evp: evp, ctx: ctx, keylen: keylen, blocksize: blocksz }
+    }
+
+    /**
+     * Enables or disables padding. If padding is disabled, total amount of
+     * data encrypted must be a multiple of block size.
+     */
+    pub fn pad(&self, padding: bool) {
+        if self.blocksize > 0 {
+            unsafe {
+                let v = if padding { 1 as c_int } else { 0 };
+                ffi::EVP_CIPHER_CTX_set_padding(self.ctx, v);
+            }
+        }
+    }
+
+    /**
+     * Initializes this crypter.
+     */
+    pub fn init<T: AsRef<[u8]>>(&self, mode: Mode, key: &[u8], iv: T) {
+        unsafe {
+            let mode = match mode {
+                Mode::Encrypt => 1 as c_int,
+                Mode::Decrypt => 0 as c_int,
+            };
+            assert_eq!(key.len(), self.keylen as usize);
+
+            ffi::EVP_CipherInit(
+                self.ctx,
+                self.evp,
+                key.as_ptr(),
+                iv.as_ref().as_ptr(),
+                mode
+            );
+        }
+    }
+
+    /**
+     * Update this crypter with more data to encrypt or decrypt. Returns
+     * encrypted or decrypted bytes.
+     */
+    pub fn update(&self, data: &[u8]) -> Vec<u8> {
+        unsafe {
+            let sum = data.len() + (self.blocksize as usize);
+            let mut res = repeat(0u8).take(sum).collect::<Vec<_>>();
+            let mut reslen = sum as c_int;
+
+            ffi::EVP_CipherUpdate(
+                self.ctx,
+                res.as_mut_ptr(),
+                &mut reslen,
+                data.as_ptr(),
+                data.len() as c_int
+            );
+
+            res.truncate(reslen as usize);
+            res
+        }
+    }
+
+    /**
+     * Finish crypting. Returns the remaining partial block of output, if any.
+     */
+    pub fn finalize(&self) -> Vec<u8> {
+        unsafe {
+            let mut res = repeat(0u8).take(self.blocksize as usize).collect::<Vec<_>>();
+            let mut reslen = self.blocksize as c_int;
+
+            ffi::EVP_CipherFinal(self.ctx,
+                                       res.as_mut_ptr(),
+                                       &mut reslen);
+
+            res.truncate(reslen as usize);
+            res
+        }
+    }
+}
+
+impl Drop for Crypter {
+    fn drop(&mut self) {
+        unsafe {
+            ffi::EVP_CIPHER_CTX_free(self.ctx);
+        }
+    }
+}
+
+/**
+ * Encrypts data, using the specified crypter type in encrypt mode with the
+ * specified key and iv; returns the resulting (encrypted) data.
+ */
+pub fn encrypt<T: AsRef<[u8]>>(t: Type, key: &[u8], iv: T, data: &[u8]) -> Vec<u8> {
+    let c = Crypter::new(t);
+    c.init(Mode::Encrypt, key, iv);
+    let mut r = c.update(data);
+    let rest = c.finalize();
+    r.extend(rest.into_iter());
+    r
+}
+
+/**
+ * Decrypts data, using the specified crypter type in decrypt mode with the
+ * specified key and iv; returns the resulting (decrypted) data.
+ */
+pub fn decrypt<T: AsRef<[u8]>>(t: Type, key: &[u8], iv: T, data: &[u8]) -> Vec<u8> {
+    let c = Crypter::new(t);
+    c.init(Mode::Decrypt, key, iv);
+    let mut r = c.update(data);
+    let rest = c.finalize();
+    r.extend(rest.into_iter());
+    r
+}
+
+#[cfg(test)]
+mod tests {
+    use serialize::hex::FromHex;
+
+    // Test vectors from FIPS-197:
+    // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+    #[test]
+    fn test_aes_256_ecb() {
+        let k0 =
+           [0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8,
+            0x08u8, 0x09u8, 0x0au8, 0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8,
+            0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8, 0x16u8, 0x17u8,
+            0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8];
+        let p0 =
+           [0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8,
+            0x88u8, 0x99u8, 0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8];
+        let c0 =
+           [0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8,
+            0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8];
+        let c = super::Crypter::new(super::Type::AES_256_ECB);
+        c.init(super::Mode::Encrypt, &k0, &[]);
+        c.pad(false);
+        let mut r0 = c.update(&p0);
+        r0.extend(c.finalize().into_iter());
+        assert!(r0 == c0);
+        c.init(super::Mode::Decrypt, &k0, &[]);
+        c.pad(false);
+        let mut p1 = c.update(&r0);
+        p1.extend(c.finalize().into_iter());
+        assert!(p1 == p0);
+    }
+
+    #[test]
+    fn test_aes_256_cbc_decrypt() {
+        let cr = super::Crypter::new(super::Type::AES_256_CBC);
+        let iv = [
+            4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8,
+            69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8,
+            0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8,
+            0_u8, 0_u8, 0_u8
+        ];
+        let data = [
+            143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8,
+            241_u8, 242_u8, 31_u8, 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8,
+            2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, 233_u8, 136_u8, 139_u8,
+            27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8
+        ];
+        let ciphered_data = [
+            0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8,
+            0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8
+            ];
+        cr.init(super::Mode::Decrypt, &data, &iv);
+        cr.pad(false);
+        let unciphered_data_1 = cr.update(&ciphered_data);
+        let unciphered_data_2 = cr.finalize();
+
+        let expected_unciphered_data = b"I love turtles.\x01";
+
+        assert!(unciphered_data_2.len() == 0);
+
+        assert_eq!(&unciphered_data_1, expected_unciphered_data);
+    }
+
+    fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) {
+        use serialize::hex::ToHex;
+
+        let cipher = super::Crypter::new(ciphertype);
+        cipher.init(super::Mode::Encrypt, &key.from_hex().unwrap(), &iv.from_hex().unwrap());
+
+        let expected = ct.from_hex().unwrap();
+        let mut computed = cipher.update(&pt.from_hex().unwrap());
+        computed.extend(cipher.finalize().into_iter());
+
+        if computed != expected {
+            println!("Computed: {}", computed.to_hex());
+            println!("Expected: {}", expected.to_hex());
+            if computed.len() != expected.len() {
+                println!("Lengths differ: {} in computed vs {} expected",
+                         computed.len(), expected.len());
+            }
+            panic!("test failure");
+        }
+    }
+
+    #[test]
+    fn test_rc4() {
+
+        let pt = "0000000000000000000000000000000000000000000000000000000000000000000000000000";
+        let ct = "A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4";
+        let key = "97CD440324DA5FD1F7955C1C13B6B466";
+        let iv = "";
+
+        cipher_test(super::Type::RC4_128, pt, ct, key, iv);
+    }
+
+    #[test]
+    #[cfg(feature = "aes_xts")]
+    fn test_aes256_xts() {
+        // Test case 174 from
+        // http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip
+        let pt = "77f4ef63d734ebd028508da66c22cdebdd52ecd6ee2ab0a50bc8ad0cfd692ca5fcd4e6dedc45df7f6503f462611dc542";
+        let ct = "ce7d905a7776ac72f240d22aafed5e4eb7566cdc7211220e970da634ce015f131a5ecb8d400bc9e84f0b81d8725dbbc7";
+        let key = "b6bfef891f83b5ff073f2231267be51eb084b791fa19a154399c0684c8b2dfcb37de77d28bbda3b4180026ad640b74243b3133e7b9fae629403f6733423dae28";
+        let iv = "db200efb7eaaa737dbdf40babb68953f";
+
+        cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv);
+    }
+
+    /*#[test]
+    fn test_aes128_ctr() {
+
+        let pt = ~"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710";
+        let ct = ~"874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE";
+        let key = ~"2B7E151628AED2A6ABF7158809CF4F3C";
+        let iv = ~"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
+
+        cipher_test(super::AES_128_CTR, pt, ct, key, iv);
+    }*/
+
+    /*#[test]
+    fn test_aes128_gcm() {
+        // Test case 3 in GCM spec
+        let pt = ~"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255";
+        let ct = ~"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4";
+        let key = ~"feffe9928665731c6d6a8f9467308308";
+        let iv = ~"cafebabefacedbaddecaf888";
+
+        cipher_test(super::AES_128_GCM, pt, ct, key, iv);
+    }*/
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/lib.rs.html b/src/openssl/lib.rs.html new file mode 100644 index 0000000..e8ad872 --- /dev/null +++ b/src/openssl/lib.rs.html @@ -0,0 +1,147 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.3")]
+
+#[macro_use]
+extern crate bitflags;
+extern crate libc;
+#[macro_use]
+extern crate lazy_static;
+extern crate openssl_sys as ffi;
+
+#[cfg(test)]
+extern crate rustc_serialize as serialize;
+
+#[cfg(test)]
+#[cfg(any(feature="dtlsv1", feature="dtlsv1_2"))]
+extern crate connected_socket;
+
+mod macros;
+
+pub mod asn1;
+pub mod bn;
+pub mod bio;
+pub mod crypto;
+pub mod ssl;
+pub mod x509;
+pub mod nid;
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/nid.rs.html b/src/openssl/nid.rs.html new file mode 100644 index 0000000..857ab9d --- /dev/null +++ b/src/openssl/nid.rs.html @@ -0,0 +1,437 @@ + + + + + + + + + + nid.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub enum Nid {
+    Undefined,
+    Rsadsi,
+    Pkcs,
+    MD2,
+    MD4,
+    MD5,
+    RC4,
+    RsaEncryption,
+    RSA_MD2,
+    RSA_MD5,
+    PBE_MD2_DES,
+    X500,
+    x509,
+    CN,
+    C,
+    L,
+    ST,
+    O,
+    OU,
+    RSA,
+    Pkcs7,
+    Pkcs7_data,
+    Pkcs7_signedData,
+    Pkcs7_envelopedData,
+    Pkcs7_signedAndEnvelopedData,
+    Pkcs7_digestData,
+    Pkcs7_encryptedData,
+    Pkcs3,
+    DhKeyAgreement,
+    DES_ECB,
+    DES_CFB,
+    DES_CBC,
+    DES_EDE,
+    DES_EDE3,
+    IDEA_CBC,
+    IDEA_ECB,
+    RC2_CBC,
+    RC2_ECB,
+    RC2_CFB,
+    RC2_OFB,
+    SHA,
+    RSA_SHA,
+    DES_EDE_CBC,
+    DES_EDE3_CBC,
+    DES_OFB,
+    IDEA_OFB,
+    Pkcs9,
+    Email,
+    UnstructuredName,
+    ContentType,
+    MessageDigest,
+    SigningTime,
+    CounterSignature,
+    UnstructuredAddress,
+    ExtendedCertificateAttributes,
+    Netscape,
+    NetscapeCertExtention,
+    NetscapeDatatype,
+    DES_EDE_CFB64,
+    DES_EDE3_CFB64,
+    DES_EDE_OFB64,
+    DES_EDE3_OFB64,
+    SHA1,
+    RSA_SHA1,
+    DSA_SHA,
+    DSA_OLD,
+    PBE_SHA1_RC2_64,
+    PBKDF2,
+    DSA_SHA1_OLD,
+    NetscapeCertType,
+    NetscapeBaseUrl,
+    NetscapeRevocationUrl,
+    NetscapeCARevocationUrl,
+    NetscapeRenewalUrl,
+    NetscapeCAPolicyUrl,
+    NetscapeSSLServerName,
+    NetscapeComment,
+    NetscapeCertSequence,
+    DESX_CBC,
+    ID_CE,
+    SubjectKeyIdentifier,
+    KeyUsage,
+    PrivateKeyUsagePeriod,
+    SubjectAltName,
+    IssuerAltName,
+    BasicConstraints,
+    CrlNumber,
+    CertificatePolicies,
+    AuthorityKeyIdentifier,
+    BF_CBC,
+    BF_ECB,
+    BF_OFB,
+    MDC2,
+    RSA_MDC2,
+    RC4_40,
+    RC2_40_CBC,
+    G,
+    S,
+    I,
+    UID,
+    CrlDistributionPoints,
+    RSA_NP_MD5,
+    SN,
+    T,
+    D,
+    CAST5_CBC,
+    CAST5_ECB,
+    CAST5_CFB,
+    CAST5_OFB,
+    PbeWithMD5AndCast5CBC,
+    DSA_SHA1,
+    MD5_SHA1,
+    RSA_SHA1_2,
+    DSA,
+    RIPEMD160,
+    RSA_RIPEMD160,
+    RC5_CBC,
+    RC5_ECB,
+    RC5_CFB,
+    RC5_OFB,
+    RLE,
+    ZLIB,
+    ExtendedKeyUsage,
+    PKIX,
+    ID_KP,
+    ServerAuth,
+    ClientAuth,
+    CodeSigning,
+    EmailProtection,
+    TimeStamping,
+    MsCodeInd,
+    MsCodeCom,
+    MsCtlSigh,
+    MsSGC,
+    MsEFS,
+    NsSGC,
+    DeltaCRL,
+    CRLReason,
+    InvalidityDate,
+    SXNetID,
+    Pkcs12,
+    PBE_SHA1_RC4_128,
+    PBE_SHA1_RC4_40,
+    PBE_SHA1_3DES,
+    PBE_SHA1_2DES,
+    PBE_SHA1_RC2_128,
+    PBE_SHA1_RC2_40,
+    KeyBag,
+    Pkcs8ShroudedKeyBag,
+    CertBag,
+    CrlBag,
+    SecretBag,
+    SafeContentsBag,
+    FriendlyName,
+    LocalKeyID,
+    X509Certificate,
+    SdsiCertificate,
+    X509Crl,
+    PBES2,
+    PBMAC1,
+    HmacWithSha1,
+    ID_QT_CPS,
+    ID_QT_UNOTICE,
+    RC2_64_CBC,
+    SMIMECaps
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/ssl/error.rs.html b/src/openssl/ssl/error.rs.html new file mode 100644 index 0000000..683c375 --- /dev/null +++ b/src/openssl/ssl/error.rs.html @@ -0,0 +1,373 @@ + + + + + + + + + + error.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+pub use self::SslError::*;
+pub use self::OpensslError::*;
+
+use libc::c_ulong;
+use std::error;
+use std::fmt;
+use std::ffi::CStr;
+use std::io;
+
+use ffi;
+
+/// An SSL error
+#[derive(Debug)]
+pub enum SslError {
+    /// The underlying stream reported an error
+    StreamError(io::Error),
+    /// The SSL session has been closed by the other end
+    SslSessionClosed,
+    /// An error in the OpenSSL library
+    OpenSslErrors(Vec<OpensslError>)
+}
+
+impl fmt::Display for SslError {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        try!(fmt.write_str(error::Error::description(self)));
+        if let OpenSslErrors(ref errs) = *self {
+            let mut first = true;
+            for err in errs {
+                if first {
+                    try!(fmt.write_str(": "));
+                    first = false;
+                } else {
+                    try!(fmt.write_str(", "));
+                }
+                match *err {
+                    UnknownError { ref reason, .. } => try!(fmt.write_str(reason)),
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl error::Error for SslError {
+    fn description(&self) -> &str {
+        match *self {
+            StreamError(_) => "The underlying stream reported an error",
+            SslSessionClosed => "The SSL session has been closed by the other end",
+            OpenSslErrors(_) => "An error in the OpenSSL library",
+        }
+    }
+
+    fn cause(&self) -> Option<&error::Error> {
+        match *self {
+            StreamError(ref err) => Some(err as &error::Error),
+            _ => None
+        }
+    }
+}
+
+/// An error from the OpenSSL library
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum OpensslError {
+    /// An unknown error
+    UnknownError {
+        /// The library reporting the error
+        library: String,
+        /// The function reporting the error
+        function: String,
+        /// The reason for the error
+        reason: String
+    }
+}
+
+fn get_lib(err: c_ulong) -> String {
+    unsafe {
+        let bytes = CStr::from_ptr(ffi::ERR_lib_error_string(err)).to_bytes().to_vec();
+        String::from_utf8(bytes).unwrap()
+    }
+}
+
+fn get_func(err: c_ulong) -> String {
+    unsafe {
+        let bytes = CStr::from_ptr(ffi::ERR_func_error_string(err)).to_bytes().to_vec();
+        String::from_utf8(bytes).unwrap()
+    }
+}
+
+fn get_reason(err: c_ulong) -> String {
+    unsafe {
+        let bytes = CStr::from_ptr(ffi::ERR_reason_error_string(err)).to_bytes().to_vec();
+        String::from_utf8(bytes).unwrap()
+    }
+}
+
+impl SslError {
+    /// Creates a new `OpenSslErrors` with the current contents of the error
+    /// stack.
+    pub fn get() -> SslError {
+        let mut errs = vec!();
+        loop {
+            match unsafe { ffi::ERR_get_error() } {
+                0 => break,
+                err => errs.push(SslError::from_error_code(err))
+            }
+        }
+        OpenSslErrors(errs)
+    }
+
+    /// Creates an `SslError` from the raw numeric error code.
+    pub fn from_error(err: c_ulong) -> SslError {
+        OpenSslErrors(vec![SslError::from_error_code(err)])
+    }
+
+    fn from_error_code(err: c_ulong) -> OpensslError {
+        ffi::init();
+        UnknownError {
+            library: get_lib(err),
+            function: get_func(err),
+            reason: get_reason(err)
+        }
+    }
+}
+
+#[test]
+fn test_uknown_error_should_have_correct_messages() {
+    let errs = match SslError::from_error(336032784) {
+        OpenSslErrors(errs) => errs,
+        _ => panic!("This should always be an `OpenSslErrors` variant.")
+    };
+
+    let UnknownError { ref library, ref function, ref reason } = errs[0];
+
+    assert_eq!(&library[..], "SSL routines");
+    assert_eq!(&function[..], "SSL23_GET_SERVER_HELLO");
+    assert_eq!(&reason[..], "sslv3 alert handshake failure");
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/ssl/mod.rs.html b/src/openssl/ssl/mod.rs.html new file mode 100644 index 0000000..40cd850 --- /dev/null +++ b/src/openssl/ssl/mod.rs.html @@ -0,0 +1,2079 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+
+use libc::{c_int, c_void, c_long};
+use std::any::TypeId;
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::mem;
+use std::net;
+use std::path::Path;
+use std::ptr;
+use std::sync::{Once, ONCE_INIT, Arc, Mutex};
+use std::ops::{Deref, DerefMut};
+use std::cmp;
+use std::any::Any;
+#[cfg(feature = "npn")]
+use libc::{c_uchar, c_uint};
+#[cfg(feature = "npn")]
+use std::slice;
+
+use bio::{MemBio};
+use ffi;
+use ssl::error::{SslError, SslSessionClosed, StreamError, OpenSslErrors};
+use x509::{X509StoreContext, X509FileType, X509};
+use crypto::pkey::PKey;
+
+pub mod error;
+#[cfg(test)]
+mod tests;
+
+static mut VERIFY_IDX: c_int = -1;
+
+fn init() {
+    static mut INIT: Once = ONCE_INIT;
+
+    unsafe {
+        INIT.call_once(|| {
+            ffi::init();
+
+            let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
+                                                           None, None);
+            assert!(verify_idx >= 0);
+            VERIFY_IDX = verify_idx;
+        });
+    }
+}
+
+bitflags! {
+    flags SslContextOptions: c_long {
+        const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004,
+        const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008,
+        const SSL_OP_TLSEXT_PADDING = 0x00000010,
+        const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020,
+        const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 0x00000040,
+        const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080,
+        const SSL_OP_TLS_D5_BUG = 0x00000100,
+        const SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200,
+        const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800,
+        const SSL_OP_ALL = 0x80000BFF,
+        const SSL_OP_NO_QUERY_MTU = 0x00001000,
+        const SSL_OP_COOKIE_EXCHANGE = 0x00002000,
+        const SSL_OP_NO_TICKET = 0x00004000,
+        const SSL_OP_CISCO_ANYCONNECT = 0x00008000,
+        const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000,
+        const SSL_OP_NO_COMPRESSION = 0x00020000,
+        const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000,
+        const SSL_OP_SINGLE_ECDH_USE = 0x00080000,
+        const SSL_OP_SINGLE_DH_USE = 0x00100000,
+        const SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000,
+        const SSL_OP_TLS_ROLLBACK_BUG = 0x00800000,
+        const SSL_OP_NO_SSLV2 = 0x00000000,
+        const SSL_OP_NO_SSLV3 = 0x02000000,
+        const SSL_OP_NO_TLSV1 = 0x04000000,
+        const SSL_OP_NO_TLSV1_2 = 0x08000000,
+        const SSL_OP_NO_TLSV1_1 = 0x10000000,
+        const SSL_OP_NO_DTLSV1 = 0x04000000,
+        const SSL_OP_NO_DTLSV1_2 = 0x08000000
+    }
+}
+
+/// Determines the SSL method supported
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum SslMethod {
+    #[cfg(feature = "sslv2")]
+    /// Only support the SSLv2 protocol, requires the `sslv2` feature.
+    Sslv2,
+    /// Support the SSLv2, SSLv3 and TLSv1 protocols.
+    Sslv23,
+    /// Only support the SSLv3 protocol.
+    Sslv3,
+    /// Only support the TLSv1 protocol.
+    Tlsv1,
+    #[cfg(feature = "tlsv1_1")]
+    /// Support TLSv1.1 protocol, requires the `tlsv1_1` feature.
+    Tlsv1_1,
+    #[cfg(feature = "tlsv1_2")]
+    /// Support TLSv1.2 protocol, requires the `tlsv1_2` feature.
+    Tlsv1_2,
+    #[cfg(feature = "dtlsv1")]
+    /// Support DTLSv1 protocol, requires the `dtlsv1` feature.
+    Dtlsv1,
+    #[cfg(feature = "dtlsv1_2")]
+    /// Support DTLSv1.2 protocol, requires the `dtlsv1_2` feature.
+    Dtlsv1_2,
+}
+
+impl SslMethod {
+    unsafe fn to_raw(&self) -> *const ffi::SSL_METHOD {
+        match *self {
+            #[cfg(feature = "sslv2")]
+            SslMethod::Sslv2 => ffi::SSLv2_method(),
+            SslMethod::Sslv3 => ffi::SSLv3_method(),
+            SslMethod::Tlsv1 => ffi::TLSv1_method(),
+            SslMethod::Sslv23 => ffi::SSLv23_method(),
+            #[cfg(feature = "tlsv1_1")]
+            SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(),
+            #[cfg(feature = "tlsv1_2")]
+            SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(),
+            #[cfg(feature = "dtlsv1")]
+            SslMethod::Dtlsv1 => ffi::DTLSv1_method(),
+            #[cfg(feature = "dtlsv1_2")]
+            SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(),
+        }
+    }
+
+    #[cfg(feature = "dtlsv1")]
+    pub fn is_dtlsv1(&self) -> bool {
+        *self == SslMethod::Dtlsv1
+    }
+
+    #[cfg(feature = "dtlsv1_2")]
+    pub fn is_dtlsv1_2(&self) -> bool {
+        *self == SslMethod::Dtlsv1_2
+    }
+
+    pub fn is_dtls(&self) -> bool {
+        self.is_dtlsv1() || self.is_dtlsv1_2()
+    }
+
+    #[cfg(not(feature = "dtlsv1"))]
+    pub fn is_dtlsv1(&self) -> bool {
+        false
+    }
+
+    #[cfg(not(feature = "dtlsv1_2"))]
+    pub fn is_dtlsv1_2(&self) -> bool {
+        false
+    }
+}
+
+/// Determines the type of certificate verification used
+bitflags! {
+    flags SslVerifyMode: i32 {
+        /// Verify that the server's certificate is trusted
+        const SSL_VERIFY_PEER = ffi::SSL_VERIFY_PEER,
+        /// Do not verify the server's certificate
+        const SSL_VERIFY_NONE = ffi::SSL_VERIFY_NONE,
+        /// Terminate handshake if client did not return a certificate.
+        /// Use together with SSL_VERIFY_PEER.
+        const SSL_VERIFY_FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+    }
+}
+
+lazy_static! {
+    static ref INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
+}
+
+// Creates a static index for user data of type T
+// Registers a destructor for the data which will be called
+// when context is freed
+fn get_verify_data_idx<T: Any + 'static>() -> c_int {
+    extern fn free_data_box<T>(_parent: *mut c_void, ptr: *mut c_void,
+                               _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int,
+                               _argl: c_long, _argp: *mut c_void) {
+        if ptr != 0 as *mut _ {
+            let _: Box<T> = unsafe { mem::transmute(ptr) };
+        }
+    }
+
+    *INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| {
+        unsafe {
+            let f: ffi::CRYPTO_EX_free = free_data_box::<T>;
+            let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f));
+            assert!(idx >= 0);
+            idx
+        }
+    })
+}
+
+/// Creates a static index for the list of NPN protocols.
+/// Registers a destructor for the data which will be called
+/// when the context is freed.
+#[cfg(feature = "npn")]
+fn get_npn_protos_idx() -> c_int {
+    static mut NPN_PROTOS_IDX: c_int = -1;
+    static mut INIT: Once = ONCE_INIT;
+
+    extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void,
+                            _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int,
+                            _argl: c_long, _argp: *mut c_void) {
+        if !ptr.is_null() {
+            let _: Box<Vec<u8>> = unsafe { mem::transmute(ptr) };
+        }
+    }
+
+    unsafe {
+        INIT.call_once(|| {
+            let f: ffi::CRYPTO_EX_free = free_data_box;
+            let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
+                                                    None, Some(f));
+            assert!(idx >= 0);
+            NPN_PROTOS_IDX = idx;
+        });
+        NPN_PROTOS_IDX
+    }
+}
+
+extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX)
+        -> c_int {
+    unsafe {
+        let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
+        let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+        let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
+        let verify: Option<VerifyCallback> = mem::transmute(verify);
+
+        let ctx = X509StoreContext::new(x509_ctx);
+
+        match verify {
+            None => preverify_ok,
+            Some(verify) => verify(preverify_ok != 0, &ctx) as c_int
+        }
+    }
+}
+
+extern fn raw_verify_with_data<T>(preverify_ok: c_int,
+                                  x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
+                                  where T: Any + 'static {
+    unsafe {
+        let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
+        let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+
+        let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
+        let verify: Option<VerifyCallbackData<T>> = mem::transmute(verify);
+
+        let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<T>());
+        let data: Box<T> = mem::transmute(data);
+
+        let ctx = X509StoreContext::new(x509_ctx);
+
+        let res = match verify {
+            None => preverify_ok,
+            Some(verify) => verify(preverify_ok != 0, &ctx, &*data) as c_int
+        };
+
+        // Since data might be required on the next verification
+        // it is time to forget about it and avoid dropping
+        // data will be freed once OpenSSL considers it is time
+        // to free all context data
+        mem::forget(data);
+        res
+    }
+}
+
+/// The function is given as the callback to `SSL_CTX_set_next_proto_select_cb`.
+///
+/// It chooses the protocol that the client wishes to use, out of the given list of protocols
+/// supported by the server. It achieves this by delegating to the `SSL_select_next_proto`
+/// function. The list of protocols supported by the client is found in the extra data of the
+/// OpenSSL context.
+#[cfg(feature = "npn")]
+extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL,
+                                   out: *mut *mut c_uchar, outlen: *mut c_uchar,
+                                   inbuf: *const c_uchar, inlen: c_uint,
+                                   _arg: *mut c_void) -> c_int {
+    unsafe {
+        // First, get the list of protocols (that the client should support) saved in the context
+        // extra data.
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+        let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx());
+        let protocols: &Vec<u8> = mem::transmute(protocols);
+        // Prepare the client list parameters to be passed to the OpenSSL function...
+        let client = protocols.as_ptr();
+        let client_len = protocols.len() as c_uint;
+        // Finally, let OpenSSL find a protocol to be used, by matching the given server and
+        // client lists.
+        ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len);
+    }
+
+    ffi::SSL_TLSEXT_ERR_OK
+}
+
+/// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`.
+///
+/// It causes the parameter `out` to point at a `*const c_uchar` instance that
+/// represents the list of protocols that the server should advertise as those
+/// that it supports.
+/// The list of supported protocols is found in the extra data of the OpenSSL
+/// context.
+#[cfg(feature = "npn")]
+extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
+                                       out: *mut *const c_uchar, outlen: *mut c_uint,
+                                       _arg: *mut c_void) -> c_int {
+    unsafe {
+        // First, get the list of (supported) protocols saved in the context extra data.
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+        let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx());
+        if protocols.is_null() {
+            *out = b"".as_ptr();
+            *outlen = 0;
+        } else {
+            // If the pointer is valid, put the pointer to the actual byte array into the
+            // output parameter `out`, as well as its length into `outlen`.
+            let protocols: &Vec<u8> = mem::transmute(protocols);
+            *out = protocols.as_ptr();
+            *outlen = protocols.len() as c_uint;
+        }
+    }
+
+    ffi::SSL_TLSEXT_ERR_OK
+}
+
+/// The signature of functions that can be used to manually verify certificates
+pub type VerifyCallback = fn(preverify_ok: bool,
+                             x509_ctx: &X509StoreContext) -> bool;
+
+/// The signature of functions that can be used to manually verify certificates
+/// when user-data should be carried for all verification process
+pub type VerifyCallbackData<T> = fn(preverify_ok: bool,
+                                    x509_ctx: &X509StoreContext,
+                                    data: &T) -> bool;
+
+// FIXME: macro may be instead of inlining?
+#[inline]
+fn wrap_ssl_result(res: c_int) -> Result<(),SslError> {
+    if res == 0 {
+        Err(SslError::get())
+    } else {
+        Ok(())
+    }
+}
+
+/// An SSL context object
+pub struct SslContext {
+    ctx: *mut ffi::SSL_CTX
+}
+
+unsafe impl Send for SslContext {}
+unsafe impl Sync for SslContext {}
+
+// TODO: add useful info here
+impl fmt::Debug for SslContext {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "SslContext")
+    }
+}
+
+impl Drop for SslContext {
+    fn drop(&mut self) {
+        unsafe { ffi::SSL_CTX_free(self.ctx) }
+    }
+}
+
+impl SslContext {
+    /// Creates a new SSL context.
+    pub fn new(method: SslMethod) -> Result<SslContext, SslError> {
+        init();
+
+        let ctx = unsafe { ffi::SSL_CTX_new(method.to_raw()) };
+        if ctx == ptr::null_mut() {
+            return Err(SslError::get());
+        }
+
+        let ctx = SslContext { ctx: ctx };
+
+        if method.is_dtls() {
+            ctx.set_read_ahead(1);
+        }
+
+        Ok(ctx)
+    }
+
+    /// Configures the certificate verification method for new connections.
+    pub fn set_verify(&mut self, mode: SslVerifyMode,
+                      verify: Option<VerifyCallback>) {
+        unsafe {
+            ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX,
+                                     mem::transmute(verify));
+            let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
+                                raw_verify;
+
+            ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+        }
+    }
+
+    /// Configures the certificate verification method for new connections also
+    /// carrying supplied data.
+    // Note: no option because there is no point to set data without providing
+    // a function handling it
+    pub fn set_verify_with_data<T>(&mut self, mode: SslVerifyMode,
+                                   verify: VerifyCallbackData<T>,
+                                   data: T)
+                                   where T: Any + 'static {
+        let data = Box::new(data);
+        unsafe {
+            ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX,
+                                     mem::transmute(Some(verify)));
+            ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<T>(),
+                                     mem::transmute(data));
+            let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
+                                raw_verify_with_data::<T>;
+
+            ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+        }
+    }
+
+    /// Sets verification depth
+    pub fn set_verify_depth(&mut self, depth: u32) {
+        unsafe {
+            ffi::SSL_CTX_set_verify_depth(self.ctx, depth as c_int);
+        }
+    }
+
+    pub fn set_read_ahead(&self, m: u32) {
+        unsafe {
+            ffi::SSL_CTX_set_read_ahead(self.ctx, m as c_long);
+        }
+    }
+
+    #[allow(non_snake_case)]
+    /// Specifies the file that contains trusted CA certificates.
+    pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(),SslError> {
+        let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr(), ptr::null())
+            })
+    }
+
+    /// Specifies the file that contains certificate
+    pub fn set_certificate_file<P: AsRef<Path>>(&mut self, file: P, file_type: X509FileType)
+                                                -> Result<(),SslError> {
+        let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_certificate_file(self.ctx, file.as_ptr(), file_type as c_int)
+            })
+    }
+
+    /// Specifies the certificate
+    pub fn set_certificate(&mut self, cert: &X509) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_certificate(self.ctx, cert.get_handle())
+            })
+    }
+
+    /// Adds a certificate to the certificate chain presented together with the
+    /// certificate specified using set_certificate()
+    pub fn add_extra_chain_cert(&mut self, cert: &X509) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_add_extra_chain_cert(self.ctx, cert.get_handle()) as c_int
+            })
+    }
+
+    /// Specifies the file that contains private key
+    pub fn set_private_key_file<P: AsRef<Path>>(&mut self, file: P,
+                                file_type: X509FileType) -> Result<(),SslError> {
+        let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_PrivateKey_file(self.ctx, file.as_ptr(), file_type as c_int)
+            })
+    }
+
+    /// Specifies the private key
+    pub fn set_private_key(&mut self, key: &PKey) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_PrivateKey(self.ctx, key.get_handle())
+            })
+    }
+
+    /// Check consistency of private key and certificate
+    pub fn check_private_key(&mut self) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_check_private_key(self.ctx)
+            })
+    }
+
+    pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                let cipher_list = CString::new(cipher_list.as_bytes()).unwrap();
+                ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr())
+            })
+    }
+
+    pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions {
+        let raw_bits = option.bits();
+        let ret = unsafe {
+            ffi::SSL_CTX_set_options(self.ctx, raw_bits)
+        };
+        SslContextOptions::from_bits(ret).unwrap()
+    }
+
+    pub fn get_options(&mut self) -> SslContextOptions {
+        let ret = unsafe {
+            ffi::SSL_CTX_get_options(self.ctx)
+        };
+        SslContextOptions::from_bits(ret).unwrap()
+    }
+
+    pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions {
+        let raw_bits = option.bits();
+        let ret = unsafe {
+            ffi::SSL_CTX_clear_options(self.ctx, raw_bits)
+        };
+        SslContextOptions::from_bits(ret).unwrap()
+    }
+
+    /// Set the protocols to be used during Next Protocol Negotiation (the protocols
+    /// supported by the application).
+    ///
+    /// This method needs the `npn` feature.
+    #[cfg(feature = "npn")]
+    pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) {
+        // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL
+        // APIs -- a list of length-prefixed strings.
+        let mut npn_protocols = Vec::new();
+        for protocol in protocols {
+            let len = protocol.len() as u8;
+            npn_protocols.push(len);
+            // If the length is greater than the max `u8`, this truncates the protocol name.
+            npn_protocols.extend(protocol[..len as usize].to_vec());
+        }
+        let protocols: Box<Vec<u8>> = Box::new(npn_protocols);
+
+        unsafe {
+            // Attach the protocol list to the OpenSSL context structure,
+            // so that we can refer to it within the callback.
+            ffi::SSL_CTX_set_ex_data(self.ctx, get_npn_protos_idx(),
+                                     mem::transmute(protocols));
+            // Now register the callback that performs the default protocol
+            // matching based on the client-supported list of protocols that
+            // has been saved.
+            ffi::SSL_CTX_set_next_proto_select_cb(self.ctx, raw_next_proto_select_cb, ptr::null_mut());
+            // Also register the callback to advertise these protocols, if a server socket is
+            // created with the context.
+            ffi::SSL_CTX_set_next_protos_advertised_cb(self.ctx, raw_next_protos_advertise_cb, ptr::null_mut());
+        }
+    }
+}
+
+#[allow(dead_code)]
+struct MemBioRef<'ssl> {
+    ssl: &'ssl Ssl,
+    bio: MemBio,
+}
+
+impl<'ssl> Deref for MemBioRef<'ssl> {
+    type Target = MemBio;
+
+    fn deref(&self) -> &MemBio {
+        &self.bio
+    }
+}
+
+impl<'ssl> DerefMut for MemBioRef<'ssl> {
+    fn deref_mut(&mut self) -> &mut MemBio {
+        &mut self.bio
+    }
+}
+
+pub struct Ssl {
+    ssl: *mut ffi::SSL
+}
+
+unsafe impl Send for Ssl {}
+unsafe impl Sync for Ssl {}
+
+// TODO: put useful information here
+impl fmt::Debug for Ssl {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "Ssl")
+    }
+}
+
+impl Drop for Ssl {
+    fn drop(&mut self) {
+        unsafe { ffi::SSL_free(self.ssl) }
+    }
+}
+
+impl Ssl {
+    pub fn new(ctx: &SslContext) -> Result<Ssl, SslError> {
+        let ssl = unsafe { ffi::SSL_new(ctx.ctx) };
+        if ssl == ptr::null_mut() {
+            return Err(SslError::get());
+        }
+        let ssl = Ssl { ssl: ssl };
+
+        let rbio = try!(MemBio::new());
+        let wbio = try!(MemBio::new());
+
+        unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) }
+        Ok(ssl)
+    }
+
+    fn get_rbio<'a>(&'a self) -> MemBioRef<'a> {
+        unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) }
+    }
+
+    fn get_wbio<'a>(&'a self) -> MemBioRef<'a> {
+        unsafe { self.wrap_bio(ffi::SSL_get_wbio(self.ssl)) }
+    }
+
+    fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> {
+        assert!(bio != ptr::null_mut());
+        MemBioRef {
+            ssl: self,
+            bio: MemBio::borrowed(bio)
+        }
+    }
+
+    fn connect(&self) -> c_int {
+        unsafe { ffi::SSL_connect(self.ssl) }
+    }
+
+    fn accept(&self) -> c_int {
+        unsafe { ffi::SSL_accept(self.ssl) }
+    }
+
+    fn read(&self, buf: &mut [u8]) -> c_int {
+        let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+        unsafe { ffi::SSL_read(self.ssl, buf.as_ptr() as *mut c_void, len) }
+    }
+
+    fn write(&self, buf: &[u8]) -> c_int {
+        let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+        unsafe { ffi::SSL_write(self.ssl, buf.as_ptr() as *const c_void, len) }
+    }
+
+    fn get_error(&self, ret: c_int) -> LibSslError {
+        let err = unsafe { ffi::SSL_get_error(self.ssl, ret) };
+        match LibSslError::from_i32(err as i32) {
+            Some(err) => err,
+            None => unreachable!()
+        }
+    }
+
+    /// Set the host name to be used with SNI (Server Name Indication).
+    pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> {
+        let ret = unsafe {
+                // This is defined as a macro:
+                //      #define SSL_set_tlsext_host_name(s,name) \
+                //          SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
+
+                let hostname = CString::new(hostname.as_bytes()).unwrap();
+                ffi::SSL_ctrl(self.ssl, ffi::SSL_CTRL_SET_TLSEXT_HOSTNAME,
+                              ffi::TLSEXT_NAMETYPE_host_name,
+                              hostname.as_ptr() as *mut c_void)
+        };
+
+        // For this case, 0 indicates failure.
+        if ret == 0 {
+            Err(SslError::get())
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn get_peer_certificate(&self) -> Option<X509> {
+        unsafe {
+            let ptr = ffi::SSL_get_peer_certificate(self.ssl);
+            if ptr.is_null() {
+                None
+            } else {
+                Some(X509::new(ptr, true))
+            }
+        }
+    }
+
+    /// Returns the protocol selected by performing Next Protocol Negotiation, if any.
+    ///
+    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
+    /// to interpret it.
+    ///
+    /// This method needs the `npn` feature.
+    #[cfg(feature = "npn")]
+    pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> {
+        unsafe {
+            let mut data: *const c_uchar = ptr::null();
+            let mut len: c_uint = 0;
+            // Get the negotiated protocol from the SSL instance.
+            // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
+            ffi::SSL_get0_next_proto_negotiated(self.ssl, &mut data, &mut len);
+
+            if data.is_null() {
+                None
+            } else {
+                Some(slice::from_raw_parts(data, len as usize))
+            }
+        }
+    }
+
+    /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any).
+    pub fn pending(&self) -> usize {
+        unsafe {
+            ffi::SSL_pending(self.ssl) as usize
+        }
+    }
+}
+
+macro_rules! make_LibSslError {
+    ($($variant:ident = $value:ident),+) => {
+        #[derive(Debug)]
+        #[repr(i32)]
+        enum LibSslError {
+            $($variant = ffi::$value),+
+        }
+
+        impl LibSslError {
+            fn from_i32(val: i32) -> Option<LibSslError> {
+                match val {
+                    $(ffi::$value => Some(LibSslError::$variant),)+
+                    _ => None
+                }
+            }
+        }
+    }
+}
+
+make_LibSslError! {
+    ErrorNone = SSL_ERROR_NONE,
+    ErrorSsl = SSL_ERROR_SSL,
+    ErrorWantRead = SSL_ERROR_WANT_READ,
+    ErrorWantWrite = SSL_ERROR_WANT_WRITE,
+    ErrorWantX509Lookup = SSL_ERROR_WANT_X509_LOOKUP,
+    ErrorSyscall = SSL_ERROR_SYSCALL,
+    ErrorZeroReturn = SSL_ERROR_ZERO_RETURN,
+    ErrorWantConnect = SSL_ERROR_WANT_CONNECT,
+    ErrorWantAccept = SSL_ERROR_WANT_ACCEPT
+}
+
+/// A stream wrapper which handles SSL encryption for an underlying stream.
+#[derive(Clone)]
+pub struct SslStream<S> {
+    stream: S,
+    ssl: Arc<Ssl>,
+    buf: Vec<u8>
+}
+
+impl SslStream<net::TcpStream> {
+    /// Create a new independently owned handle to the underlying socket.
+    pub fn try_clone(&self) -> io::Result<SslStream<net::TcpStream>> {
+        Ok(SslStream {
+            stream: try!(self.stream.try_clone()),
+            ssl: self.ssl.clone(),
+            buf: self.buf.clone(),
+        })
+    }
+}
+
+impl<S> fmt::Debug for SslStream<S> where S: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "SslStream {{ stream: {:?}, ssl: {:?} }}", self.stream, self.ssl)
+    }
+}
+
+impl<S: Read+Write> SslStream<S> {
+    fn new_base(ssl:Ssl, stream: S) -> SslStream<S> {
+        SslStream {
+            stream: stream,
+            ssl: Arc::new(ssl),
+            // Maximum TLS record size is 16k
+            // We're just using this as a buffer, so there's no reason to pay
+            // to memset it
+            buf: {
+                const CAP: usize = 16 * 1024;
+                let mut v = Vec::with_capacity(CAP);
+                unsafe { v.set_len(CAP); }
+                v
+            }
+        }
+    }
+
+    pub fn new_server_from(ssl: Ssl, stream: S) -> Result<SslStream<S>, SslError> {
+        let mut ssl = SslStream::new_base(ssl, stream);
+        ssl.in_retry_wrapper(|ssl| { ssl.accept() }).and(Ok(ssl))
+    }
+
+    /// Attempts to create a new SSL stream from a given `Ssl` instance.
+    pub fn new_from(ssl: Ssl, stream: S) -> Result<SslStream<S>, SslError> {
+        let mut ssl = SslStream::new_base(ssl, stream);
+        ssl.in_retry_wrapper(|ssl| { ssl.connect() }).and(Ok(ssl))
+    }
+
+    /// Creates a new SSL stream
+    pub fn new(ctx: &SslContext, stream: S) -> Result<SslStream<S>, SslError> {
+        let ssl = try!(Ssl::new(ctx));
+        SslStream::new_from(ssl, stream)
+    }
+
+    /// Creates a new SSL server stream
+    pub fn new_server(ctx: &SslContext, stream: S) -> Result<SslStream<S>, SslError> {
+        let ssl = try!(Ssl::new(ctx));
+        SslStream::new_server_from(ssl, stream)
+    }
+
+    #[doc(hidden)]
+    pub fn get_inner(&mut self) -> &mut S {
+        self.get_mut()
+    }
+
+    /// Returns a reference to the underlying stream.
+    pub fn get_ref(&self) -> &S {
+        &self.stream
+    }
+
+    /// Return the certificate of the peer
+    pub fn get_peer_certificate(&self) -> Option<X509> {
+        self.ssl.get_peer_certificate()
+    }
+
+    /// Returns a mutable reference to the underlying stream.
+    ///
+    /// ## Warning
+    ///
+    /// It is inadvisable to read from or write to the underlying stream as it
+    /// will most likely desynchronize the SSL session.
+    pub fn get_mut(&mut self) -> &mut S {
+        &mut self.stream
+    }
+
+    fn in_retry_wrapper<F>(&mut self, mut blk: F)
+            -> Result<c_int, SslError> where F: FnMut(&Ssl) -> c_int {
+        loop {
+            let ret = blk(&self.ssl);
+            if ret > 0 {
+                return Ok(ret);
+            }
+
+            let e = self.ssl.get_error(ret);
+            match e {
+                LibSslError::ErrorWantRead => {
+                    try_ssl_stream!(self.flush());
+                    let len = try_ssl_stream!(self.stream.read(&mut self.buf[..]));
+                    if len == 0 {
+                        self.ssl.get_rbio().set_eof(true);
+                    } else {
+                        try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len]));
+                    }
+                }
+                LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) }
+                LibSslError::ErrorZeroReturn => return Err(SslSessionClosed),
+                LibSslError::ErrorSsl => return Err(SslError::get()),
+                LibSslError::ErrorSyscall if ret == 0 => return Ok(0),
+                err => panic!("unexpected error {:?} with ret {}", err, ret),
+            }
+        }
+    }
+
+    fn write_through(&mut self) -> io::Result<()> {
+        io::copy(&mut *self.ssl.get_wbio(), &mut self.stream).map(|_| ())
+    }
+
+    /// Get the compression currently in use.  The result will be
+    /// either None, indicating no compression is in use, or a string
+    /// with the compression name.
+    pub fn get_compression(&self) -> Option<String> {
+        let ptr = unsafe { ffi::SSL_get_current_compression(self.ssl.ssl) };
+        if ptr == ptr::null() {
+            return None;
+        }
+
+        let meth = unsafe { ffi::SSL_COMP_get_name(ptr) };
+        let s = unsafe {
+            String::from_utf8(CStr::from_ptr(meth).to_bytes().to_vec()).unwrap()
+        };
+
+        Some(s)
+    }
+
+    /// Returns the protocol selected by performing Next Protocol Negotiation, if any.
+    ///
+    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
+    /// to interpret it.
+    ///
+    /// This method needs the `npn` feature.
+    #[cfg(feature = "npn")]
+    pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> {
+        self.ssl.get_selected_npn_protocol()
+    }
+
+    /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any).
+    pub fn pending(&self) -> usize {
+        self.ssl.pending()
+    }
+}
+
+impl<S: Read+Write> Read for SslStream<S> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        match self.in_retry_wrapper(|ssl| { ssl.read(buf) }) {
+            Ok(len) => Ok(len as usize),
+            Err(SslSessionClosed) => Ok(0),
+            Err(StreamError(e)) => Err(e),
+            Err(e @ OpenSslErrors(_)) => {
+                Err(io::Error::new(io::ErrorKind::Other, e))
+            }
+        }
+    }
+}
+
+impl<S: Read+Write> Write for SslStream<S> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let count = match self.in_retry_wrapper(|ssl| ssl.write(buf)) {
+            Ok(len) => len as usize,
+            Err(SslSessionClosed) => 0,
+            Err(StreamError(e)) => return Err(e),
+            Err(e @ OpenSslErrors(_)) => return Err(io::Error::new(io::ErrorKind::Other, e)),
+        };
+        try!(self.write_through());
+        Ok(count)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        try!(self.write_through());
+        self.stream.flush()
+    }
+}
+
+/// A utility type to help in cases where the use of SSL is decided at runtime.
+#[derive(Debug)]
+pub enum MaybeSslStream<S> where S: Read+Write {
+    /// A connection using SSL
+    Ssl(SslStream<S>),
+    /// A connection not using SSL
+    Normal(S),
+}
+
+impl<S> Read for MaybeSslStream<S> where S: Read+Write {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.read(buf),
+            MaybeSslStream::Normal(ref mut s) => s.read(buf),
+        }
+    }
+}
+
+impl<S> Write for MaybeSslStream<S> where S: Read+Write {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.write(buf),
+            MaybeSslStream::Normal(ref mut s) => s.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.flush(),
+            MaybeSslStream::Normal(ref mut s) => s.flush(),
+        }
+    }
+}
+
+impl<S> MaybeSslStream<S> where S: Read+Write {
+    /// Returns a reference to the underlying stream.
+    pub fn get_ref(&self) -> &S {
+        match *self {
+            MaybeSslStream::Ssl(ref s) => s.get_ref(),
+            MaybeSslStream::Normal(ref s) => s,
+        }
+    }
+
+    /// Returns a mutable reference to the underlying stream.
+    ///
+    /// ## Warning
+    ///
+    /// It is inadvisable to read from or write to the underlying stream.
+    pub fn get_mut(&mut self) -> &mut S {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.get_mut(),
+            MaybeSslStream::Normal(ref mut s) => s,
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/x509/mod.rs.html b/src/openssl/x509/mod.rs.html new file mode 100644 index 0000000..ea45241 --- /dev/null +++ b/src/openssl/x509/mod.rs.html @@ -0,0 +1,1461 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+
+use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void};
+use std::io;
+use std::io::prelude::*;
+use std::cmp::Ordering;
+use std::ffi::{CString, CStr};
+use std::iter::repeat;
+use std::mem;
+use std::ptr;
+use std::ops::Deref;
+use std::fmt;
+use std::str;
+
+use asn1::{Asn1Time};
+use bio::{MemBio};
+use crypto::hash;
+use crypto::hash::Type as HashType;
+use crypto::pkey::{PKey,Parts};
+use crypto::rand::rand_bytes;
+use ffi;
+use ssl::error::{SslError, StreamError};
+use nid;
+
+
+#[cfg(test)]
+mod tests;
+
+pub struct SslString {
+    s : &'static str
+}
+
+impl<'s> Drop for SslString {
+    fn drop(&mut self) {
+        unsafe { ffi::CRYPTO_free(self.s.as_ptr() as *mut c_void); }
+    }
+}
+
+impl Deref for SslString {
+    type Target = str;
+
+    fn deref(&self) -> &str {
+        self.s
+    }
+}
+
+impl SslString {
+    unsafe fn new(buf: *const c_char) -> SslString {
+        SslString {
+            s: str::from_utf8(CStr::from_ptr(buf).to_bytes()).unwrap()
+        }
+    }
+}
+
+impl fmt::Display for SslString {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self.s, f)
+    }
+}
+
+impl fmt::Debug for SslString {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(self.s, f)
+    }
+}
+
+#[derive(Copy, Clone)]
+#[repr(i32)]
+pub enum X509FileType {
+    PEM = ffi::X509_FILETYPE_PEM,
+    ASN1 = ffi::X509_FILETYPE_ASN1,
+    Default = ffi::X509_FILETYPE_DEFAULT
+}
+
+#[allow(missing_copy_implementations)]
+pub struct X509StoreContext {
+    ctx: *mut ffi::X509_STORE_CTX
+}
+
+impl X509StoreContext {
+    pub fn new(ctx: *mut ffi::X509_STORE_CTX) -> X509StoreContext {
+        X509StoreContext {
+            ctx: ctx
+        }
+    }
+
+    pub fn get_error(&self) -> Option<X509ValidationError> {
+        let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) };
+        X509ValidationError::from_raw(err)
+    }
+
+    pub fn get_current_cert<'a>(&'a self) -> Option<X509<'a>> {
+        let ptr = unsafe { ffi::X509_STORE_CTX_get_current_cert(self.ctx) };
+
+        if ptr.is_null() {
+            None
+        } else {
+            Some(X509 { ctx: Some(self), handle: ptr, owned: false })
+        }
+    }
+}
+
+#[doc(hidden)]
+trait AsStr<'a> {
+    fn as_str(&self) -> &'a str;
+}
+
+#[derive(Clone, Copy)]
+pub enum KeyUsage {
+    DigitalSignature,
+    NonRepudiation,
+    KeyEncipherment,
+    DataEncipherment,
+    KeyAgreement,
+    KeyCertSign,
+    CRLSign,
+    EncipherOnly,
+    DecipherOnly
+}
+
+impl AsStr<'static> for KeyUsage {
+    fn as_str(&self) -> &'static str {
+        match self {
+            &KeyUsage::DigitalSignature => "digitalSignature",
+            &KeyUsage::NonRepudiation => "nonRepudiation",
+            &KeyUsage::KeyEncipherment => "keyEncipherment",
+            &KeyUsage::DataEncipherment => "dataEncipherment",
+            &KeyUsage::KeyAgreement => "keyAgreement",
+            &KeyUsage::KeyCertSign => "keyCertSign",
+            &KeyUsage::CRLSign => "cRLSign",
+            &KeyUsage::EncipherOnly => "encipherOnly",
+            &KeyUsage::DecipherOnly => "decipherOnly"
+        }
+    }
+}
+
+
+#[derive(Clone, Copy)]
+pub enum ExtKeyUsage {
+    ServerAuth,
+    ClientAuth,
+    CodeSigning,
+    EmailProtection,
+    TimeStamping,
+    MsCodeInd,
+    MsCodeCom,
+    MsCtlSign,
+    MsSgc,
+    MsEfs,
+    NsSgc
+}
+
+impl AsStr<'static> for ExtKeyUsage {
+    fn as_str(&self) -> &'static str {
+        match self {
+            &ExtKeyUsage::ServerAuth => "serverAuth",
+            &ExtKeyUsage::ClientAuth => "clientAuth",
+            &ExtKeyUsage::CodeSigning => "codeSigning",
+            &ExtKeyUsage::EmailProtection => "emailProtection",
+            &ExtKeyUsage::TimeStamping => "timeStamping",
+            &ExtKeyUsage::MsCodeInd => "msCodeInd",
+            &ExtKeyUsage::MsCodeCom => "msCodeCom",
+            &ExtKeyUsage::MsCtlSign => "msCTLSign",
+            &ExtKeyUsage::MsSgc => "msSGC",
+            &ExtKeyUsage::MsEfs => "msEFS",
+            &ExtKeyUsage::NsSgc =>"nsSGC"
+        }
+    }
+}
+
+
+// FIXME: a dirty hack as there is no way to
+// implement ToString for Vec as both are defined
+// in another crate
+#[doc(hidden)]
+trait ToStr {
+    fn to_str(&self) -> String;
+}
+
+impl<'a, T: AsStr<'a>> ToStr for Vec<T> {
+    fn to_str(&self) -> String {
+        self.iter().enumerate().fold(String::new(), |mut acc, (idx, v)| {
+            if idx > 0 { acc.push(',') };
+            acc.push_str(v.as_str());
+            acc
+        })
+    }
+}
+
+#[allow(non_snake_case)]
+/// Generator of private key/certificate pairs
+///
+/// # Example
+///
+/// ```
+/// # #[allow(unstable)]
+/// # fn main() {
+/// use std::fs;
+/// use std::fs::File;
+/// use std::io::prelude::*;
+/// use std::path::Path;
+///
+/// use openssl::crypto::hash::Type;
+/// use openssl::x509::{KeyUsage, X509Generator};
+///
+/// let gen = X509Generator::new()
+///        .set_bitlength(2048)
+///        .set_valid_period(365*2)
+///        .set_CN("SuperMegaCorp Inc.")
+///        .set_sign_hash(Type::SHA256)
+///        .set_usage(&[KeyUsage::DigitalSignature]);
+///
+/// let (cert, pkey) = gen.generate().unwrap();
+///
+/// let cert_path = "doc_cert.pem";
+/// let mut file = File::create(cert_path).unwrap();
+/// assert!(cert.write_pem(&mut file).is_ok());
+/// # let _ = fs::remove_file(cert_path);
+///
+/// let pkey_path = "doc_key.pem";
+/// let mut file = File::create(pkey_path).unwrap();
+/// assert!(pkey.write_pem(&mut file).is_ok());
+/// # let _ = fs::remove_file(pkey_path);
+/// # }
+/// ```
+pub struct X509Generator {
+    bits: u32,
+    days: u32,
+    CN: String,
+    key_usage: Vec<KeyUsage>,
+    ext_key_usage: Vec<ExtKeyUsage>,
+    hash_type: HashType,
+}
+
+impl X509Generator {
+    /// Creates a new generator with the following defaults:
+    ///
+    /// bit length: 1024
+    ///
+    /// validity period: 365 days
+    ///
+    /// CN: "rust-openssl"
+    ///
+    /// hash: SHA1
+    pub fn new() -> X509Generator {
+        X509Generator {
+            bits: 1024,
+            days: 365,
+            CN: "rust-openssl".to_string(),
+            key_usage: Vec::new(),
+            ext_key_usage: Vec::new(),
+            hash_type: HashType::SHA1
+        }
+    }
+
+    /// Sets desired bit length
+    pub fn set_bitlength(mut self, bits: u32) -> X509Generator {
+        self.bits = bits;
+        self
+    }
+
+    /// Sets certificate validity period in days since today
+    pub fn set_valid_period(mut self, days: u32) -> X509Generator {
+        self.days = days;
+        self
+    }
+
+    #[allow(non_snake_case)]
+    /// Sets Common Name of certificate
+    pub fn set_CN(mut self, CN: &str) -> X509Generator {
+        self.CN = CN.to_string();
+        self
+    }
+
+    /// Sets what for certificate could be used
+    pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator {
+        self.key_usage = purposes.to_vec();
+        self
+    }
+
+    /// Sets allowed extended usage of certificate
+    pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator {
+        self.ext_key_usage = purposes.to_vec();
+        self
+    }
+
+    pub fn set_sign_hash(mut self, hash_type: hash::Type) -> X509Generator {
+        self.hash_type = hash_type;
+        self
+    }
+
+    fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> {
+        unsafe {
+            let mut ctx: ffi::X509V3_CTX = mem::zeroed();
+            ffi::X509V3_set_ctx(&mut ctx, x509, x509,
+                                ptr::null_mut(), ptr::null_mut(), 0);
+            let value = CString::new(value.as_bytes()).unwrap();
+            let ext = ffi::X509V3_EXT_conf_nid(ptr::null_mut(),
+                                               mem::transmute(&ctx),
+                                               extension,
+                                               value.as_ptr() as *mut c_char);
+
+            let mut success = false;
+            if ext != ptr::null_mut() {
+                success = ffi::X509_add_ext(x509, ext, -1) != 0;
+                ffi::X509_EXTENSION_free(ext);
+            }
+            lift_ssl_if!(!success)
+        }
+    }
+
+    fn add_name(name: *mut ffi::X509_NAME, key: &str, value: &str) -> Result<(), SslError> {
+        let value_len = value.len() as c_int;
+        lift_ssl!(unsafe {
+            let key = CString::new(key.as_bytes()).unwrap();
+            let value = CString::new(value.as_bytes()).unwrap();
+            ffi::X509_NAME_add_entry_by_txt(name, key.as_ptr(), ffi::MBSTRING_UTF8,
+                                            value.as_ptr(), value_len, -1, 0)
+        })
+    }
+
+    fn random_serial() -> c_long {
+        let len = mem::size_of::<c_long>();
+        let bytes = rand_bytes(len);
+        let mut res = 0;
+        for b in bytes.iter() {
+            res = res << 8;
+            res |= (*b as c_long) & 0xff;
+        }
+
+        // While OpenSSL is actually OK to have negative serials
+        // other libraries (for example, Go crypto) can drop
+        // such certificates as invalid, so we clear the high bit
+        ((res as c_ulong) >> 1) as c_long
+    }
+
+    /// Generates a private key and a self-signed certificate and returns them
+    pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), SslError> {
+        ffi::init();
+
+        let mut p_key = PKey::new();
+        p_key.gen(self.bits as usize);
+
+        let x509 = try!(self.sign(&p_key));
+        Ok((x509, p_key))
+    }
+
+    /// Sets the certificate public-key, then self-sign and return it
+    /// Note: That the bit-length of the private key is used (set_bitlength is ignored)
+    pub fn sign<'a>(&self, p_key: &PKey) -> Result<X509<'a>, SslError> {
+        ffi::init();
+
+        unsafe {
+            let x509 = ffi::X509_new();
+            try_ssl_null!(x509);
+
+            let x509 = X509 { handle: x509, ctx: None, owned: true};
+
+            try_ssl!(ffi::X509_set_version(x509.handle, 2));
+            try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.handle), X509Generator::random_serial()));
+
+            let not_before = try!(Asn1Time::days_from_now(0));
+            let not_after = try!(Asn1Time::days_from_now(self.days));
+
+            try_ssl!(ffi::X509_set_notBefore(x509.handle, mem::transmute(not_before.get_handle())));
+            // If prev line succeded - ownership should go to cert
+            mem::forget(not_before);
+
+            try_ssl!(ffi::X509_set_notAfter(x509.handle, mem::transmute(not_after.get_handle())));
+            // If prev line succeded - ownership should go to cert
+            mem::forget(not_after);
+
+            try_ssl!(ffi::X509_set_pubkey(x509.handle, p_key.get_handle()));
+
+            let name = ffi::X509_get_subject_name(x509.handle);
+            try_ssl_null!(name);
+
+            try!(X509Generator::add_name(name, "CN", &self.CN));
+            ffi::X509_set_issuer_name(x509.handle, name);
+
+            if self.key_usage.len() > 0 {
+                try!(X509Generator::add_extension(x509.handle, ffi::NID_key_usage,
+                                                  &self.key_usage.to_str()));
+            }
+
+            if self.ext_key_usage.len() > 0 {
+                try!(X509Generator::add_extension(x509.handle, ffi::NID_ext_key_usage,
+                                                  &self.ext_key_usage.to_str()));
+            }
+
+            let hash_fn = self.hash_type.evp_md();
+            try_ssl!(ffi::X509_sign(x509.handle, p_key.get_handle(), hash_fn));
+            Ok(x509)
+        }
+    }
+
+    /// Obtain a certificate signing request (CSR)
+    pub fn request(&self, p_key: &PKey) -> Result<X509Req, SslError> {
+        let cert=match self.sign(p_key) {
+            Ok(c) => c,
+            Err(x) => return Err(x)
+        };
+
+        let hash_fn = self.hash_type.evp_md();
+        let req = unsafe { ffi::X509_to_X509_REQ(cert.handle, p_key.get_handle(), hash_fn) };
+        try_ssl_null!(req);
+
+        Ok(X509Req::new(req))
+    }
+}
+
+
+#[allow(dead_code)]
+/// A public key certificate
+pub struct X509<'ctx> {
+    ctx: Option<&'ctx X509StoreContext>,
+    handle: *mut ffi::X509,
+    owned: bool
+}
+
+impl<'ctx> X509<'ctx> {
+    /// Creates new from handle with desired ownership.
+    pub fn new(handle: *mut ffi::X509, owned: bool) -> X509<'ctx> {
+        X509 {
+            ctx: None,
+            handle: handle,
+            owned: owned,
+        }
+    }
+
+    /// Creates a new certificate from context. Doesn't take ownership
+    /// of handle.
+    pub fn new_in_ctx(handle: *mut ffi::X509, ctx: &'ctx X509StoreContext) -> X509<'ctx> {
+        X509 {
+            ctx: Some(ctx),
+            handle: handle,
+            owned: false
+        }
+    }
+
+    /// Reads certificate from PEM, takes ownership of handle
+    pub fn from_pem<R>(reader: &mut R) -> Result<X509<'ctx>, SslError> where R: Read {
+        let mut mem_bio = try!(MemBio::new());
+        try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+
+        unsafe {
+            let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.get_handle(),
+                                                              ptr::null_mut(),
+                                                              None, ptr::null_mut()));
+            Ok(X509::new(handle, true))
+        }
+    }
+
+    pub fn get_handle(&self) -> *mut ffi::X509 {
+        self.handle
+    }
+
+    pub fn subject_name<'a>(&'a self) -> X509Name<'a> {
+        let name = unsafe { ffi::X509_get_subject_name(self.handle) };
+        X509Name { x509: self, name: name }
+    }
+
+    pub fn public_key(&self) -> PKey {
+        let pkey = unsafe { ffi::X509_get_pubkey(self.handle) };
+        assert!(!pkey.is_null());
+
+        PKey::from_handle(pkey, Parts::Public)
+    }
+
+    /// Returns certificate fingerprint calculated using provided hash
+    pub fn fingerprint(&self, hash_type: hash::Type) -> Option<Vec<u8>> {
+        let evp = hash_type.evp_md();
+        let len = hash_type.md_len();
+        let v: Vec<u8> = repeat(0).take(len as usize).collect();
+        let act_len: c_uint = 0;
+        let res = unsafe {
+            ffi::X509_digest(self.handle, evp, mem::transmute(v.as_ptr()),
+                             mem::transmute(&act_len))
+        };
+
+        match res {
+            0 => None,
+            _ => {
+                let act_len = act_len as usize;
+                match len.cmp(&act_len) {
+                    Ordering::Greater => None,
+                    Ordering::Equal => Some(v),
+                    Ordering::Less => panic!("Fingerprint buffer was corrupted!")
+                }
+            }
+        }
+    }
+
+    /// Writes certificate as PEM
+    pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError> where W: Write {
+        let mut mem_bio = try!(MemBio::new());
+        unsafe {
+            try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(),
+                                             self.handle));
+        }
+        io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ())
+    }
+}
+
+impl<'ctx> Drop for X509<'ctx> {
+    fn drop(&mut self) {
+        if self.owned {
+            unsafe { ffi::X509_free(self.handle) };
+        }
+    }
+}
+
+#[allow(dead_code)]
+pub struct X509Name<'x> {
+    x509: &'x X509<'x>,
+    name: *mut ffi::X509_NAME
+}
+
+#[allow(dead_code)]
+pub struct X509NameEntry<'x> {
+    x509_name: &'x X509Name<'x>,
+    ne: *mut ffi::X509_NAME_ENTRY
+}
+
+impl <'x> X509Name<'x> {
+    pub fn text_by_nid(&self, nid: nid::Nid) -> Option<SslString> {
+        unsafe {
+            let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1);
+            if loc == -1 {
+                return None;
+            }
+
+            let ne = ffi::X509_NAME_get_entry(self.name, loc);
+            if ne.is_null() {
+                return None;
+            }
+
+            let asn1_str = ffi::X509_NAME_ENTRY_get_data(ne);
+            if asn1_str.is_null() {
+                return None;
+            }
+
+            let mut str_from_asn1 : *mut c_char = ptr::null_mut();
+            let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str);
+
+            if len < 0 {
+                return None
+            }
+
+            assert!(!str_from_asn1.is_null());
+
+            Some(SslString::new(str_from_asn1))
+        }
+    }
+}
+
+/// A certificate signing request
+pub struct X509Req {
+    handle: *mut ffi::X509_REQ,
+}
+
+impl X509Req {
+    /// Creates new from handle
+    pub fn new(handle: *mut ffi::X509_REQ) -> X509Req {
+        X509Req {
+            handle: handle,
+        }
+    }
+
+    /// Reads CSR from PEM
+    pub fn from_pem<R>(reader: &mut R) -> Result<X509Req, SslError> where R: Read {
+        let mut mem_bio = try!(MemBio::new());
+        try!(io::copy(reader, &mut mem_bio).map_err(StreamError));
+
+        unsafe {
+            let handle = try_ssl_null!(ffi::PEM_read_bio_X509_REQ(mem_bio.get_handle(),
+                                                              ptr::null_mut(),
+                                                              None, ptr::null_mut()));
+            Ok(X509Req::new(handle))
+        }
+    }
+
+    /// Writes CSR as PEM
+    pub fn write_pem<W>(&self, writer: &mut W) -> Result<(), SslError> where W: Write {
+        let mut mem_bio = try!(MemBio::new());
+        unsafe {
+            try_ssl!(ffi::PEM_write_bio_X509_REQ(mem_bio.get_handle(),
+                                             self.handle));
+        }
+        io::copy(&mut mem_bio, writer).map_err(StreamError).map(|_| ())
+    }
+}
+
+impl Drop for X509Req {
+    fn drop(&mut self) {
+        unsafe { ffi::X509_REQ_free(self.handle) };
+    }
+}
+
+macro_rules! make_validation_error(
+    ($ok_val:ident, $($name:ident = $val:ident,)+) => (
+        #[derive(Copy, Clone)]
+        pub enum X509ValidationError {
+            $($name,)+
+            X509UnknownError(c_int)
+        }
+
+        impl X509ValidationError {
+            #[doc(hidden)]
+            pub fn from_raw(err: c_int) -> Option<X509ValidationError> {
+                match err {
+                    ffi::$ok_val => None,
+                    $(ffi::$val => Some(X509ValidationError::$name),)+
+                    err => Some(X509ValidationError::X509UnknownError(err))
+                }
+            }
+        }
+    )
+);
+
+make_validation_error!(X509_V_OK,
+    X509UnableToGetIssuerCert = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
+    X509UnableToGetCrl = X509_V_ERR_UNABLE_TO_GET_CRL,
+    X509UnableToDecryptCertSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
+    X509UnableToDecryptCrlSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
+    X509UnableToDecodeIssuerPublicKey = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
+    X509CertSignatureFailure = X509_V_ERR_CERT_SIGNATURE_FAILURE,
+    X509CrlSignatureFailure = X509_V_ERR_CRL_SIGNATURE_FAILURE,
+    X509CertNotYetValid = X509_V_ERR_CERT_NOT_YET_VALID,
+    X509CertHasExpired = X509_V_ERR_CERT_HAS_EXPIRED,
+    X509CrlNotYetValid = X509_V_ERR_CRL_NOT_YET_VALID,
+    X509CrlHasExpired = X509_V_ERR_CRL_HAS_EXPIRED,
+    X509ErrorInCertNotBeforeField = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
+    X509ErrorInCertNotAfterField = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
+    X509ErrorInCrlLastUpdateField = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
+    X509ErrorInCrlNextUpdateField = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
+    X509OutOfMem = X509_V_ERR_OUT_OF_MEM,
+    X509DepthZeroSelfSignedCert = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
+    X509SelfSignedCertInChain = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
+    X509UnableToGetIssuerCertLocally = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
+    X509UnableToVerifyLeafSignature = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
+    X509CertChainTooLong = X509_V_ERR_CERT_CHAIN_TOO_LONG,
+    X509CertRevoked = X509_V_ERR_CERT_REVOKED,
+    X509InvalidCA = X509_V_ERR_INVALID_CA,
+    X509PathLengthExceeded = X509_V_ERR_PATH_LENGTH_EXCEEDED,
+    X509InvalidPurpose = X509_V_ERR_INVALID_PURPOSE,
+    X509CertUntrusted = X509_V_ERR_CERT_UNTRUSTED,
+    X509CertRejected = X509_V_ERR_CERT_REJECTED,
+    X509SubjectIssuerMismatch = X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
+    X509AkidSkidMismatch = X509_V_ERR_AKID_SKID_MISMATCH,
+    X509AkidIssuerSerialMismatch = X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
+    X509KeyusageNoCertsign = X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
+    X509UnableToGetCrlIssuer = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER,
+    X509UnhandledCriticalExtension = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
+    X509KeyusageNoCrlSign = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN,
+    X509UnhandledCriticalCrlExtension = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
+    X509InvalidNonCA = X509_V_ERR_INVALID_NON_CA,
+    X509ProxyPathLengthExceeded = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED,
+    X509KeyusageNoDigitalSignature = X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE,
+    X509ProxyCertificatesNotAllowed = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED,
+    X509InvalidExtension = X509_V_ERR_INVALID_EXTENSION,
+    X509InavlidPolicyExtension = X509_V_ERR_INVALID_POLICY_EXTENSION,
+    X509NoExplicitPolicy = X509_V_ERR_NO_EXPLICIT_POLICY,
+    X509DifferentCrlScope = X509_V_ERR_DIFFERENT_CRL_SCOPE,
+    X509UnsupportedExtensionFeature = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE,
+    X509UnnestedResource = X509_V_ERR_UNNESTED_RESOURCE,
+    X509PermittedVolation = X509_V_ERR_PERMITTED_VIOLATION,
+    X509ExcludedViolation = X509_V_ERR_EXCLUDED_VIOLATION,
+    X509SubtreeMinmax = X509_V_ERR_SUBTREE_MINMAX,
+    X509UnsupportedConstraintType = X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE,
+    X509UnsupportedConstraintSyntax = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX,
+    X509UnsupportedNameSyntax = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
+    X509CrlPathValidationError= X509_V_ERR_CRL_PATH_VALIDATION_ERROR,
+    X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION,
+);
+
+
+#[test]
+fn test_negative_serial() {
+    // I guess that's enough to get a random negative number
+    for _ in 0..1000 {
+        assert!(X509Generator::random_serial() > 0, "All serials should be positive");
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl_sys/lib.rs.html b/src/openssl_sys/lib.rs.html new file mode 100644 index 0000000..bd0937b --- /dev/null +++ b/src/openssl_sys/lib.rs.html @@ -0,0 +1,1327 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+
+#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
+#![allow(dead_code)]
+#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.3")]
+
+extern crate libc;
+
+#[cfg(target_os = "nacl")]
+extern crate libressl_pnacl_sys;
+
+use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t};
+use std::mem;
+use std::ptr;
+use std::sync::{Mutex, MutexGuard};
+use std::sync::{Once, ONCE_INIT};
+
+pub type ASN1_INTEGER = c_void;
+pub type ASN1_STRING = c_void;
+pub type ASN1_TIME = c_void;
+pub type BIO = c_void;
+pub type BIO_METHOD = c_void;
+pub type BN_CTX = c_void;
+pub type COMP_METHOD = c_void;
+pub type CRYPTO_EX_DATA = c_void;
+pub type ENGINE = c_void;
+pub type EVP_CIPHER = c_void;
+pub type EVP_CIPHER_CTX = c_void;
+pub type EVP_MD = c_void;
+pub type EVP_PKEY = c_void;
+pub type EVP_PKEY_CTX = c_void;
+pub type RSA = c_void;
+pub type SSL = c_void;
+pub type SSL_CTX = c_void;
+pub type SSL_METHOD = c_void;
+pub type X509 = c_void;
+pub type X509_CRL = c_void;
+pub type X509_EXTENSION = c_void;
+pub type X509_NAME = c_void;
+pub type X509_NAME_ENTRY = c_void;
+pub type X509_REQ = c_void;
+pub type X509_STORE_CTX = c_void;
+
+#[repr(C)]
+pub struct EVP_MD_CTX {
+    digest: *mut EVP_MD,
+    engine: *mut c_void,
+    flags: c_ulong,
+    md_data: *mut c_void,
+    pctx: *mut EVP_PKEY_CTX,
+    update: *mut c_void
+}
+
+impl Copy for EVP_MD_CTX {}
+impl Clone for EVP_MD_CTX {
+    fn clone(&self) -> EVP_MD_CTX { *self }
+}
+
+#[repr(C)]
+pub struct HMAC_CTX {
+    md: *mut EVP_MD,
+    md_ctx: EVP_MD_CTX,
+    i_ctx: EVP_MD_CTX,
+    o_ctx: EVP_MD_CTX,
+    key_length: c_uint,
+    key: [c_uchar; 128]
+}
+
+impl Copy for HMAC_CTX {}
+impl Clone for HMAC_CTX {
+    fn clone(&self) -> HMAC_CTX { *self }
+}
+
+#[repr(C)]
+pub struct X509V3_CTX {
+    flags: c_int,
+    issuer_cert: *mut c_void,
+    subject_cert: *mut c_void,
+    subject_req: *mut c_void,
+    crl: *mut c_void,
+    db_meth: *mut c_void,
+    db: *mut c_void,
+    // I like the last comment line, it is copied from OpenSSL sources:
+    // Maybe more here
+}
+
+impl Copy for X509V3_CTX {}
+impl Clone for X509V3_CTX {
+    fn clone(&self) -> X509V3_CTX { *self }
+}
+
+#[repr(C)]
+pub struct BIGNUM {
+    pub d: *mut c_void,
+    pub top: c_int,
+    pub dmax: c_int,
+    pub neg: c_int,
+    pub flags: c_int,
+}
+
+impl Copy for BIGNUM {}
+impl Clone for BIGNUM {
+    fn clone(&self) -> BIGNUM { *self }
+}
+
+pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void,
+                                       ad: *const CRYPTO_EX_DATA, idx: c_int,
+                                       argl: c_long, argp: *const c_void) -> c_int;
+pub type CRYPTO_EX_dup = extern "C" fn(to: *mut CRYPTO_EX_DATA,
+                                       from: *mut CRYPTO_EX_DATA, from_d: *mut c_void,
+                                       idx: c_int, argl: c_long, argp: *mut c_void)
+                                       -> c_int;
+pub type CRYPTO_EX_free = extern "C" fn(parent: *mut c_void, ptr: *mut c_void,
+                                        ad: *mut CRYPTO_EX_DATA, idx: c_int,
+                                        argl: c_long, argp: *mut c_void);
+pub type PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int,
+                                          rwflag: c_int, user_data: *mut c_void)
+                                          -> c_int;
+
+pub const BIO_CTRL_EOF: c_int = 2;
+pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130;
+
+pub const CRYPTO_LOCK: c_int = 1;
+
+pub const MBSTRING_ASC:  c_int = MBSTRING_FLAG | 1;
+pub const MBSTRING_BMP:  c_int = MBSTRING_FLAG | 2;
+pub const MBSTRING_FLAG: c_int = 0x1000;
+pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4;
+pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG;
+
+pub const NID_ext_key_usage: c_int = 126;
+pub const NID_key_usage:     c_int = 83;
+
+pub const SSL_CTRL_OPTIONS: c_int = 32;
+pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
+
+pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55;
+pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14;
+
+pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41;
+pub const SSL_ERROR_NONE: c_int = 0;
+pub const SSL_ERROR_SSL: c_int = 1;
+pub const SSL_ERROR_SYSCALL: c_int = 5;
+pub const SSL_ERROR_WANT_ACCEPT: c_int = 8;
+pub const SSL_ERROR_WANT_CONNECT: c_int = 7;
+pub const SSL_ERROR_WANT_READ: c_int = 2;
+pub const SSL_ERROR_WANT_WRITE: c_int = 3;
+pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4;
+pub const SSL_ERROR_ZERO_RETURN: c_int = 6;
+pub const SSL_VERIFY_NONE: c_int = 0;
+pub const SSL_VERIFY_PEER: c_int = 1;
+pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2;
+
+pub const TLSEXT_NAMETYPE_host_name: c_long = 0;
+
+pub const SSL_TLSEXT_ERR_OK: c_int = 0;
+pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1;
+pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2;
+pub const SSL_TLSEXT_ERR_NOACK: c_int = 3;
+
+#[cfg(feature = "npn")]
+pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0;
+#[cfg(feature = "npn")]
+pub const OPENSSL_NPN_NEGOTIATED: c_int = 1;
+#[cfg(feature = "npn")]
+pub const OPENSSL_NPN_NO_OVERLAP: c_int = 2;
+
+pub const V_ASN1_GENERALIZEDTIME: c_int = 24;
+pub const V_ASN1_UTCTIME:         c_int = 23;
+
+pub const X509_FILETYPE_ASN1: c_int = 2;
+pub const X509_FILETYPE_DEFAULT: c_int = 3;
+pub const X509_FILETYPE_PEM: c_int = 1;
+pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31;
+pub const X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30;
+pub const X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50;
+pub const X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22;
+pub const X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10;
+pub const X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9;
+pub const X509_V_ERR_CERT_REJECTED: c_int = 28;
+pub const X509_V_ERR_CERT_REVOKED: c_int = 23;
+pub const X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7;
+pub const X509_V_ERR_CERT_UNTRUSTED: c_int = 27;
+pub const X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12;
+pub const X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11;
+pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54;
+pub const X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8;
+pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18;
+pub const X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44;
+pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14;
+pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13;
+pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15;
+pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16;
+pub const X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48;
+pub const X509_V_ERR_INVALID_CA: c_int = 24;
+pub const X509_V_ERR_INVALID_EXTENSION: c_int = 41;
+pub const X509_V_ERR_INVALID_NON_CA: c_int = 37;
+pub const X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42;
+pub const X509_V_ERR_INVALID_PURPOSE: c_int = 26;
+pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32;
+pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35;
+pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39;
+pub const X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43;
+pub const X509_V_ERR_OUT_OF_MEM: c_int = 17;
+pub const X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25;
+pub const X509_V_ERR_PERMITTED_VIOLATION: c_int = 47;
+pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40;
+pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38;
+pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19;
+pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29;
+pub const X509_V_ERR_SUBTREE_MINMAX: c_int = 49;
+pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6;
+pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4;
+pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5;
+pub const X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3;
+pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33;
+pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2;
+pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20;
+pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21;
+pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36;
+pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34;
+pub const X509_V_ERR_UNNESTED_RESOURCE: c_int = 46;
+pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52;
+pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51;
+pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45;
+pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53;
+pub const X509_V_OK: c_int = 0;
+
+static mut MUTEXES: *mut Vec<Mutex<()>> = 0 as *mut Vec<Mutex<()>>;
+static mut GUARDS: *mut Vec<Option<MutexGuard<'static, ()>>> = 0 as *mut Vec<Option<MutexGuard<'static, ()>>>;
+
+extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char,
+                               _line: c_int) {
+    unsafe {
+        let mutex = &(*MUTEXES)[n as usize];
+
+        if mode & CRYPTO_LOCK != 0 {
+            (*GUARDS)[n as usize] = Some(mutex.lock().unwrap());
+        } else {
+            &(*GUARDS)[n as usize].take();
+        }
+    }
+}
+
+pub fn init() {
+    static mut INIT: Once = ONCE_INIT;
+
+    unsafe {
+        INIT.call_once(|| {
+            SSL_library_init();
+            SSL_load_error_strings();
+
+            let num_locks = CRYPTO_num_locks();
+            let mut mutexes = Box::new(Vec::new());
+            for _ in 0..num_locks {
+                mutexes.push(Mutex::new(()));
+            }
+            MUTEXES = mem::transmute(mutexes);
+            let guards: Box<Vec<Option<MutexGuard<()>>>> =
+                Box::new((0..num_locks).map(|_| None).collect());
+            GUARDS = mem::transmute(guards);
+
+            CRYPTO_set_locking_callback(locking_function);
+        })
+    }
+}
+
+// Functions converted from macros
+pub unsafe fn BIO_eof(b: *mut BIO) -> bool {
+    BIO_ctrl(b, BIO_CTRL_EOF, 0, ptr::null_mut()) == 1
+}
+
+pub unsafe fn SSL_CTX_set_options(ssl: *mut SSL_CTX, op: c_long) -> c_long {
+    SSL_CTX_ctrl(ssl, SSL_CTRL_OPTIONS, op, ptr::null_mut())
+}
+
+pub unsafe fn BIO_set_mem_eof_return(b: *mut BIO, v: c_int) {
+    BIO_ctrl(b, BIO_C_SET_BUF_MEM_EOF_RETURN, v as c_long, ptr::null_mut());
+}
+
+pub unsafe fn SSL_CTX_get_options(ssl: *mut SSL_CTX) -> c_long {
+    SSL_CTX_ctrl(ssl, SSL_CTRL_OPTIONS, 0, ptr::null_mut())
+}
+
+pub unsafe fn SSL_CTX_clear_options(ssl: *mut SSL_CTX, op: c_long) -> c_long {
+    SSL_CTX_ctrl(ssl, SSL_CTRL_CLEAR_OPTIONS, (op), ptr::null_mut())
+}
+
+pub unsafe fn SSL_CTX_add_extra_chain_cert(ssl: *mut SSL_CTX, cert: *mut X509) -> c_long {
+    SSL_CTX_ctrl(ssl, SSL_CTRL_EXTRA_CHAIN_CERT, 0, cert)
+}
+
+pub unsafe fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long {
+    SSL_CTX_ctrl(ctx, SSL_CTRL_SET_READ_AHEAD, m, ptr::null_mut())
+}
+
+// True functions
+extern "C" {
+    pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int;
+    pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;
+    pub fn ASN1_TIME_free(tm: *mut ASN1_TIME);
+
+    pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long;
+    pub fn BIO_free_all(b: *mut BIO);
+    pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO;
+    pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int;
+    pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int;
+    pub fn BIO_s_mem() -> *const BIO_METHOD;
+
+    pub fn BN_new() -> *mut BIGNUM;
+    pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM;
+    pub fn BN_clear_free(bn: *mut BIGNUM);
+
+    pub fn BN_CTX_new() -> *mut BN_CTX;
+    pub fn BN_CTX_free(ctx: *mut BN_CTX);
+
+    pub fn BN_num_bits(bn: *mut BIGNUM) -> c_int;
+    pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int);
+    pub fn BN_set_word(bn: *mut BIGNUM, n: c_ulong) -> c_int;
+
+    /* Arithmetic operations on BIGNUMs */
+    pub fn BN_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int;
+    pub fn BN_div(dv: *mut BIGNUM, rem: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_gcd(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_mod_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_mod_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_mod_inverse(r: *mut BIGNUM, a: *mut BIGNUM, n: *mut BIGNUM, ctx: *mut BN_CTX) -> *const BIGNUM;
+    pub fn BN_mod_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_mod_sqr(r: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_mod_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_nnmod(rem: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_add_word(r: *mut BIGNUM, w: c_ulong) -> c_int;
+    pub fn BN_sub_word(r: *mut BIGNUM, w: c_ulong) -> c_int;
+    pub fn BN_mul_word(r: *mut BIGNUM, w: c_ulong) -> c_int;
+    pub fn BN_div_word(r: *mut BIGNUM, w: c_ulong) -> c_ulong;
+    pub fn BN_mod_word(r: *const BIGNUM, w: c_ulong) -> c_ulong;
+    pub fn BN_sqr(r: *mut BIGNUM, a: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int;
+    pub fn BN_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int;
+
+    /* Bit operations on BIGNUMs */
+    pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int;
+    pub fn BN_is_bit_set(a: *mut BIGNUM, n: c_int) -> c_int;
+    pub fn BN_lshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int;
+    pub fn BN_lshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int;
+    pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int;
+    pub fn BN_rshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int;
+    pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int;
+    pub fn BN_rshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int;
+
+    /* Comparisons on BIGNUMs */
+    pub fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int;
+    pub fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int;
+
+    /* Prime handling */
+    pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int;
+    pub fn BN_is_prime_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *const c_void) -> c_int;
+    pub fn BN_is_prime_fasttest_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, do_trial_division: c_int, cb: *const c_void) -> c_int;
+
+    /* Random number handling */
+    pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int;
+    pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int;
+    pub fn BN_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int;
+    pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int;
+
+    /* Conversion from/to binary representation */
+    pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM;
+    pub fn BN_bn2bin(a: *mut BIGNUM, to: *mut u8) -> c_int;
+
+    /* Conversion from/to decimal string representation */
+    pub fn BN_dec2bn(a: *const *mut BIGNUM, s: *const c_char) -> c_int;
+    pub fn BN_bn2dec(a: *mut BIGNUM) -> *const c_char;
+
+    /* Conversion from/to hexidecimal string representation */
+    pub fn BN_hex2bn(a: *const *mut BIGNUM, s: *const c_char) -> c_int;
+    pub fn BN_bn2hex(a: *mut BIGNUM) -> *const c_char;
+
+    pub fn CRYPTO_num_locks() -> c_int;
+    pub fn CRYPTO_set_locking_callback(func: extern "C" fn(mode: c_int,
+                                                           n: c_int,
+                                                           file: *const c_char,
+                                                           line: c_int));
+    pub fn CRYPTO_free(buf: *mut c_void);
+    pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void,
+                         len: size_t) -> c_int;
+
+    pub fn ERR_get_error() -> c_ulong;
+
+    pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char;
+    pub fn ERR_func_error_string(err: c_ulong) -> *const c_char;
+    pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char;
+
+    pub fn ERR_load_crypto_strings();
+
+    pub fn EVP_md5() -> *const EVP_MD;
+    pub fn EVP_ripemd160() -> *const EVP_MD;
+    pub fn EVP_sha1() -> *const EVP_MD;
+    pub fn EVP_sha224() -> *const EVP_MD;
+    pub fn EVP_sha256() -> *const EVP_MD;
+    pub fn EVP_sha384() -> *const EVP_MD;
+    pub fn EVP_sha512() -> *const EVP_MD;
+
+    pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER;
+    pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER;
+    #[cfg(feature = "aes_xts")]
+    pub fn EVP_aes_128_xts() -> *const EVP_CIPHER;
+    // fn EVP_aes_128_ctr() -> EVP_CIPHER;
+    // fn EVP_aes_128_gcm() -> EVP_CIPHER;
+    pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER;
+    pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER;
+    #[cfg(feature = "aes_xts")]
+    pub fn EVP_aes_256_xts() -> *const EVP_CIPHER;
+    // fn EVP_aes_256_ctr() -> EVP_CIPHER;
+    // fn EVP_aes_256_gcm() -> EVP_CIPHER;
+    pub fn EVP_rc4() -> *const EVP_CIPHER;
+
+    pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX;
+    pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int;
+    pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
+
+    pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER,
+                          key: *const u8, iv: *const u8, mode: c_int) -> c_int;
+    pub fn EVP_CipherUpdate(ctx: *mut EVP_CIPHER_CTX, outbuf: *mut u8,
+                            outlen: &mut c_int, inbuf: *const u8, inlen: c_int) -> c_int;
+    pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int) -> c_int;
+
+    pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int;
+    pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *const ENGINE) -> c_int;
+    pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const u8, n: c_uint) -> c_int;
+    pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int;
+    pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int;
+
+    pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX;
+    pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int;
+    pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX);
+
+    pub fn EVP_PKEY_new() -> *mut EVP_PKEY;
+    pub fn EVP_PKEY_free(k: *mut EVP_PKEY);
+    pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *const c_void) -> c_int;
+    pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA;
+    pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int;
+    pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int;
+
+    pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX);
+    pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX);
+    pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *const HMAC_CTX) -> c_int;
+
+    // Pre-1.0 versions of these didn't return anything, so the shims bridge that gap
+    #[cfg_attr(target_os = "nacl", link_name = "HMAC_Init_ex")]
+    pub fn HMAC_Init_ex_shim(ctx: *mut HMAC_CTX, key: *const u8, keylen: c_int, md: *const EVP_MD, imple: *const ENGINE) -> c_int;
+    #[cfg_attr(target_os = "nacl", link_name = "HMAC_Final")]
+    pub fn HMAC_Final_shim(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint) -> c_int;
+    #[cfg_attr(target_os = "nacl", link_name = "HMAC_Update")]
+    pub fn HMAC_Update_shim(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint) -> c_int;
+
+
+    pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>,
+                             user_data: *mut c_void) -> *mut X509;
+    pub fn PEM_read_bio_X509_REQ(bio: *mut BIO, out: *mut *mut X509_REQ, callback: Option<PasswordCallback>,
+                             user_data: *mut c_void) -> *mut X509_REQ;
+    pub fn PEM_read_bio_PrivateKey(bio: *mut BIO, out: *mut *mut EVP_PKEY, callback: Option<PasswordCallback>,
+                             user_data: *mut c_void) -> *mut X509;
+
+    pub fn PEM_write_bio_PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER,
+                                    kstr: *mut c_char, klen: c_int,
+                                    callback: Option<PasswordCallback>,
+                                    user_data: *mut c_void) -> c_int;
+    pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int;
+    pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int;
+
+    pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const u8, passlen: c_int,
+                                  salt: *const u8, saltlen: c_int,
+                                  iter: c_int, keylen: c_int,
+                                  out: *mut u8) -> c_int;
+
+
+    pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int;
+
+    pub fn RSA_generate_key(modsz: c_int, e: c_ulong, cb: *const c_void, cbarg: *const c_void) -> *mut RSA;
+    pub fn RSA_private_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA,
+                               pad: c_int) -> c_int;
+    pub fn RSA_public_encrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA,
+                              pad: c_int) -> c_int;
+    pub fn RSA_sign(t: c_int, m: *const u8, mlen: c_uint, sig: *mut u8, siglen: *mut c_uint,
+                    k: *mut RSA) -> c_int;
+    pub fn RSA_size(k: *mut RSA) -> c_int;
+    pub fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint,
+                      k: *mut RSA) -> c_int;
+
+    pub fn SSL_library_init() -> c_int;
+
+    pub fn SSL_load_error_strings();
+
+    #[cfg(feature = "sslv2")]
+    pub fn SSLv2_method() -> *const SSL_METHOD;
+    pub fn SSLv3_method() -> *const SSL_METHOD;
+    pub fn TLSv1_method() -> *const SSL_METHOD;
+    #[cfg(feature = "tlsv1_1")]
+    pub fn TLSv1_1_method() -> *const SSL_METHOD;
+    #[cfg(feature = "tlsv1_2")]
+    pub fn TLSv1_2_method() -> *const SSL_METHOD;
+    #[cfg(feature = "dtlsv1")]
+    pub fn DTLSv1_method() -> *const SSL_METHOD;
+    #[cfg(feature = "dtlsv1_2")]
+    pub fn DTLSv1_2_method() -> *const SSL_METHOD;
+    pub fn SSLv23_method() -> *const SSL_METHOD;
+
+    pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL;
+    pub fn SSL_pending(ssl: *const SSL) -> c_int;
+    pub fn SSL_free(ssl: *mut SSL);
+    pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO);
+    pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut BIO;
+    pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO;
+    pub fn SSL_accept(ssl: *mut SSL) -> c_int;
+    pub fn SSL_connect(ssl: *mut SSL) -> c_int;
+    pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long,
+                    parg: *mut c_void) -> c_long;
+    pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int;
+    pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int;
+    pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int;
+    pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int;
+    pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX;
+    pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD;
+    pub fn SSL_get_peer_certificate(ssl: *mut SSL) -> *mut X509;
+
+    pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
+
+    pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX;
+    pub fn SSL_CTX_free(ctx: *mut SSL_CTX);
+    pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int,
+                              verify_callback: Option<extern fn(c_int, *mut X509_STORE_CTX) -> c_int>);
+    pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int);
+    pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char,
+                                         CApath: *const c_char) -> c_int;
+    pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void,
+                                    new_func: Option<CRYPTO_EX_new>,
+                                    dup_func: Option<CRYPTO_EX_dup>,
+                                    free_func: Option<CRYPTO_EX_free>)
+                                    -> c_int;
+    pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void)
+                               -> c_int;
+    pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void;
+
+    pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int;
+    pub fn SSL_CTX_use_certificate(ctx: *mut SSL_CTX, cert: *mut X509) -> c_int;
+
+    pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int;
+    pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int;
+    pub fn SSL_CTX_check_private_key(ctx: *mut SSL_CTX) -> c_int;
+
+    pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int;
+
+    pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long;
+    #[cfg(feature = "npn")]
+    pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX,
+                                                 cb: extern "C" fn(ssl: *mut SSL,
+                                                                   out: *mut *const c_uchar,
+                                                                   outlen: *mut c_uint,
+                                                                   arg: *mut c_void) -> c_int,
+                                                 arg: *mut c_void);
+    #[cfg(feature = "npn")]
+    pub fn SSL_CTX_set_next_proto_select_cb(ssl: *mut SSL_CTX,
+                                            cb: extern "C" fn(ssl: *mut SSL,
+                                                              out: *mut *mut c_uchar,
+                                                              outlen: *mut c_uchar,
+                                                              inbuf: *const c_uchar,
+                                                              inlen: c_uint,
+                                                              arg: *mut c_void) -> c_int,
+                                            arg: *mut c_void);
+    #[cfg(feature = "npn")]
+    pub fn SSL_select_next_proto(out: *mut *mut c_uchar, outlen: *mut c_uchar,
+                                 inbuf: *const c_uchar, inlen: c_uint,
+                                 client: *const c_uchar, client_len: c_uint) -> c_int;
+    #[cfg(feature = "npn")]
+    pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint);
+
+    pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int;
+    pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int;
+    pub fn X509_free(x: *mut X509);
+    pub fn X509_REQ_free(x: *mut X509_REQ);
+    pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER;
+    pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME;
+    pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME;
+    pub fn X509_new() -> *mut X509;
+    pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int;
+    pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int;
+    pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int;
+    pub fn X509_set_version(x: *mut X509, version: c_ulong) -> c_int;
+    pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int;
+    pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int;
+    pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY;
+    pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ;
+
+    pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION);
+
+    pub fn X509_NAME_add_entry_by_txt(x: *mut X509, field: *const c_char, ty: c_int, bytes: *const c_char, len: c_int, loc: c_int, set: c_int) -> c_int;
+    pub fn X509_NAME_get_index_by_NID(n: *mut X509_NAME, nid: c_int, last_pos: c_int) ->c_int;
+    pub fn X509_NAME_get_entry(n: *mut X509_NAME, loc: c_int) -> *mut X509_NAME_ENTRY;
+    pub fn X509_NAME_ENTRY_get_data(ne: *mut X509_NAME_ENTRY) -> *mut ASN1_STRING;
+
+    pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_char, s: *mut ASN1_STRING) -> c_int;
+
+    pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509;
+    pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int;
+    pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void;
+
+    pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION;
+    pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int);
+
+    pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int;
+    pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA;
+    pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int;
+    pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA;
+}
+
+pub mod probe;
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl_sys/probe.rs.html b/src/openssl_sys/probe.rs.html new file mode 100644 index 0000000..402d897 --- /dev/null +++ b/src/openssl_sys/probe.rs.html @@ -0,0 +1,243 @@ + + + + + + + + + + probe.rs.html -- source + + + + + + + + + + + + + + + +
 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
+
+use std::env;
+use std::fs;
+use std::path::PathBuf;
+
+pub struct ProbeResult {
+    pub cert_file: Option<PathBuf>,
+    pub cert_dir: Option<PathBuf>,
+}
+
+/// Probe the system for the directory in which CA certificates should likely be
+/// found.
+///
+/// This will only search known system locations.
+pub fn find_certs_dirs() -> Vec<PathBuf> {
+    // see http://gagravarr.org/writing/openssl-certs/others.shtml
+    [
+        "/var/ssl",
+        "/usr/share/ssl",
+        "/usr/local/ssl",
+        "/usr/local/openssl",
+        "/usr/local/share",
+        "/usr/lib/ssl",
+        "/usr/ssl",
+        "/etc/openssl",
+        "/etc/pki/tls",
+        "/etc/ssl",
+    ].iter().map(|s| PathBuf::from(*s)).filter(|p| {
+        fs::metadata(p).is_ok()
+    }).collect()
+}
+
+pub fn init_ssl_cert_env_vars() {
+    let ProbeResult { cert_file, cert_dir } = probe();
+    match cert_file {
+        Some(path) => put("SSL_CERT_FILE", path),
+        None => {}
+    }
+    match cert_dir {
+        Some(path) => put("SSL_CERT_DIR", path),
+        None => {}
+    }
+
+    fn put(var: &str, path: PathBuf) {
+        // Don't stomp over what anyone else has set
+        match env::var(var) {
+            Ok(..) => {}
+            Err(..) => env::set_var(var, &path),
+        }
+    }
+}
+
+pub fn probe() -> ProbeResult {
+    let mut result = ProbeResult {
+        cert_file: env::var_os("SSL_CERT_FILE").map(PathBuf::from),
+        cert_dir: env::var_os("SSL_CERT_DIR").map(PathBuf::from),
+    };
+    for certs_dir in find_certs_dirs().iter() {
+        // cert.pem looks to be an openssl 1.0.1 thing, while
+        // certs/ca-certificates.crt appears to be a 0.9.8 thing
+        try(&mut result.cert_file, certs_dir.join("cert.pem"));
+        try(&mut result.cert_file, certs_dir.join("certs/ca-certificates.crt"));
+        try(&mut result.cert_file, certs_dir.join("certs/ca-root-nss.crt"));
+
+        try(&mut result.cert_dir, certs_dir.join("certs"));
+    }
+    result
+}
+
+fn try(dst: &mut Option<PathBuf>, val: PathBuf) {
+    if dst.is_none() && fs::metadata(&val).is_ok() {
+        *dst = Some(val);
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/pkg_config/lib.rs.html b/src/pkg_config/lib.rs.html new file mode 100644 index 0000000..250138e --- /dev/null +++ b/src/pkg_config/lib.rs.html @@ -0,0 +1,679 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+
+//! A build dependency for Cargo libraries to find system artifacts through the
+//! `pkg-config` utility.
+//!
+//! This library will shell out to `pkg-config` as part of build scripts and
+//! probe the system to determine how to link to a specified library. The
+//! `Config` structure serves as a method of configuring how `pkg-config` is
+//! invoked in a builder style.
+//!
+//! A number of environment variables are available to globally configure how
+//! this crate will invoke `pkg-config`:
+//!
+//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config`
+//!   will automatically be disabled for all cross compiles.
+//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when
+//!   probing for the library named `foo`.
+//!
+//! There are also a number of environment variables which can configure how a
+//! library is linked to (dynamically vs statically). These variables control
+//! whether the `--static` flag is passed. Note that this behavior can be
+//! overridden by configuring explicitly on `Config`. The variables are checked
+//! in the following order:
+//!
+//! * `FOO_STATIC` - pass `--static` for the library `foo`
+//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo`
+//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries
+//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries
+//!
+//! After running `pkg-config` all appropriate Cargo metadata will be printed on
+//! stdout if the search was successful.
+//!
+//! # Example
+//!
+//! Find the system library named `foo`.
+//!
+//! ```no_run
+//! extern crate pkg_config;
+//!
+//! fn main() {
+//!     pkg_config::find_library("foo").unwrap();
+//! }
+//! ```
+//!
+//! Configure how library `foo` is linked to.
+//!
+//! ```no_run
+//! extern crate pkg_config;
+//!
+//! fn main() {
+//!     pkg_config::Config::new().statik(true).find("foo").unwrap();
+//! }
+//! ```
+
+#![doc(html_root_url = "http://alexcrichton.com/pkg-config-rs")]
+#![cfg_attr(test, deny(warnings))]
+
+use std::ascii::AsciiExt;
+use std::env;
+use std::ffi::{OsStr, OsString};
+use std::fs;
+use std::path::{PathBuf, Path};
+use std::process::Command;
+use std::str;
+
+pub fn target_supported() -> bool {
+    env::var("HOST") == env::var("TARGET") ||
+        env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()
+}
+
+#[derive(Clone)]
+pub struct Config {
+    statik: Option<bool>,
+    atleast_version: Option<String>,
+    extra_args: Vec<OsString>,
+}
+
+#[derive(Debug)]
+pub struct Library {
+    pub libs: Vec<String>,
+    pub link_paths: Vec<PathBuf>,
+    pub frameworks: Vec<String>,
+    pub framework_paths: Vec<PathBuf>,
+    pub include_paths: Vec<PathBuf>,
+    pub version: String,
+    _priv: (),
+}
+
+/// Simple shortcut for using all default options for finding a library.
+pub fn find_library(name: &str) -> Result<Library, String> {
+    Config::new().find(name)
+}
+
+impl Config {
+    /// Creates a new set of configuration options which are all initially set
+    /// to "blank".
+    pub fn new() -> Config {
+        Config {
+            statik: None,
+            atleast_version: None,
+            extra_args: vec![],
+        }
+    }
+
+    /// Indicate whether the `--static` flag should be passed.
+    ///
+    /// This will override the inference from environment variables described in
+    /// the crate documentation.
+    pub fn statik(&mut self, statik: bool) -> &mut Config {
+        self.statik = Some(statik);
+        self
+    }
+
+    /// Indicate that the library must be at least version `vers`.
+    pub fn atleast_version(&mut self, vers: &str) -> &mut Config {
+        self.atleast_version = Some(vers.to_string());
+        self
+    }
+
+    /// Add an argument to pass to pkg-config.
+    ///
+    /// It's placed after all of the arguments generated by this library.
+    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Config {
+        self.extra_args.push(arg.as_ref().to_os_string());
+        self
+    }
+
+    /// Run `pkg-config` to find the library `name`.
+    ///
+    /// This will use all configuration previously set to specify how
+    /// `pkg-config` is run.
+    pub fn find(&self, name: &str) -> Result<Library, String> {
+        if env::var_os(&format!("{}_NO_PKG_CONFIG", envify(name))).is_some() {
+            return Err(format!("pkg-config requested to be aborted for {}", name))
+        } else if !target_supported() {
+            return Err("pkg-config doesn't handle cross compilation. Use \
+                        PKG_CONFIG_ALLOW_CROSS=1 to override".to_string());
+        }
+
+        let mut library = Library::new();
+
+        let output = try!(run(self.command(name, &["--libs", "--cflags"])));
+        library.parse_libs_cflags(name, &output, self);
+
+        let output = try!(run(self.command(name, &["--modversion"])));
+        library.parse_modversion(&output);
+
+        Ok(library)
+    }
+
+    /// Run `pkg-config` to get the value of a variable from a package using
+    /// --variable.
+    pub fn get_variable(package: &str, variable: &str) -> Result<String, String> {
+        let arg = format!("--variable={}", variable);
+        let cfg = Config::new();
+        Ok(try!(run(cfg.command(package, &[&arg]))).trim_right().to_owned())
+    }
+
+    fn is_static(&self, name: &str) -> bool {
+        self.statik.unwrap_or_else(|| infer_static(name))
+    }
+
+    fn command(&self, name: &str, args: &[&str]) -> Command {
+        let mut cmd = Command::new("pkg-config");
+        if self.is_static(name) {
+            cmd.arg("--static");
+        }
+        cmd.args(args)
+           .args(&self.extra_args)
+           .env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
+        if let Some(ref version) = self.atleast_version {
+            cmd.arg(&format!("{} >= {}", name, version));
+        } else {
+            cmd.arg(name);
+        }
+        cmd
+    }
+}
+
+impl Library {
+    fn new() -> Library {
+        Library {
+            libs: Vec::new(),
+            link_paths: Vec::new(),
+            include_paths: Vec::new(),
+            frameworks: Vec::new(),
+            framework_paths: Vec::new(),
+            version: String::new(),
+            _priv: (),
+        }
+    }
+
+    fn parse_libs_cflags(&mut self, name: &str, output: &str, config: &Config) {
+        let parts = output.split(' ')
+                          .filter(|l| l.len() > 2)
+                          .map(|arg| (&arg[0..2], &arg[2..]))
+                          .collect::<Vec<_>>();
+
+        let mut dirs = Vec::new();
+        let statik = config.is_static(name);
+        for &(flag, val) in parts.iter() {
+            match flag {
+                "-L" => {
+                    println!("cargo:rustc-link-search=native={}", val);
+                    dirs.push(PathBuf::from(val));
+                    self.link_paths.push(PathBuf::from(val));
+                }
+                "-F" => {
+                    println!("cargo:rustc-link-search=framework={}", val);
+                    self.framework_paths.push(PathBuf::from(val));
+                }
+                "-I" => {
+                    self.include_paths.push(PathBuf::from(val));
+                }
+                "-l" => {
+                    self.libs.push(val.to_string());
+                    if statik && !is_system(val, &dirs) {
+                        println!("cargo:rustc-link-lib=static={}", val);
+                    } else {
+                        println!("cargo:rustc-link-lib={}", val);
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        let mut iter = output.split(' ');
+        while let Some(part) = iter.next() {
+            if part != "-framework" { continue }
+            if let Some(lib) = iter.next() {
+                println!("cargo:rustc-link-lib=framework={}", lib);
+                self.frameworks.push(lib.to_string());
+            }
+        }
+    }
+
+    fn parse_modversion(&mut self, output: &str) {
+        self.version.push_str(output.trim());
+    }
+}
+
+fn infer_static(name: &str) -> bool {
+    let name = envify(name);
+    if env::var_os(&format!("{}_STATIC", name)).is_some() {
+        true
+    } else if env::var_os(&format!("{}_DYNAMIC", name)).is_some() {
+        false
+    } else if env::var_os("PKG_CONFIG_ALL_STATIC").is_some() {
+        true
+    } else if env::var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() {
+        false
+    } else {
+        false
+    }
+}
+
+fn envify(name: &str) -> String {
+    name.chars().map(|c| c.to_ascii_uppercase()).map(|c| {
+        if c == '-' {'_'} else {c}
+    }).collect()
+}
+
+fn is_system(name: &str, dirs: &[PathBuf]) -> bool {
+    let libname = format!("lib{}.a", name);
+    let root = Path::new("/usr");
+    !dirs.iter().any(|d| {
+        !d.starts_with(root) && fs::metadata(&d.join(&libname)).is_ok()
+    })
+}
+
+fn run(mut cmd: Command) -> Result<String, String> {
+    let out = try!(cmd.output().map_err(|e| {
+        format!("failed to run `{:?}`: {}", cmd, e)
+    }));
+
+    let stdout = String::from_utf8(out.stdout).unwrap();
+    if out.status.success() {
+        return Ok(stdout);
+    }
+
+    let stderr = str::from_utf8(&out.stderr).unwrap();
+    let mut msg = format!("`{:?}` did not exit successfully: {}", cmd, out.status);
+    if stdout.len() > 0 {
+        msg.push_str("\n--- stdout\n");
+        msg.push_str(&stdout);
+    }
+    if stderr.len() > 0 {
+        msg.push_str("\n--- stderr\n");
+        msg.push_str(stderr);
+    }
+
+    return Err(msg);
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex/char.rs.html b/src/regex/char.rs.html new file mode 100644 index 0000000..f830f03 --- /dev/null +++ b/src/regex/char.rs.html @@ -0,0 +1,311 @@ + + + + + + + + + + char.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::char;
+use std::cmp::Ordering;
+use std::fmt;
+use std::u32;
+
+use syntax;
+
+/// An inline representation of `Option<char>`.
+///
+/// This eliminates the need to do case analysis on `Option<char>` to determine
+/// ordinality with other characters.
+///
+/// (The `Option<char>` is not related to encoding. Instead, it is used in the
+/// matching engines to represent the beginning and ending boundaries of the
+/// search text.)
+#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Char(u32);
+
+impl fmt::Debug for Char {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match char::from_u32(self.0) {
+            None => write!(f, "Empty"),
+            Some(c) => write!(f, "{:?}", c),
+        }
+    }
+}
+
+impl Char {
+    /// Returns true iff the character is absent.
+    #[inline]
+    pub fn is_none(self) -> bool { self.0 == u32::MAX }
+
+    /// Returns the length of the character's UTF-8 encoding.
+    ///
+    /// If the character is absent, then `0` is returned.
+    #[inline]
+    pub fn len_utf8(self) -> usize {
+        char::from_u32(self.0).map(|c| c.len_utf8()).unwrap_or(0)
+    }
+
+    /// Returns the simple case folding of this character.
+    ///
+    /// If the character is absent, then absence is returned.
+    pub fn case_fold(self) -> Char {
+        char::from_u32(self.0).map(syntax::simple_case_fold).into()
+    }
+
+    /// Returns true iff the character is a word character.
+    ///
+    /// If the character is absent, then false is returned.
+    pub fn is_word_char(self) -> bool {
+        char::from_u32(self.0).map(syntax::is_word_char).unwrap_or(false)
+    }
+
+    /// Converts the character to a real primitive `char`.
+    ///
+    /// If the character is absent, then `None` is returned.
+    pub fn as_char(self) -> Option<char> {
+        // This is only used in the `regex!` macro because it expands char
+        // classes into `match` expressions (instead of binary search).
+        char::from_u32(self.0)
+    }
+}
+
+impl From<char> for Char {
+    fn from(c: char) -> Char { Char(c as u32) }
+}
+
+impl From<Option<char>> for Char {
+    fn from(c: Option<char>) -> Char {
+        c.map(|c| c.into()).unwrap_or(Char(u32::MAX))
+    }
+}
+
+impl PartialEq<char> for Char {
+    #[inline]
+    fn eq(&self, other: &char) -> bool { self.0 == *other as u32 }
+}
+
+impl PartialEq<Char> for char {
+    #[inline]
+    fn eq(&self, other: &Char) -> bool { *self as u32 == other.0 }
+}
+
+impl PartialOrd<char> for Char {
+    #[inline]
+    fn partial_cmp(&self, other: &char) -> Option<Ordering> {
+        self.0.partial_cmp(&(*other as u32))
+    }
+}
+
+impl PartialOrd<Char> for char {
+    #[inline]
+    fn partial_cmp(&self, other: &Char) -> Option<Ordering> {
+        (*self as u32).partial_cmp(&other.0)
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex/input.rs.html b/src/regex/input.rs.html new file mode 100644 index 0000000..dfe5571 --- /dev/null +++ b/src/regex/input.rs.html @@ -0,0 +1,325 @@ + + + + + + + + + + input.rs.html -- source + + + + + + + + + + + + + + + +
  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
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops;
+
+use char::Char;
+use prefix::Prefix;
+
+/// Represents a location in the input.
+#[derive(Clone, Copy, Debug)]
+pub struct InputAt {
+    pos: usize,
+    c: Char,
+    len: usize,
+}
+
+impl InputAt {
+    /// Returns true iff this position is at the beginning of the input.
+    pub fn is_beginning(&self) -> bool {
+        self.pos == 0
+    }
+
+    /// Returns the character at this position.
+    ///
+    /// If this position is just before or after the input, then an absent
+    /// character is returned.
+    pub fn char(&self) -> Char {
+        self.c
+    }
+
+    /// Returns the UTF-8 width of the character at this position.
+    pub fn len(&self) -> usize {
+        self.len
+    }
+
+    /// Returns the byte offset of this position.
+    pub fn pos(&self) -> usize {
+        self.pos
+    }
+
+    /// Returns the byte offset of the next position in the input.
+    pub fn next_pos(&self) -> usize {
+        self.pos + self.len
+    }
+}
+
+/// An abstraction over input used in the matching engines.
+pub trait Input {
+    /// Return an encoding of the position at byte offset `i`.
+    fn at(&self, i: usize) -> InputAt;
+    /// Return an encoding of the char position just prior to byte offset `i`.
+    fn previous_at(&self, i: usize) -> InputAt;
+    /// Scan the input for a matching prefix.
+    fn prefix_at(&self, prefixes: &Prefix, at: InputAt) -> Option<InputAt>;
+}
+
+/// An input reader over characters.
+///
+/// (This is the only implementation of `Input` at the moment.)
+#[derive(Debug)]
+pub struct CharInput<'t>(&'t str);
+
+impl<'t> CharInput<'t> {
+    /// Return a new character input reader for the given string.
+    pub fn new(s: &'t str) -> CharInput<'t> {
+        CharInput(s)
+    }
+}
+
+impl<'t> ops::Deref for CharInput<'t> {
+    type Target = str;
+
+    fn deref(&self) -> &str {
+        self.0
+    }
+}
+
+impl<'t> Input for CharInput<'t> {
+    // This `inline(always)` increases throughput by almost 25% on the `hard`
+    // benchmarks over a normal `inline` annotation.
+    //
+    // I'm not sure why `#[inline]` isn't enough to convince LLVM, but it is
+    // used *a lot* in the guts of the matching engines.
+    #[inline(always)]
+    fn at(&self, i: usize) -> InputAt {
+        let c = self[i..].chars().next().into();
+        InputAt {
+            pos: i,
+            c: c,
+            len: c.len_utf8(),
+        }
+    }
+
+    fn previous_at(&self, i: usize) -> InputAt {
+        let c: Char = self[..i].chars().rev().next().into();
+        let len = c.len_utf8();
+        InputAt {
+            pos: i - len,
+            c: c,
+            len: len,
+        }
+    }
+
+    fn prefix_at(&self, prefixes: &Prefix, at: InputAt) -> Option<InputAt> {
+        prefixes.find(&self[at.pos()..]).map(|(s, _)| self.at(at.pos() + s))
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex/lib.rs.html b/src/regex/lib.rs.html new file mode 100644 index 0000000..8331db1 --- /dev/null +++ b/src/regex/lib.rs.html @@ -0,0 +1,959 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This crate provides a native implementation of regular expressions that is
+//! heavily based on RE2 both in syntax and in implementation. Notably,
+//! backreferences and arbitrary lookahead/lookbehind assertions are not
+//! provided. In return, regular expression searching provided by this package
+//! has excellent worst-case performance. The specific syntax supported is
+//! documented further down.
+//!
+//! This crate's documentation provides some simple examples, describes Unicode
+//! support and exhaustively lists the supported syntax. For more specific
+//! details on the API, please see the documentation for the `Regex` type.
+//!
+//! # Usage
+//!
+//! This crate is [on crates.io](https://crates.io/crates/regex) and can be
+//! used by adding `regex` to your dependencies in your project's `Cargo.toml`.
+//!
+//! ```toml
+//! [dependencies]
+//! regex = "0.1.8"
+//! ```
+//!
+//! and this to your crate root:
+//!
+//! ```rust
+//! extern crate regex;
+//! ```
+//!
+//! # First example: find a date
+//!
+//! General use of regular expressions in this package involves compiling an
+//! expression and then using it to search, split or replace text. For example,
+//! to confirm that some text resembles a date:
+//!
+//! ```rust
+//! use regex::Regex;
+//! let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+//! assert!(re.is_match("2014-01-01"));
+//! ```
+//!
+//! Notice the use of the `^` and `$` anchors. In this crate, every expression
+//! is executed with an implicit `.*?` at the beginning and end, which allows
+//! it to match anywhere in the text. Anchors can be used to ensure that the
+//! full text matches an expression.
+//!
+//! This example also demonstrates the utility of
+//! [raw strings](http://doc.rust-lang.org/stable/reference.html#raw-byte-string-literals)
+//! in Rust, which
+//! are just like regular strings except they are prefixed with an `r` and do
+//! not process any escape sequences. For example, `"\\d"` is the same
+//! expression as `r"\d"`.
+//!
+//! # The `regex!` macro
+//!
+//! Rust's compile-time meta-programming facilities provide a way to write a
+//! `regex!` macro which compiles regular expressions *when your program
+//! compiles*. Said differently, if you only use `regex!` to build regular
+//! expressions in your program, then your program cannot compile with an
+//! invalid regular expression. Moreover, the `regex!` macro compiles the
+//! given expression to native Rust code, which ideally makes it faster.
+//! Unfortunately (or fortunately), the dynamic implementation has had a lot
+//! more optimization work put it into it currently, so it is faster than
+//! the `regex!` macro in most cases.
+//!
+//! To use the `regex!` macro, you must enable the `plugin` feature and import
+//! the `regex_macros` crate as a syntax extension:
+//!
+//! ```ignore
+//! #![feature(plugin)]
+//! #![plugin(regex_macros)]
+//! extern crate regex;
+//!
+//! fn main() {
+//!     let re = regex!(r"^\d{4}-\d{2}-\d{2}$");
+//!     assert!(re.is_match("2014-01-01"));
+//! }
+//! ```
+//!
+//! There are a few things worth mentioning about using the `regex!` macro.
+//! Firstly, the `regex!` macro *only* accepts string *literals*.
+//! Secondly, the `regex` crate *must* be linked with the name `regex` since
+//! the generated code depends on finding symbols in the `regex` crate.
+//!
+//! One downside of using the `regex!` macro is that it can increase the
+//! size of your program's binary since it generates specialized Rust code.
+//! The extra size probably won't be significant for a small number of
+//! expressions, but 100+ calls to `regex!` will probably result in a
+//! noticeably bigger binary.
+//!
+//! **NOTE**: This is implemented using a compiler plugin, which is not
+//! available on the Rust 1.0 beta/stable channels. Therefore, you'll only
+//! be able to use `regex!` on the nightlies.
+//!
+//! # Example: iterating over capture groups
+//!
+//! This crate provides convenient iterators for matching an expression
+//! repeatedly against a search string to find successive non-overlapping
+//! matches. For example, to find all dates in a string and be able to access
+//! them by their component pieces:
+//!
+//! ```rust
+//! # extern crate regex; use regex::Regex;
+//! # fn main() {
+//! let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();
+//! let text = "2012-03-14, 2013-01-01 and 2014-07-05";
+//! for cap in re.captures_iter(text) {
+//!     println!("Month: {} Day: {} Year: {}",
+//!              cap.at(2).unwrap_or(""), cap.at(3).unwrap_or(""),
+//!              cap.at(1).unwrap_or(""));
+//! }
+//! // Output:
+//! // Month: 03 Day: 14 Year: 2012
+//! // Month: 01 Day: 01 Year: 2013
+//! // Month: 07 Day: 05 Year: 2014
+//! # }
+//! ```
+//!
+//! Notice that the year is in the capture group indexed at `1`. This is
+//! because the *entire match* is stored in the capture group at index `0`.
+//!
+//! # Example: replacement with named capture groups
+//!
+//! Building on the previous example, perhaps we'd like to rearrange the date
+//! formats. This can be done with text replacement. But to make the code
+//! clearer, we can *name*  our capture groups and use those names as variables
+//! in our replacement text:
+//!
+//! ```rust
+//! # extern crate regex; use regex::Regex;
+//! # fn main() {
+//! let re = Regex::new(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})").unwrap();
+//! let before = "2012-03-14, 2013-01-01 and 2014-07-05";
+//! let after = re.replace_all(before, "$m/$d/$y");
+//! assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014");
+//! # }
+//! ```
+//!
+//! The `replace` methods are actually polymorphic in the replacement, which
+//! provides more flexibility than is seen here. (See the documentation for
+//! `Regex::replace` for more details.)
+//!
+//! Note that if your regex gets complicated, you can use the `x` flag to
+//! enable insigificant whitespace mode, which also lets you write comments:
+//!
+//! ```rust
+//! # extern crate regex; use regex::Regex;
+//! # fn main() {
+//! let re = Regex::new(r"(?x)
+//!   (?P<y>\d{4}) # the year
+//!   -
+//!   (?P<m>\d{2}) # the month
+//!   -
+//!   (?P<d>\d{2}) # the day
+//! ").unwrap();
+//! let before = "2012-03-14, 2013-01-01 and 2014-07-05";
+//! let after = re.replace_all(before, "$m/$d/$y");
+//! assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014");
+//! # }
+//! ```
+//!
+//! # Pay for what you use
+//!
+//! With respect to searching text with a regular expression, there are three
+//! questions that can be asked:
+//!
+//! 1. Does the text match this expression?
+//! 2. If so, where does it match?
+//! 3. Where are the submatches?
+//!
+//! Generally speaking, this crate could provide a function to answer only #3,
+//! which would subsume #1 and #2 automatically. However, it can be
+//! significantly more expensive to compute the location of submatches, so it's
+//! best not to do it if you don't need to.
+//!
+//! Therefore, only use what you need. For example, don't use `find` if you
+//! only need to test if an expression matches a string. (Use `is_match`
+//! instead.)
+//!
+//! # Unicode
+//!
+//! This implementation executes regular expressions **only** on sequences of
+//! Unicode scalar values while exposing match locations as byte indices into
+//! the search string.
+//!
+//! Currently, only simple case folding is supported. Namely, when matching
+//! case-insensitively, the characters are first mapped using the
+//! [simple case folding](ftp://ftp.unicode.org/Public/UNIDATA/CaseFolding.txt)
+//! mapping.
+//!
+//! Regular expressions themselves are also **only** interpreted as a sequence
+//! of Unicode scalar values. This means you can use Unicode characters
+//! directly in your expression:
+//!
+//! ```rust
+//! # extern crate regex; use regex::Regex;
+//! # fn main() {
+//! let re = Regex::new(r"(?i)Δ+").unwrap();
+//! assert_eq!(re.find("ΔδΔ"), Some((0, 6)));
+//! # }
+//! ```
+//!
+//! Finally, Unicode general categories and scripts are available as character
+//! classes. For example, you can match a sequence of numerals, Greek or
+//! Cherokee letters:
+//!
+//! ```rust
+//! # extern crate regex; use regex::Regex;
+//! # fn main() {
+//! let re = Regex::new(r"[\pN\p{Greek}\p{Cherokee}]+").unwrap();
+//! assert_eq!(re.find("abcΔᎠβⅠᏴγδⅡxyz"), Some((3, 23)));
+//! # }
+//! ```
+//!
+//! # Syntax
+//!
+//! The syntax supported in this crate is almost in an exact correspondence
+//! with the syntax supported by RE2. It is documented below.
+//!
+//! Note that the regular expression parser and abstract syntax are exposed in
+//! a separate crate,
+//! [`regex-syntax`](../regex_syntax/index.html).
+//!
+//! ## Matching one character
+//!
+//! <pre class="rust">
+//! .           any character except new line (includes new line with s flag)
+//! [xyz]       A character class matching either x, y or z.
+//! [^xyz]      A character class matching any character except x, y and z.
+//! [a-z]       A character class matching any character in range a-z.
+//! \d          digit (\p{Nd})
+//! \D          not digit
+//! [:alpha:]   ASCII character class ([A-Za-z])
+//! [:^alpha:]  Negated ASCII character class ([^A-Za-z])
+//! \pN         One-letter name Unicode character class
+//! \p{Greek}   Unicode character class (general category or script)
+//! \PN         Negated one-letter name Unicode character class
+//! \P{Greek}   negated Unicode character class (general category or script)
+//! </pre>
+//!
+//! Any named character class may appear inside a bracketed `[...]` character
+//! class. For example, `[\p{Greek}\pN]` matches any Greek or numeral
+//! character.
+//!
+//! ## Composites
+//!
+//! <pre class="rust">
+//! xy    concatenation (x followed by y)
+//! x|y   alternation (x or y, prefer x)
+//! </pre>
+//!
+//! ## Repetitions
+//!
+//! <pre class="rust">
+//! x*        zero or more of x (greedy)
+//! x+        one or more of x (greedy)
+//! x?        zero or one of x (greedy)
+//! x*?       zero or more of x (ungreedy)
+//! x+?       one or more of x (ungreedy)
+//! x??       zero or one of x (ungreedy)
+//! x{n,m}    at least n x and at most m x (greedy)
+//! x{n,}     at least n x (greedy)
+//! x{n}      exactly n x
+//! x{n,m}?   at least n x and at most m x (ungreedy)
+//! x{n,}?    at least n x (ungreedy)
+//! x{n}?     exactly n x
+//! </pre>
+//!
+//! ## Empty matches
+//!
+//! <pre class="rust">
+//! ^     the beginning of text (or start-of-line with multi-line mode)
+//! $     the end of text (or end-of-line with multi-line mode)
+//! \A    only the beginning of text (even with multi-line mode enabled)
+//! \z    only the end of text (even with multi-line mode enabled)
+//! \b    a Unicode word boundary (\w on one side and \W, \A, or \z on other)
+//! \B    not a Unicode word boundary
+//! </pre>
+//!
+//! ## Grouping and flags
+//!
+//! <pre class="rust">
+//! (exp)          numbered capture group (indexed by opening parenthesis)
+//! (?P&lt;name&gt;exp)  named (also numbered) capture group (allowed chars: [_0-9a-zA-Z])
+//! (?:exp)        non-capturing group
+//! (?flags)       set flags within current group
+//! (?flags:exp)   set flags for exp (non-capturing)
+//! </pre>
+//!
+//! Flags are each a single character. For example, `(?x)` sets the flag `x`
+//! and `(?-x)` clears the flag `x`. Multiple flags can be set or cleared at
+//! the same time: `(?xy)` sets both the `x` and `y` flags and `(?x-y)` sets
+//! the `x` flag and clears the `y` flag.
+//!
+//! All flags are by default disabled. They are:
+//!
+//! <pre class="rust">
+//! i     case-insensitive
+//! m     multi-line mode: ^ and $ match begin/end of line
+//! s     allow . to match \n
+//! U     swap the meaning of x* and x*?
+//! x     ignore whitespace and allow line comments (starting with `#`)
+//! </pre>
+//!
+//! Here's an example that matches case-insensitively for only part of the
+//! expression:
+//!
+//! ```rust
+//! # extern crate regex; use regex::Regex;
+//! # fn main() {
+//! let re = Regex::new(r"(?i)a+(?-i)b+").unwrap();
+//! let cap = re.captures("AaAaAbbBBBb").unwrap();
+//! assert_eq!(cap.at(0), Some("AaAaAbb"));
+//! # }
+//! ```
+//!
+//! Notice that the `a+` matches either `a` or `A`, but the `b+` only matches
+//! `b`.
+//!
+//! ## Escape sequences
+//!
+//! <pre class="rust">
+//! \*         literal *, works for any punctuation character: \.+*?()|[]{}^$
+//! \a         bell (\x07)
+//! \f         form feed (\x0C)
+//! \t         horizontal tab
+//! \n         new line
+//! \r         carriage return
+//! \v         vertical tab (\x0B)
+//! \123       octal character code (up to three digits)
+//! \x7F       hex character code (exactly two digits)
+//! \x{10FFFF} any hex character code corresponding to a Unicode code point
+//! </pre>
+//!
+//! ## Perl character classes (Unicode friendly)
+//!
+//! These classes are based on the definitions provided in
+//! [UTS#18](http://www.unicode.org/reports/tr18/#Compatibility_Properties):
+//!
+//! <pre class="rust">
+//! \d     digit (\p{Nd})
+//! \D     not digit
+//! \s     whitespace (\p{White_Space})
+//! \S     not whitespace
+//! \w     word character (\p{Alphabetic} + \p{M} + \d + \p{Pc} + \p{Join_Control})
+//! \W     not word character
+//! </pre>
+//!
+//! ## ASCII character classes
+//!
+//! <pre class="rust">
+//! [:alnum:]    alphanumeric ([0-9A-Za-z])
+//! [:alpha:]    alphabetic ([A-Za-z])
+//! [:ascii:]    ASCII ([\x00-\x7F])
+//! [:blank:]    blank ([\t ])
+//! [:cntrl:]    control ([\x00-\x1F\x7F])
+//! [:digit:]    digits ([0-9])
+//! [:graph:]    graphical ([!-~])
+//! [:lower:]    lower case ([a-z])
+//! [:print:]    printable ([ -~])
+//! [:punct:]    punctuation ([!-/:-@[-`{-~])
+//! [:space:]    whitespace ([\t\n\v\f\r ])
+//! [:upper:]    upper case ([A-Z])
+//! [:word:]     word characters ([0-9A-Za-z_])
+//! [:xdigit:]   hex digit ([0-9A-Fa-f])
+//! </pre>
+//!
+//! # Untrusted input
+//!
+//! This crate can handle both untrusted regular expressions and untrusted
+//! search text.
+//!
+//! Untrusted regular expressions are handled by capping the size of a compiled
+//! regular expression. (See `Regex::with_size_limit`.) Without this, it would
+//! be trivial for an attacker to exhaust your system's memory with expressions
+//! like `a{100}{100}{100}`.
+//!
+//! Untrusted search text is allowed because the matching engine(s) in this
+//! crate have time complexity `O(mn)` (with `m ~ regex` and `n ~ search
+//! text`), which means there's no way to cause exponential blow-up like with
+//! some other regular expression engines. (We pay for this by disallowing
+//! features like arbitrary look-ahead and back-references.)
+
+#![deny(missing_docs)]
+#![cfg_attr(test, deny(warnings))]
+#![cfg_attr(feature = "pattern", feature(pattern))]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+       html_root_url = "http://doc.rust-lang.org/regex/")]
+
+extern crate aho_corasick;
+extern crate memchr;
+extern crate regex_syntax as syntax;
+
+pub use re::{
+    Regex, Error, Captures, SubCaptures, SubCapturesPos, SubCapturesNamed,
+    FindCaptures, FindMatches,
+    Replacer, NoExpand, RegexSplits, RegexSplitsN,
+    quote, is_match,
+};
+
+mod backtrack;
+mod char;
+mod compile;
+mod input;
+mod pool;
+mod prefix;
+mod program;
+mod nfa;
+mod re;
+
+/// The `internal` module exists to support the `regex!` macro and other
+/// suspicious activity, such as testing different matching engines.
+#[doc(hidden)]
+pub mod internal {
+    pub use char::Char;
+    pub use input::{Input, CharInput, InputAt};
+    pub use program::{
+        Program, MatchEngine, CharRanges, Inst, LookInst, OneChar,
+    };
+    pub use re::ExNative;
+    pub use re::Regex::{Dynamic, Native};
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex/program.rs.html b/src/regex/program.rs.html new file mode 100644 index 0000000..8f6ed02 --- /dev/null +++ b/src/regex/program.rs.html @@ -0,0 +1,1057 @@ + + + + + + + + + + program.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp::{self, Ordering};
+
+use syntax;
+
+use Error;
+use backtrack::{Backtrack, BackMachine};
+use char::Char;
+use compile::Compiler;
+use nfa::{Nfa, NfaThreads};
+use pool::Pool;
+use prefix::Prefix;
+use re::CaptureIdxs;
+
+const NUM_PREFIX_LIMIT: usize = 30;
+const PREFIX_LENGTH_LIMIT: usize = 15;
+
+pub type InstIdx = usize;
+
+/// An instruction, the underlying unit of a compiled regular expression
+#[derive(Clone, Debug)]
+pub enum Inst {
+    /// A match has occurred.
+    /// This is always the last instruction and only occurs in a single spot.
+    /// We could special case this in the code, but it is much clearer to
+    /// handle it as a proper instruction.
+    Match,
+    /// Save the current location in the input into the given capture location.
+    Save(usize),
+    /// Jump to the instruction given.
+    Jump(InstIdx),
+    /// Match either instruction, preferring the first.
+    Split(InstIdx, InstIdx),
+    /// A zero-width instruction. When this instruction matches, the input
+    /// is not advanced.
+    EmptyLook(LookInst),
+    /// Match a single possibly case insensitive character.
+    Char(OneChar),
+    /// Match one or more possibly case insensitive character ranges.
+    Ranges(CharRanges),
+}
+
+/// A single character instruction.
+#[derive(Clone, Debug)]
+pub struct OneChar {
+    /// The character.
+    pub c: char,
+    /// True if the character should be matched case insensitively.
+    /// (i.e., The input character will need to be case folded.)
+    pub casei: bool,
+}
+
+/// A multi-range character class instruction.
+#[derive(Clone, Debug)]
+pub struct CharRanges {
+    /// Sorted sequence of non-overlapping ranges.
+    pub ranges: Vec<(char, char)>,
+    /// Whether to match case insensitively.
+    pub casei: bool,
+}
+
+/// The set of zero-width match instructions.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum LookInst {
+    /// Start of line or input.
+    StartLine,
+    /// End of line or input.
+    EndLine,
+    /// Start of input.
+    StartText,
+    /// End of input.
+    EndText,
+    /// Word character on one side and non-word character on other.
+    WordBoundary,
+    /// Word character on both sides or non-word character on both sides.
+    NotWordBoundary,
+}
+
+impl OneChar {
+    /// Tests whether the given input character matches this instruction.
+    #[inline(always)] // About ~5-15% more throughput then `#[inline]`
+    pub fn matches(&self, c: Char) -> bool {
+        self.c == c || (self.casei && self.c == c.case_fold())
+    }
+}
+
+impl CharRanges {
+    /// Emits a range specifically for the `.` expression.
+    pub fn any() -> CharRanges {
+        CharRanges {
+            ranges: vec![('\x00', '\u{10ffff}')],
+            casei: false,
+        }
+    }
+
+    /// Emits a range specifically for the `(?s).` expression.
+    pub fn any_nonl() -> CharRanges {
+        CharRanges {
+            ranges: vec![('\x00', '\x09'), ('\x0B', '\u{10ffff}')],
+            casei: false,
+        }
+    }
+
+    /// Emits a range from the AST character class.
+    pub fn from_class(cls: syntax::CharClass) -> CharRanges {
+        let casei = cls.is_case_insensitive();
+        CharRanges {
+            ranges: cls.into_iter().map(|r| (r.start, r.end)).collect(),
+            casei: casei,
+        }
+    }
+
+    /// Tests whether the given input character matches this instruction.
+    #[inline(always)] // About ~5-15% more throughput then `#[inline]`
+    pub fn matches(&self, mut c: Char) -> Option<usize> {
+        if self.casei {
+            c = c.case_fold();
+        }
+        // This speeds up the `match_class_unicode` benchmark by checking
+        // some common cases quickly without binary search. e.g., Matching
+        // a Unicode class on predominantly ASCII text.
+        for i in 0..cmp::min(self.ranges.len(), 4) {
+            let r = self.ranges[i];
+            if c < r.0 {
+                return None;
+            }
+            if c <= r.1 {
+                return Some(i);
+            }
+        }
+        self.ranges.binary_search_by(|r| {
+            if r.1 < c {
+                Ordering::Less
+            } else if r.0 > c {
+                Ordering::Greater
+            } else {
+                Ordering::Equal
+            }
+        }).ok()
+    }
+}
+
+impl LookInst {
+    /// Tests whether the pair of characters matches this zero-width
+    /// instruction.
+    pub fn matches(&self, c1: Char, c2: Char) -> bool {
+        use self::LookInst::*;
+        match *self {
+            StartLine => c1.is_none() || c1 == '\n',
+            EndLine => c2.is_none() || c2 == '\n',
+            StartText => c1.is_none(),
+            EndText => c2.is_none(),
+            ref wbty => {
+                let (w1, w2) = (c1.is_word_char(), c2.is_word_char());
+                (*wbty == WordBoundary && w1 ^ w2)
+                || (*wbty == NotWordBoundary && !(w1 ^ w2))
+            }
+        }
+    }
+}
+
+/// The matching engines offered by this regex implementation.
+///
+/// N.B. This is exported for use in testing.
+#[doc(hidden)]
+#[derive(Clone, Copy, Debug)]
+pub enum MatchEngine {
+    /// A bounded backtracking implementation. About twice as fast as the
+    /// NFA, but can only work on small regexes and small input.
+    Backtrack,
+    /// A full NFA simulation. Can always be employed but almost always the
+    /// slowest choice.
+    Nfa,
+    /// If the entire regex is a literal and no capture groups have been
+    /// requested, then we can degrade to a simple substring match.
+    Literals,
+}
+
+/// Program represents a compiled regular expression. Once an expression is
+/// compiled, its representation is immutable and will never change.
+/// (Well, almost. In fact, the matching engines cache state that can be
+/// reused on subsequent searches. But this is interior mutability that
+/// shouldn't be observable by the caller.)
+#[derive(Debug)]
+pub struct Program {
+    /// The original regular expression string.
+    pub original: String,
+    /// A sequence of instructions.
+    pub insts: Vec<Inst>,
+    /// The sequence of capture group names. There is an entry for each capture
+    /// group index and a name exists only if the capture group is named.
+    pub cap_names: Vec<Option<String>>,
+    /// If the regular expression requires a literal prefix in order to have a
+    /// match, that prefix is stored here as a DFA.
+    pub prefixes: Prefix,
+    /// True iff matching any literal prefix indicates a match.
+    pub prefixes_complete: bool,
+    /// True iff program is anchored at the beginning.
+    pub anchored_begin: bool,
+    /// True iff program is anchored at the end.
+    pub anchored_end: bool,
+    /// The type of matching engine to use.
+    /// When `None` (the default), pick an engine automatically.
+    pub engine: Option<MatchEngine>,
+    /// Cached NFA threads.
+    pub nfa_threads: Pool<NfaThreads>,
+    /// Cached backtracking memory.
+    pub backtrack: Pool<BackMachine>,
+}
+
+impl Program {
+    /// Compiles a Regex.
+    pub fn new(
+        engine: Option<MatchEngine>,
+        size_limit: usize,
+        re: &str,
+    ) -> Result<Program, Error> {
+        let expr = try!(syntax::Expr::parse(re));
+        let (insts, cap_names) = try!(Compiler::new(size_limit).compile(expr));
+        let (insts_len, ncaps) = (insts.len(), num_captures(&insts));
+        let create_threads = move || NfaThreads::new(insts_len, ncaps);
+        let create_backtrack = move || BackMachine::new();
+        let mut prog = Program {
+            original: re.into(),
+            insts: insts,
+            cap_names: cap_names,
+            prefixes: Prefix::Empty,
+            prefixes_complete: false,
+            anchored_begin: false,
+            anchored_end: false,
+            engine: engine,
+            nfa_threads: Pool::new(Box::new(create_threads)),
+            backtrack: Pool::new(Box::new(create_backtrack)),
+        };
+
+        prog.find_prefixes();
+        prog.anchored_begin = match prog.insts[1] {
+            Inst::EmptyLook(LookInst::StartText) => true,
+            _ => false,
+        };
+        prog.anchored_end = match prog.insts[prog.insts.len() - 3] {
+            Inst::EmptyLook(LookInst::EndText) => true,
+            _ => false,
+        };
+        Ok(prog)
+    }
+
+    /// Executes a compiled regex program.
+    pub fn exec(
+        &self,
+        caps: &mut CaptureIdxs,
+        text: &str,
+        start: usize,
+    ) -> bool {
+        match self.choose_engine(caps.len(), text) {
+            MatchEngine::Backtrack => Backtrack::exec(self, caps, text, start),
+            MatchEngine::Nfa => Nfa::exec(self, caps, text, start),
+            MatchEngine::Literals => {
+                match self.prefixes.find(&text[start..]) {
+                    None => false,
+                    Some((s, e)) => {
+                        if caps.len() == 2 {
+                            caps[0] = Some(start + s);
+                            caps[1] = Some(start + e);
+                        }
+                        true
+                    }
+                }
+            }
+        }
+    }
+
+    fn choose_engine(&self, cap_len: usize, text: &str) -> MatchEngine {
+        // If the engine is already chosen, then we use it.
+        // But that might not be a good idea. e.g., What if `Literals` is
+        // chosen and it can't work? I guess we should probably check whether
+        // the chosen engine is appropriate or not.
+        self.engine.unwrap_or_else(|| {
+            if cap_len <= 2
+               && self.prefixes.preserves_priority()
+               && self.prefixes_complete {
+                MatchEngine::Literals
+            } else if Backtrack::should_exec(self, text) {
+                // We're only here if the input and regex combined are small.
+                MatchEngine::Backtrack
+            } else {
+                MatchEngine::Nfa
+            }
+        })
+    }
+
+    /// Returns the total number of capture groups in the regular expression.
+    /// This includes the zeroth capture.
+    pub fn num_captures(&self) -> usize {
+        num_captures(&self.insts)
+    }
+
+    /// Allocate new capture groups.
+    pub fn alloc_captures(&self) -> Vec<Option<usize>> {
+        vec![None; 2 * self.num_captures()]
+    }
+
+    /// Find and store a prefix machine for the current program.
+    pub fn find_prefixes(&mut self) {
+        use self::Inst::*;
+
+        let (ps, complete) = self.prefixes_from_insts(1);
+        if ps.len() > 0 {
+            self.prefixes = Prefix::new(ps);
+            self.prefixes_complete = complete;
+            return;
+        }
+        let mut pc = 1;
+        let mut prefixes = vec![];
+        let mut pcomplete = true;
+        while let Split(x, y) = self.insts[pc] {
+            let (xps, xcomplete) = self.prefixes_from_insts(x);
+            let (yps, ycomplete) = self.prefixes_from_insts(y);
+            let mut done = false;
+            match (&self.insts[x], &self.insts[y]) {
+                // We should be able to support this. Add explicit stack. ---AG
+                (&Split(_, _), &Split(_, _)) => return,
+                (_, &Split(_, _)) if xps.len() == 0 => return,
+                (_, &Split(_, _)) => {
+                    pcomplete = pcomplete && xcomplete;
+                    prefixes.extend(xps);
+                    pc = y;
+                }
+                (&Split(_, _), _) if yps.len() == 0 => return,
+                (&Split(_, _), _) => {
+                    pcomplete = pcomplete && ycomplete;
+                    prefixes.extend(yps);
+                    pc = x;
+                }
+                _ if xps.len() == 0 || yps.len() == 0 => return,
+                // This is our base case. We've followed splits the whole
+                // way, which means both instructions lead to a match.
+                _ => {
+                    pcomplete = pcomplete && xcomplete && ycomplete;
+                    prefixes.extend(xps);
+                    prefixes.extend(yps);
+                    done = true;
+                }
+            }
+            // Arg. We've over-extended ourselves, quit with nothing to
+            // show for it.
+            if prefixes.len() > NUM_PREFIX_LIMIT {
+                return;
+            }
+            if done { break; }
+        }
+        self.prefixes = Prefix::new(prefixes);
+        self.prefixes_complete = pcomplete && self.prefixes.len() > 0;
+    }
+
+    /// Find a prefix starting at the given instruction.
+    ///
+    /// Returns `true` in the tuple if the end of the prefix leads trivially
+    /// to a match. (This may report false negatives, but being conservative
+    /// is OK.)
+    fn prefixes_from_insts(&self, mut pc: usize) -> (Vec<String>, bool) {
+        use self::Inst::*;
+
+        let mut complete = true;
+        let mut alts = vec![String::new()];
+        while pc < self.insts.len() {
+            let inst = &self.insts[pc];
+
+            // Each iteration adds one character to every alternate prefix *or*
+            // it stops. Thus, the prefix alternates grow in lock step, and it
+            // suffices to check one of them to see if the prefix limit has been
+            // exceeded.
+            if alts[0].len() > PREFIX_LENGTH_LIMIT {
+                complete = false;
+                break;
+            }
+            match *inst {
+                Save(_) => { pc += 1; continue } // completely ignore it
+                Char(OneChar { c, casei: false }) => {
+                    for alt in &mut alts {
+                        alt.push(c);
+                    }
+                    pc += 1;
+                }
+                Ranges(CharRanges { ref ranges, casei: false }) => {
+                    let nchars = num_chars_in_ranges(ranges);
+                    if alts.len() * nchars > NUM_PREFIX_LIMIT {
+                        complete = false;
+                        break;
+                    }
+
+                    let orig = alts;
+                    alts = Vec::with_capacity(orig.len());
+                    for &(s, e) in ranges {
+                        for c in (s as u32)..(e as u32 + 1){
+                            for alt in &orig {
+                                let mut alt = alt.clone();
+                                alt.push(::std::char::from_u32(c).unwrap());
+                                alts.push(alt);
+                            }
+                        }
+                    }
+                    pc += 1;
+                }
+                Jump(pc2) => pc = pc2,
+                _ => { complete = self.leads_to_match(pc); break }
+            }
+        }
+        if alts[0].len() == 0 {
+            (vec![], false)
+        } else {
+            (alts, complete)
+        }
+    }
+
+    fn leads_to_match(&self, mut pc: usize) -> bool {
+        // I'm pretty sure this is conservative, so it might have some
+        // false negatives.
+        loop {
+            match self.insts[pc] {
+                Inst::Match => return true,
+                Inst::Save(_) => pc += 1,
+                Inst::Jump(pc2) => pc = pc2,
+                _ => return false,
+            }
+        }
+    }
+}
+
+impl Clone for Program {
+    fn clone(&self) -> Program {
+        let (insts_len, ncaps) = (self.insts.len(), self.num_captures());
+        let create_threads = move || NfaThreads::new(insts_len, ncaps);
+        let create_backtrack = move || BackMachine::new();
+        Program {
+            original: self.original.clone(),
+            insts: self.insts.clone(),
+            cap_names: self.cap_names.clone(),
+            prefixes: self.prefixes.clone(),
+            prefixes_complete: self.prefixes_complete,
+            anchored_begin: self.anchored_begin,
+            anchored_end: self.anchored_end,
+            engine: self.engine,
+            nfa_threads: Pool::new(Box::new(create_threads)),
+            backtrack: Pool::new(Box::new(create_backtrack)),
+        }
+    }
+}
+
+/// Return the number of captures in the given sequence of instructions.
+fn num_captures(insts: &[Inst]) -> usize {
+    let mut n = 0;
+    for inst in insts {
+        match *inst {
+            Inst::Save(c) => n = cmp::max(n, c+1),
+            _ => {}
+        }
+    }
+    // There's exactly 2 Save slots for every capture.
+    n / 2
+}
+
+/// Count the number of characters in the given range.
+///
+/// This is useful for pre-emptively limiting the number of prefix literals
+/// we extract from a regex program.
+fn num_chars_in_ranges(ranges: &[(char, char)]) -> usize {
+    ranges.iter()
+          .map(|&(s, e)| (e as u32) - (s as u32))
+          .fold(0, |acc, len| acc + len) as usize
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex/re.rs.html b/src/regex/re.rs.html new file mode 100644 index 0000000..3472b45 --- /dev/null +++ b/src/regex/re.rs.html @@ -0,0 +1,2393 @@ + + + + + + + + + + re.rs.html -- source + + + + + + + + + + + + + + + +
   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
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::collections::hash_map::Iter;
+use std::fmt;
+#[cfg(feature = "pattern")]
+use std::str::pattern::{Pattern, Searcher, SearchStep};
+use std::str::FromStr;
+
+use program::{Program, MatchEngine};
+use syntax;
+
+const REPLACE_EXPAND: &'static str = r"(?x)
+  (?P<before>^|\b|[^$]) # Ignore `$$name`.
+  \$
+  (?P<name> # Match the actual capture name. Can be...
+    [0-9]+  # A sequence of digits (for indexed captures), or...
+    |
+    [_a-zA-Z][_0-9a-zA-Z]* # A name for named captures.
+  )
+";
+
+/// Type alias for representing capture indices.
+pub type CaptureIdxs = [Option<usize>];
+
+/// Escapes all regular expression meta characters in `text`.
+///
+/// The string returned may be safely used as a literal in a regular
+/// expression.
+pub fn quote(text: &str) -> String {
+    let mut quoted = String::with_capacity(text.len());
+    for c in text.chars() {
+        if syntax::is_punct(c) {
+            quoted.push('\\')
+        }
+        quoted.push(c);
+    }
+    quoted
+}
+
+/// Tests if the given regular expression matches somewhere in the text given.
+///
+/// If there was a problem compiling the regular expression, an error is
+/// returned.
+///
+/// To find submatches, split or replace text, you'll need to compile an
+/// expression first.
+pub fn is_match(regex: &str, text: &str) -> Result<bool, Error> {
+    Regex::new(regex).map(|r| r.is_match(text))
+}
+
+/// An error that occurred during parsing or compiling a regular expression.
+#[derive(Debug)]
+pub enum Error {
+    /// A syntax error.
+    Syntax(syntax::Error),
+    /// The compiled program exceeded the set size limit.
+    /// The argument is the size limit imposed.
+    CompiledTooBig(usize),
+    /// Hints that destructuring should not be exhaustive.
+    ///
+    /// This enum may grow additional variants, so this makes sure clients
+    /// don't count on exhaustive matching. (Otherwise, adding a new variant
+    /// could break existing code.)
+    #[doc(hidden)]
+    __Nonexhaustive,
+}
+
+impl ::std::error::Error for Error {
+    fn description(&self) -> &str {
+        match *self {
+            Error::Syntax(ref err) => err.description(),
+            Error::CompiledTooBig(_) => "compiled program too big",
+            Error::__Nonexhaustive => unreachable!(),
+        }
+    }
+
+    fn cause(&self) -> Option<&::std::error::Error> {
+        match *self {
+            Error::Syntax(ref err) => Some(err),
+            _ => None,
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Error::Syntax(ref err) => err.fmt(f),
+            Error::CompiledTooBig(limit) => {
+                write!(f, "Compiled regex exceeds size limit of {} bytes.",
+                       limit)
+            }
+            Error::__Nonexhaustive => unreachable!(),
+        }
+    }
+}
+
+impl From<syntax::Error> for Error {
+    fn from(err: syntax::Error) -> Error {
+        Error::Syntax(err)
+    }
+}
+
+/// A compiled regular expression
+///
+/// It is represented as either a sequence of bytecode instructions (dynamic)
+/// or as a specialized Rust function (native). It can be used to search, split
+/// or replace text. All searching is done with an implicit `.*?` at the
+/// beginning and end of an expression. To force an expression to match the
+/// whole string (or a prefix or a suffix), you must use an anchor like `^` or
+/// `$` (or `\A` and `\z`).
+///
+/// While this crate will handle Unicode strings (whether in the regular
+/// expression or in the search text), all positions returned are **byte
+/// indices**. Every byte index is guaranteed to be at a Unicode code point
+/// boundary.
+///
+/// The lifetimes `'r` and `'t` in this crate correspond to the lifetime of a
+/// compiled regular expression and text to search, respectively.
+///
+/// The only methods that allocate new strings are the string replacement
+/// methods. All other methods (searching and splitting) return borrowed
+/// pointers into the string given.
+///
+/// # Examples
+///
+/// Find the location of a US phone number:
+///
+/// ```rust
+/// # use regex::Regex;
+/// let re = Regex::new("[0-9]{3}-[0-9]{3}-[0-9]{4}").unwrap();
+/// assert_eq!(re.find("phone: 111-222-3333"), Some((7, 19)));
+/// ```
+///
+/// # Using the `std::str::StrExt` methods with `Regex`
+///
+/// > **Note**: This section requires that this crate is currently compiled with
+/// >           the `pattern` Cargo feature enabled.
+///
+/// Since `Regex` implements `Pattern`, you can use regexes with methods
+/// defined on `std::str::StrExt`. For example, `is_match`, `find`, `find_iter`
+/// and `split` can be replaced with `StrExt::contains`, `StrExt::find`,
+/// `StrExt::match_indices` and `StrExt::split`.
+///
+/// Here are some examples:
+///
+/// ```rust,ignore
+/// # use regex::Regex;
+/// let re = Regex::new(r"\d+").unwrap();
+/// let haystack = "a111b222c";
+///
+/// assert!(haystack.contains(&re));
+/// assert_eq!(haystack.find(&re), Some(1));
+/// assert_eq!(haystack.match_indices(&re).collect::<Vec<_>>(),
+///            vec![(1, 4), (5, 8)]);
+/// assert_eq!(haystack.split(&re).collect::<Vec<_>>(), vec!["a", "b", "c"]);
+/// ```
+#[derive(Clone)]
+pub enum Regex {
+    // The representation of `Regex` is exported to support the `regex!`
+    // syntax extension. Do not rely on it.
+    //
+    // See the comments for the `program` module in `lib.rs` for a more
+    // detailed explanation for what `regex!` requires.
+    #[doc(hidden)]
+    Dynamic(Program),
+    #[doc(hidden)]
+    Native(ExNative),
+}
+
+#[doc(hidden)]
+pub struct ExNative {
+    #[doc(hidden)]
+    pub original: &'static str,
+    #[doc(hidden)]
+    pub names: &'static &'static [Option<&'static str>],
+    #[doc(hidden)]
+    pub prog: fn(&mut CaptureIdxs, &str, usize) -> bool,
+}
+
+impl Copy for ExNative {}
+
+impl Clone for ExNative {
+    fn clone(&self) -> ExNative {
+        *self
+    }
+}
+
+impl fmt::Display for Regex {
+    /// Shows the original regular expression.
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.as_str())
+    }
+}
+
+impl fmt::Debug for Regex {
+    /// Shows the original regular expression.
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
+/// Equality comparison is based on the original string. It is possible that
+/// different regular expressions have the same matching behavior, but are
+/// still compared unequal. For example, `\d+` and `\d\d*` match the same set
+/// of strings, but are not considered equal.
+impl PartialEq for Regex {
+    fn eq(&self, other: &Regex) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl Eq for Regex {}
+
+impl FromStr for Regex {
+    type Err = Error;
+
+    /// Attempts to parse a string into a regular expression
+    fn from_str(s: &str) -> Result<Regex, Error> {
+        Regex::new(s)
+    }
+}
+
+impl Regex {
+    /// Compiles a dynamic regular expression. Once compiled, it can be
+    /// used repeatedly to search, split or replace text in a string.
+    ///
+    /// If an invalid expression is given, then an error is returned.
+    pub fn new(re: &str) -> Result<Regex, Error> {
+        Regex::with_size_limit(10 * (1 << 20), re)
+    }
+
+    /// Compiles a dynamic regular expression with the given size limit.
+    ///
+    /// The size limit is applied to the size of the *compiled* data structure.
+    /// If the data structure exceeds the size given, then an error is
+    /// returned.
+    ///
+    /// The default size limit used in `new` is 10MB.
+    pub fn with_size_limit(size: usize, re: &str) -> Result<Regex, Error> {
+        Regex::with_engine(None, size, re)
+    }
+
+    /// Compiles a dynamic regular expression and uses given matching engine.
+    ///
+    /// This is exposed for use in testing and shouldn't be used by clients.
+    /// Instead, the regex program should choose the correct matching engine
+    /// to use automatically. (Based on the regex, the size of the input and
+    /// the type of search.)
+    ///
+    /// A value of `None` means that the engine is automatically selected,
+    /// which is the default behavior.
+    ///
+    /// **WARNING**: Passing an unsuitable engine for the given regex/input
+    /// could lead to bad things. (Not unsafe things, but panics, incorrect
+    /// matches and large memory use are all things that could happen.)
+    #[doc(hidden)]
+    pub fn with_engine(
+        engine: Option<MatchEngine>,
+        size: usize,
+        re: &str,
+    ) -> Result<Regex, Error> {
+        Program::new(engine, size, re).map(Regex::Dynamic)
+    }
+
+
+    /// Returns true if and only if the regex matches the string given.
+    ///
+    /// # Example
+    ///
+    /// Test if some text contains at least one word with exactly 13
+    /// characters:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let text = "I categorically deny having triskaidekaphobia.";
+    /// assert!(Regex::new(r"\b\w{13}\b").unwrap().is_match(text));
+    /// # }
+    /// ```
+    pub fn is_match(&self, text: &str) -> bool {
+        exec(self, &mut [], text, 0)
+    }
+
+    /// Returns the start and end byte range of the leftmost-first match in
+    /// `text`. If no match exists, then `None` is returned.
+    ///
+    /// Note that this should only be used if you want to discover the position
+    /// of the match. Testing the existence of a match is faster if you use
+    /// `is_match`.
+    ///
+    /// # Example
+    ///
+    /// Find the start and end location of the first word with exactly 13
+    /// characters:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let text = "I categorically deny having triskaidekaphobia.";
+    /// let pos = Regex::new(r"\b\w{13}\b").unwrap().find(text);
+    /// assert_eq!(pos, Some((2, 15)));
+    /// # }
+    /// ```
+    pub fn find(&self, text: &str) -> Option<(usize, usize)> {
+        let mut caps = [None, None];
+        if exec(self, &mut caps, text, 0) {
+            Some((caps[0].unwrap(), caps[1].unwrap()))
+        } else {
+            None
+        }
+    }
+
+    /// Returns an iterator for each successive non-overlapping match in
+    /// `text`, returning the start and end byte indices with respect to
+    /// `text`.
+    ///
+    /// # Example
+    ///
+    /// Find the start and end location of every word with exactly 13
+    /// characters:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let text = "Retroactively relinquishing remunerations is reprehensible.";
+    /// for pos in Regex::new(r"\b\w{13}\b").unwrap().find_iter(text) {
+    ///     println!("{:?}", pos);
+    /// }
+    /// // Output:
+    /// // (0, 13)
+    /// // (14, 27)
+    /// // (28, 41)
+    /// // (45, 58)
+    /// # }
+    /// ```
+    pub fn find_iter<'r, 't>(&'r self, text: &'t str) -> FindMatches<'r, 't> {
+        FindMatches {
+            re: self,
+            search: text,
+            last_end: 0,
+            last_match: None,
+        }
+    }
+
+    /// Returns the capture groups corresponding to the leftmost-first
+    /// match in `text`. Capture group `0` always corresponds to the entire
+    /// match. If no match is found, then `None` is returned.
+    ///
+    /// You should only use `captures` if you need access to submatches.
+    /// Otherwise, `find` is faster for discovering the location of the overall
+    /// match.
+    ///
+    /// # Examples
+    ///
+    /// Say you have some text with movie names and their release years,
+    /// like "'Citizen Kane' (1941)". It'd be nice if we could search for text
+    /// looking like that, while also extracting the movie name and its release
+    /// year separately.
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new(r"'([^']+)'\s+\((\d{4})\)").unwrap();
+    /// let text = "Not my favorite movie: 'Citizen Kane' (1941).";
+    /// let caps = re.captures(text).unwrap();
+    /// assert_eq!(caps.at(1), Some("Citizen Kane"));
+    /// assert_eq!(caps.at(2), Some("1941"));
+    /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)"));
+    /// # }
+    /// ```
+    ///
+    /// Note that the full match is at capture group `0`. Each subsequent
+    /// capture group is indexed by the order of its opening `(`.
+    ///
+    /// We can make this example a bit clearer by using *named* capture groups:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
+    ///                .unwrap();
+    /// let text = "Not my favorite movie: 'Citizen Kane' (1941).";
+    /// let caps = re.captures(text).unwrap();
+    /// assert_eq!(caps.name("title"), Some("Citizen Kane"));
+    /// assert_eq!(caps.name("year"), Some("1941"));
+    /// assert_eq!(caps.at(0), Some("'Citizen Kane' (1941)"));
+    /// # }
+    /// ```
+    ///
+    /// Here we name the capture groups, which we can access with the `name`
+    /// method. Note that the named capture groups are still accessible with
+    /// `at`.
+    ///
+    /// The `0`th capture group is always unnamed, so it must always be
+    /// accessed with `at(0)`.
+    pub fn captures<'t>(&self, text: &'t str) -> Option<Captures<'t>> {
+        let mut caps = self.alloc_captures();
+        if exec(self, &mut caps, text, 0) {
+            Some(Captures::new(self, text, caps))
+        } else {
+            None
+        }
+    }
+
+    /// Returns an iterator over all the non-overlapping capture groups matched
+    /// in `text`. This is operationally the same as `find_iter` (except it
+    /// yields information about submatches).
+    ///
+    /// # Example
+    ///
+    /// We can use this to find all movie titles and their release years in
+    /// some text, where the movie is formatted like "'Title' (xxxx)":
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
+    ///                .unwrap();
+    /// let text = "'Citizen Kane' (1941), 'The Wizard of Oz' (1939), 'M' (1931).";
+    /// for caps in re.captures_iter(text) {
+    ///     println!("Movie: {:?}, Released: {:?}", caps.name("title"), caps.name("year"));
+    /// }
+    /// // Output:
+    /// // Movie: Citizen Kane, Released: 1941
+    /// // Movie: The Wizard of Oz, Released: 1939
+    /// // Movie: M, Released: 1931
+    /// # }
+    /// ```
+    pub fn captures_iter<'r, 't>(&'r self, text: &'t str)
+                                -> FindCaptures<'r, 't> {
+        FindCaptures {
+            re: self,
+            search: text,
+            last_match: None,
+            last_end: 0,
+        }
+    }
+
+    /// Returns an iterator of substrings of `text` delimited by a match
+    /// of the regular expression.
+    /// Namely, each element of the iterator corresponds to text that *isn't*
+    /// matched by the regular expression.
+    ///
+    /// This method will *not* copy the text given.
+    ///
+    /// # Example
+    ///
+    /// To split a string delimited by arbitrary amounts of spaces or tabs:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new(r"[ \t]+").unwrap();
+    /// let fields: Vec<&str> = re.split("a b \t  c\td    e").collect();
+    /// assert_eq!(fields, vec!("a", "b", "c", "d", "e"));
+    /// # }
+    /// ```
+    pub fn split<'r, 't>(&'r self, text: &'t str) -> RegexSplits<'r, 't> {
+        RegexSplits {
+            finder: self.find_iter(text),
+            last: 0,
+        }
+    }
+
+    /// Returns an iterator of at most `limit` substrings of `text` delimited
+    /// by a match of the regular expression. (A `limit` of `0` will return no
+    /// substrings.)
+    /// Namely, each element of the iterator corresponds to text that *isn't*
+    /// matched by the regular expression.
+    /// The remainder of the string that is not split will be the last element
+    /// in the iterator.
+    ///
+    /// This method will *not* copy the text given.
+    ///
+    /// # Example
+    ///
+    /// Get the first two words in some text:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new(r"\W+").unwrap();
+    /// let fields: Vec<&str> = re.splitn("Hey! How are you?", 3).collect();
+    /// assert_eq!(fields, vec!("Hey", "How", "are you?"));
+    /// # }
+    /// ```
+    pub fn splitn<'r, 't>(&'r self, text: &'t str, limit: usize)
+                         -> RegexSplitsN<'r, 't> {
+        RegexSplitsN {
+            splits: self.split(text),
+            cur: 0,
+            limit: limit,
+        }
+    }
+
+    /// Replaces the leftmost-first match with the replacement provided.
+    /// The replacement can be a regular string (where `$N` and `$name` are
+    /// expanded to match capture groups) or a function that takes the matches'
+    /// `Captures` and returns the replaced string.
+    ///
+    /// If no match is found, then a copy of the string is returned unchanged.
+    ///
+    /// # Examples
+    ///
+    /// Note that this function is polymorphic with respect to the replacement.
+    /// In typical usage, this can just be a normal string:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new("[^01]+").unwrap();
+    /// assert_eq!(re.replace("1078910", ""), "1010");
+    /// # }
+    /// ```
+    ///
+    /// But anything satisfying the `Replacer` trait will work. For example,
+    /// a closure of type `|&Captures| -> String` provides direct access to the
+    /// captures corresponding to a match. This allows one to access
+    /// submatches easily:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # use regex::Captures; fn main() {
+    /// let re = Regex::new(r"([^,\s]+),\s+(\S+)").unwrap();
+    /// let result = re.replace("Springsteen, Bruce", |caps: &Captures| {
+    ///     format!("{} {}", caps.at(2).unwrap_or(""), caps.at(1).unwrap_or(""))
+    /// });
+    /// assert_eq!(result, "Bruce Springsteen");
+    /// # }
+    /// ```
+    ///
+    /// But this is a bit cumbersome to use all the time. Instead, a simple
+    /// syntax is supported that expands `$name` into the corresponding capture
+    /// group. Here's the last example, but using this expansion technique
+    /// with named capture groups:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// let re = Regex::new(r"(?P<last>[^,\s]+),\s+(?P<first>\S+)").unwrap();
+    /// let result = re.replace("Springsteen, Bruce", "$first $last");
+    /// assert_eq!(result, "Bruce Springsteen");
+    /// # }
+    /// ```
+    ///
+    /// Note that using `$2` instead of `$first` or `$1` instead of `$last`
+    /// would produce the same result. To write a literal `$` use `$$`.
+    ///
+    /// Finally, sometimes you just want to replace a literal string with no
+    /// submatch expansion. This can be done by wrapping a string with
+    /// `NoExpand`:
+    ///
+    /// ```rust
+    /// # extern crate regex; use regex::Regex;
+    /// # fn main() {
+    /// use regex::NoExpand;
+    ///
+    /// let re = Regex::new(r"(?P<last>[^,\s]+),\s+(\S+)").unwrap();
+    /// let result = re.replace("Springsteen, Bruce", NoExpand("$2 $last"));
+    /// assert_eq!(result, "$2 $last");
+    /// # }
+    /// ```
+    pub fn replace<R: Replacer>(&self, text: &str, rep: R) -> String {
+        self.replacen(text, 1, rep)
+    }
+
+    /// Replaces all non-overlapping matches in `text` with the
+    /// replacement provided. This is the same as calling `replacen` with
+    /// `limit` set to `0`.
+    ///
+    /// See the documentation for `replace` for details on how to access
+    /// submatches in the replacement string.
+    pub fn replace_all<R: Replacer>(&self, text: &str, rep: R) -> String {
+        self.replacen(text, 0, rep)
+    }
+
+    /// Replaces at most `limit` non-overlapping matches in `text` with the
+    /// replacement provided. If `limit` is 0, then all non-overlapping matches
+    /// are replaced.
+    ///
+    /// See the documentation for `replace` for details on how to access
+    /// submatches in the replacement string.
+    pub fn replacen<R: Replacer>
+                   (&self, text: &str, limit: usize, mut rep: R) -> String {
+        let mut new = String::with_capacity(text.len());
+        let mut last_match = 0;
+
+        if rep.no_expand().is_some() {
+            // borrow checker pains. `rep` is borrowed mutably in the `else`
+            // branch below.
+            let rep = rep.no_expand().unwrap();
+            for (i, (s, e)) in self.find_iter(text).enumerate() {
+                if limit > 0 && i >= limit {
+                    break
+                }
+                new.push_str(&text[last_match..s]);
+                new.push_str(&rep);
+                last_match = e;
+            }
+        } else {
+            for (i, cap) in self.captures_iter(text).enumerate() {
+                if limit > 0 && i >= limit {
+                    break
+                }
+                // unwrap on 0 is OK because captures only reports matches
+                let (s, e) = cap.pos(0).unwrap();
+                new.push_str(&text[last_match..s]);
+                new.push_str(&rep.reg_replace(&cap));
+                last_match = e;
+            }
+        }
+        new.push_str(&text[last_match..]);
+        new
+    }
+
+    /// Returns the original string of this regex.
+    pub fn as_str<'a>(&'a self) -> &'a str {
+        match *self {
+            Regex::Dynamic(Program { ref original, .. }) => original,
+            Regex::Native(ExNative { ref original, .. }) => original,
+        }
+    }
+
+    #[doc(hidden)]
+    pub fn names_iter<'a>(&'a self) -> NamesIter<'a> {
+        match *self {
+            Regex::Native(ref n) => NamesIter::Native(n.names.iter()),
+            Regex::Dynamic(ref d) => NamesIter::Dynamic(d.cap_names.iter())
+        }
+    }
+
+    fn names_len(&self) -> usize {
+        match *self {
+            Regex::Native(ref n) => n.names.len(),
+            Regex::Dynamic(ref d) => d.cap_names.len()
+        }
+    }
+
+    fn alloc_captures(&self) -> Vec<Option<usize>> {
+        match *self {
+            Regex::Native(ref n) => vec![None; 2 * n.names.len()],
+            Regex::Dynamic(ref d) => d.alloc_captures(),
+        }
+    }
+}
+
+pub enum NamesIter<'a> {
+    Native(::std::slice::Iter<'a, Option<&'static str>>),
+    Dynamic(::std::slice::Iter<'a, Option<String>>)
+}
+
+impl<'a> Iterator for NamesIter<'a> {
+    type Item=Option<String>;
+
+    fn next(&mut self) -> Option<Option<String>> {
+        match *self {
+            NamesIter::Native(ref mut i) =>
+                i.next().map(|x| x.map(|s| s.to_owned())),
+            NamesIter::Dynamic(ref mut i) =>
+                i.next().map(|x| x.as_ref().map(|s| s.to_owned())),
+        }
+    }
+}
+
+/// NoExpand indicates literal string replacement.
+///
+/// It can be used with `replace` and `replace_all` to do a literal
+/// string replacement without expanding `$name` to their corresponding
+/// capture groups.
+///
+/// `'r` is the lifetime of the literal text.
+pub struct NoExpand<'t>(pub &'t str);
+
+/// Replacer describes types that can be used to replace matches in a string.
+pub trait Replacer {
+    /// Returns a possibly owned string that is used to replace the match
+    /// corresponding to the `caps` capture group.
+    ///
+    /// The `'a` lifetime refers to the lifetime of a borrowed string when
+    /// a new owned string isn't needed (e.g., for `NoExpand`).
+    fn reg_replace<'a>(&'a mut self, caps: &Captures) -> Cow<'a, str>;
+
+    /// Returns a possibly owned string that never needs expansion.
+    fn no_expand<'a>(&'a mut self) -> Option<Cow<'a, str>> { None }
+}
+
+impl<'t> Replacer for NoExpand<'t> {
+    fn reg_replace<'a>(&'a mut self, _: &Captures) -> Cow<'a, str> {
+        self.0.into()
+    }
+
+    fn no_expand<'a>(&'a mut self) -> Option<Cow<'a, str>> {
+        Some(self.0.into())
+    }
+}
+
+impl<'t> Replacer for &'t str {
+    fn reg_replace<'a>(&'a mut self, caps: &Captures) -> Cow<'a, str> {
+        caps.expand(*self).into()
+    }
+
+    fn no_expand<'a>(&'a mut self) -> Option<Cow<'a, str>> {
+        let re = Regex::new(REPLACE_EXPAND).unwrap();
+        if !re.is_match(self) {
+            Some((*self).into())
+        } else {
+            None
+        }
+    }
+}
+
+impl<F> Replacer for F where F: FnMut(&Captures) -> String {
+    fn reg_replace<'a>(&'a mut self, caps: &Captures) -> Cow<'a, str> {
+        (*self)(caps).into()
+    }
+}
+
+/// Yields all substrings delimited by a regular expression match.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the string being split.
+pub struct RegexSplits<'r, 't> {
+    finder: FindMatches<'r, 't>,
+    last: usize,
+}
+
+impl<'r, 't> Iterator for RegexSplits<'r, 't> {
+    type Item = &'t str;
+
+    fn next(&mut self) -> Option<&'t str> {
+        let text = self.finder.search;
+        match self.finder.next() {
+            None => {
+                if self.last >= text.len() {
+                    None
+                } else {
+                    let s = &text[self.last..];
+                    self.last = text.len();
+                    Some(s)
+                }
+            }
+            Some((s, e)) => {
+                let matched = &text[self.last..s];
+                self.last = e;
+                Some(matched)
+            }
+        }
+    }
+}
+
+/// Yields at most `N` substrings delimited by a regular expression match.
+///
+/// The last substring will be whatever remains after splitting.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the string being split.
+pub struct RegexSplitsN<'r, 't> {
+    splits: RegexSplits<'r, 't>,
+    cur: usize,
+    limit: usize,
+}
+
+impl<'r, 't> Iterator for RegexSplitsN<'r, 't> {
+    type Item = &'t str;
+
+    fn next(&mut self) -> Option<&'t str> {
+        let text = self.splits.finder.search;
+        if self.cur >= self.limit {
+            None
+        } else {
+            self.cur += 1;
+            if self.cur >= self.limit {
+                Some(&text[self.splits.last..])
+            } else {
+                self.splits.next()
+            }
+        }
+    }
+}
+
+/// Captures represents a group of captured strings for a single match.
+///
+/// The 0th capture always corresponds to the entire match. Each subsequent
+/// index corresponds to the next capture group in the regex.
+/// If a capture group is named, then the matched string is *also* available
+/// via the `name` method. (Note that the 0th capture is always unnamed and so
+/// must be accessed with the `at` method.)
+///
+/// Positions returned from a capture group are always byte indices.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct Captures<'t> {
+    text: &'t str,
+    locs: Vec<Option<usize>>,
+    named: Option<HashMap<String, usize>>,
+}
+
+impl<'t> Captures<'t> {
+    fn new(
+        re: &Regex,
+        search: &'t str,
+        locs: Vec<Option<usize>>,
+    ) -> Captures<'t> {
+        let named =
+            if re.names_len() == 0 {
+                None
+            } else {
+                let mut named = HashMap::new();
+                for (i, name) in re.names_iter().enumerate() {
+                    if let Some(name) = name {
+                        named.insert(name, i);
+                    }
+                }
+                Some(named)
+            };
+        Captures {
+            text: search,
+            locs: locs,
+            named: named,
+        }
+    }
+
+    /// Returns the start and end positions of the Nth capture group.
+    /// Returns `None` if `i` is not a valid capture group or if the capture
+    /// group did not match anything.
+    /// The positions returned are *always* byte indices with respect to the
+    /// original string matched.
+    pub fn pos(&self, i: usize) -> Option<(usize, usize)> {
+        let (s, e) = (i * 2, i * 2 + 1);
+        if e >= self.locs.len() || self.locs[s].is_none() {
+            // VM guarantees that each pair of locations are both Some or None.
+            return None
+        }
+        Some((self.locs[s].unwrap(), self.locs[e].unwrap()))
+    }
+
+    /// Returns the matched string for the capture group `i`.  If `i` isn't
+    /// a valid capture group or didn't match anything, then `None` is
+    /// returned.
+    pub fn at(&self, i: usize) -> Option<&'t str> {
+        match self.pos(i) {
+            None => None,
+            Some((s, e)) => Some(&self.text[s..e])
+        }
+    }
+
+    /// Returns the matched string for the capture group named `name`.  If
+    /// `name` isn't a valid capture group or didn't match anything, then
+    /// `None` is returned.
+    pub fn name(&self, name: &str) -> Option<&'t str> {
+        match self.named {
+            None => None,
+            Some(ref h) => {
+                match h.get(name) {
+                    None => None,
+                    Some(i) => self.at(*i),
+                }
+            }
+        }
+    }
+
+    /// Creates an iterator of all the capture groups in order of appearance
+    /// in the regular expression.
+    pub fn iter(&'t self) -> SubCaptures<'t> {
+        SubCaptures { idx: 0, caps: self, }
+    }
+
+    /// Creates an iterator of all the capture group positions in order of
+    /// appearance in the regular expression. Positions are byte indices
+    /// in terms of the original string matched.
+    pub fn iter_pos(&'t self) -> SubCapturesPos<'t> {
+        SubCapturesPos { idx: 0, caps: self, }
+    }
+
+    /// Creates an iterator of all named groups as an tuple with the group
+    /// name and the value. The iterator returns these values in arbitrary
+    /// order.
+    pub fn iter_named(&'t self) -> SubCapturesNamed<'t> {
+        SubCapturesNamed { caps: self, inner: self.named.as_ref().map(|n| n.iter()) }
+    }
+
+    /// Expands all instances of `$name` in `text` to the corresponding capture
+    /// group `name`.
+    ///
+    /// `name` may be an integer corresponding to the index of the
+    /// capture group (counted by order of opening parenthesis where `0` is the
+    /// entire match) or it can be a name (consisting of letters, digits or
+    /// underscores) corresponding to a named capture group.
+    ///
+    /// If `name` isn't a valid capture group (whether the name doesn't exist or
+    /// isn't a valid index), then it is replaced with the empty string.
+    ///
+    /// To write a literal `$` use `$$`.
+    pub fn expand(&self, text: &str) -> String {
+        // How evil can you get?
+        let re = Regex::new(REPLACE_EXPAND).unwrap();
+        let text = re.replace_all(text, |refs: &Captures| -> String {
+            let before = refs.name("before").unwrap_or("");
+            let name = refs.name("name").unwrap_or("");
+            format!("{}{}", before, match name.parse::<usize>() {
+                Err(_) => self.name(name).unwrap_or("").to_string(),
+                Ok(i) => self.at(i).unwrap_or("").to_string(),
+            })
+        });
+        let re = Regex::new(r"\$\$").unwrap();
+        re.replace_all(&text, NoExpand("$"))
+    }
+
+    /// Returns the number of captured groups.
+    #[inline]
+    pub fn len(&self) -> usize { self.locs.len() / 2 }
+
+    /// Returns true if and only if there are no captured groups.
+    #[inline]
+    pub fn is_empty(&self) -> bool { self.len() == 0 }
+}
+
+/// An iterator over capture groups for a particular match of a regular
+/// expression.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct SubCaptures<'t> {
+    idx: usize,
+    caps: &'t Captures<'t>,
+}
+
+impl<'t> Iterator for SubCaptures<'t> {
+    type Item = Option<&'t str>;
+
+    fn next(&mut self) -> Option<Option<&'t str>> {
+        if self.idx < self.caps.len() {
+            self.idx += 1;
+            Some(self.caps.at(self.idx - 1))
+        } else {
+            None
+        }
+    }
+}
+
+/// An iterator over capture group positions for a particular match of a
+/// regular expression.
+///
+/// Positions are byte indices in terms of the original string matched.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct SubCapturesPos<'t> {
+    idx: usize,
+    caps: &'t Captures<'t>,
+}
+
+impl<'t> Iterator for SubCapturesPos<'t> {
+    type Item = Option<(usize, usize)>;
+
+    fn next(&mut self) -> Option<Option<(usize, usize)>> {
+        if self.idx < self.caps.len() {
+            self.idx += 1;
+            Some(self.caps.pos(self.idx - 1))
+        } else {
+            None
+        }
+    }
+}
+
+/// An Iterator over named capture groups as a tuple with the group
+/// name and the value.
+///
+/// `'t` is the lifetime of the matched text.
+pub struct SubCapturesNamed<'t>{
+    caps: &'t Captures<'t>,
+    inner: Option<Iter<'t, String, usize>>,
+}
+
+impl<'t> Iterator for SubCapturesNamed<'t> {
+    type Item = (&'t str, Option<&'t str>);
+
+    fn next(&mut self) -> Option<(&'t str, Option<&'t str>)> {
+        match self.inner.as_mut().map(|it| it.next()).unwrap_or(None) {
+            Some((name, pos)) => Some((name, self.caps.at(*pos))),
+            None => None
+        }
+    }
+}
+
+/// An iterator that yields all non-overlapping capture groups matching a
+/// particular regular expression.
+///
+/// The iterator stops when no more matches can be found.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the matched string.
+pub struct FindCaptures<'r, 't> {
+    re: &'r Regex,
+    search: &'t str,
+    last_match: Option<usize>,
+    last_end: usize,
+}
+
+impl<'r, 't> Iterator for FindCaptures<'r, 't> {
+    type Item = Captures<'t>;
+
+    fn next(&mut self) -> Option<Captures<'t>> {
+        if self.last_end > self.search.len() {
+            return None
+        }
+
+        let mut caps = self.re.alloc_captures();
+        if !exec(self.re, &mut caps, self.search, self.last_end) {
+            return None
+        }
+        let (s, e) = (caps[0].unwrap(), caps[1].unwrap());
+
+        // Don't accept empty matches immediately following a match.
+        // i.e., no infinite loops please.
+        if e == s && Some(self.last_end) == self.last_match {
+            if self.last_end >= self.search.len() {
+                return None;
+            }
+            self.last_end += self.search[self.last_end..].chars()
+                                 .next().unwrap().len_utf8();
+            return self.next()
+        }
+        self.last_end = e;
+        self.last_match = Some(self.last_end);
+        Some(Captures::new(self.re, self.search, caps))
+    }
+}
+
+/// An iterator over all non-overlapping matches for a particular string.
+///
+/// The iterator yields a tuple of integers corresponding to the start and end
+/// of the match. The indices are byte offsets. The iterator stops when no more
+/// matches can be found.
+///
+/// `'r` is the lifetime of the compiled expression and `'t` is the lifetime
+/// of the matched string.
+pub struct FindMatches<'r, 't> {
+    re: &'r Regex,
+    search: &'t str,
+    last_match: Option<usize>,
+    last_end: usize,
+}
+
+impl<'r, 't> Iterator for FindMatches<'r, 't> {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<(usize, usize)> {
+        if self.last_end > self.search.len() {
+            return None
+        }
+
+        let mut caps = [None, None];
+        if !exec(self.re, &mut caps, self.search, self.last_end) {
+            return None;
+        }
+        let (s, e) = (caps[0].unwrap(), caps[1].unwrap());
+
+        // Don't accept empty matches immediately following a match.
+        // i.e., no infinite loops please.
+        if e == s && Some(self.last_end) == self.last_match {
+            if self.last_end >= self.search.len() {
+                return None;
+            }
+            self.last_end += self.search[self.last_end..].chars()
+                                 .next().unwrap().len_utf8();
+            return self.next()
+        }
+        self.last_end = e;
+        self.last_match = Some(self.last_end);
+        Some((s, e))
+    }
+}
+
+#[cfg(feature = "pattern")]
+pub struct RegexSearcher<'r, 't> {
+    it: FindMatches<'r, 't>,
+    last_step_end: usize,
+    next_match: Option<(usize, usize)>,
+}
+
+#[cfg(feature = "pattern")]
+impl<'r, 't> Pattern<'t> for &'r Regex {
+    type Searcher = RegexSearcher<'r, 't>;
+
+    fn into_searcher(self, haystack: &'t str) -> RegexSearcher<'r, 't> {
+        RegexSearcher {
+            it: self.find_iter(haystack),
+            last_step_end: 0,
+            next_match: None,
+        }
+    }
+}
+
+#[cfg(feature = "pattern")]
+unsafe impl<'r, 't> Searcher<'t> for RegexSearcher<'r, 't> {
+    #[inline]
+    fn haystack(&self) -> &'t str {
+        self.it.search
+    }
+
+    #[inline]
+    fn next(&mut self) -> SearchStep {
+        if let Some((s, e)) = self.next_match {
+            self.next_match = None;
+            self.last_step_end = e;
+            return SearchStep::Match(s, e);
+        }
+        match self.it.next() {
+            None => {
+                if self.last_step_end < self.haystack().len() {
+                    let last = self.last_step_end;
+                    self.last_step_end = self.haystack().len();
+                    SearchStep::Reject(last, self.haystack().len())
+                } else {
+                    SearchStep::Done
+                }
+            }
+            Some((s, e)) => {
+                if s == self.last_step_end {
+                    self.last_step_end = e;
+                    SearchStep::Match(s, e)
+                } else {
+                    self.next_match = Some((s, e));
+                    let last = self.last_step_end;
+                    self.last_step_end = s;
+                    SearchStep::Reject(last, s)
+                }
+            }
+        }
+    }
+}
+
+fn exec(re: &Regex, caps: &mut CaptureIdxs, text: &str, start: usize) -> bool {
+    match *re {
+        Regex::Native(ExNative { ref prog, .. }) => (*prog)(caps, text, start),
+        Regex::Dynamic(ref prog) => prog.exec(caps, text, start),
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex_macros/lib.rs.html b/src/regex_macros/lib.rs.html new file mode 100644 index 0000000..6a743da --- /dev/null +++ b/src/regex_macros/lib.rs.html @@ -0,0 +1,1215 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
  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
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This crate provides the `regex!` macro. Its use is documented in the
+//! `regex` crate.
+
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+       html_root_url = "http://doc.rust-lang.org/nightly/")]
+
+#![feature(plugin_registrar, quote, rustc_private)]
+
+extern crate regex;
+extern crate syntax;
+extern crate rustc;
+
+use syntax::ast;
+use syntax::codemap;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
+use syntax::parse::token;
+use syntax::print::pprust;
+use syntax::fold::Folder;
+use syntax::ptr::P;
+
+use rustc::plugin::Registry;
+
+use regex::Regex;
+use regex::internal::{
+    Inst, LookInst, OneChar, CharRanges, Program, Dynamic, Native,
+};
+
+/// For the `regex!` syntax extension. Do not use.
+#[plugin_registrar]
+#[doc(hidden)]
+pub fn plugin_registrar(reg: &mut Registry) {
+    reg.register_macro("regex", native);
+}
+
+/// Generates specialized code for the Pike VM for a particular regular
+/// expression.
+///
+/// There are two primary differences between the code generated here and the
+/// general code in vm.rs.
+///
+/// 1. All heap allocation is removed. Sized vector types are used instead.
+///    Care must be taken to make sure that these vectors are not copied
+///    gratuitously. (If you're not sure, run the benchmarks. They will yell
+///    at you if you do.)
+/// 2. The main `match instruction { ... }` expressions are replaced with more
+///    direct `match pc { ... }`. The generators can be found in
+///    `step_insts` and `add_insts`.
+///
+/// It is strongly recommended to read the dynamic implementation in vm.rs
+/// first before trying to understand the code generator. The implementation
+/// strategy is identical and vm.rs has comments and will be easier to follow.
+fn native(cx: &mut ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree])
+          -> Box<MacResult+'static> {
+    let regex = match parse(cx, tts) {
+        Some(r) => r,
+        // error is logged in 'parse' with cx.span_err
+        None => return DummyResult::any(sp),
+    };
+    // We use the largest possible size limit because this is happening at
+    // compile time. We trust the programmer.
+    let re = match Regex::with_size_limit(::std::usize::MAX, &regex) {
+        Ok(re) => re,
+        Err(err) => {
+            cx.span_err(sp, &err.to_string());
+            return DummyResult::any(sp)
+        }
+    };
+    let prog = match re {
+        Dynamic(ref prog) => prog.clone(),
+        Native(_) => unreachable!(),
+    };
+
+    let mut gen = NfaGen {
+        cx: &*cx, sp: sp, prog: prog,
+        names: re.names_iter().collect(), original: re.as_str().to_string(),
+    };
+    MacEager::expr(gen.code())
+}
+
+struct NfaGen<'a> {
+    cx: &'a ExtCtxt<'a>,
+    sp: codemap::Span,
+    prog: Program,
+    names: Vec<Option<String>>,
+    original: String,
+}
+
+impl<'a> NfaGen<'a> {
+    fn code(&mut self) -> P<ast::Expr> {
+        // Most or all of the following things are used in the quasiquoted
+        // expression returned.
+        let num_cap_locs = 2 * self.prog.num_captures();
+        let num_insts = self.prog.insts.len();
+        let cap_names = self.vec_expr(self.names.iter(),
+            &mut |cx, name| match *name {
+                Some(ref name) => {
+                    let name = &**name;
+                    quote_expr!(cx, Some($name))
+                }
+                None => cx.expr_none(self.sp),
+            }
+        );
+        let prefix_anchor = self.prog.anchored_begin;
+
+        // let prefix_lit = Rc::new(self.prog.prefix.as_bytes().to_vec());
+        // let prefix_bytes = self.cx.expr_lit(self.sp, ast::LitBinary(prefix_lit));
+
+        // let check_prefix = self.check_prefix();
+        let step_insts = self.step_insts();
+        let add_insts = self.add_insts();
+        let regex = &*self.original;
+
+        quote_expr!(self.cx, {
+// When `regex!` is bound to a name that is not used, we have to make sure
+// that dead_code warnings don't bubble up to the user from the generated
+// code. Therefore, we suppress them by allowing dead_code. The effect is that
+// the user is only warned about *their* unused variable/code, and not the
+// unused code generated by regex!. See #14185 for an example.
+#[allow(dead_code)]
+static CAP_NAMES: &'static [Option<&'static str>] = &$cap_names;
+
+#[allow(dead_code)]
+fn exec<'t>(
+    mut caps: &mut [Option<usize>],
+    input: &'t str,
+    start: usize,
+) -> bool {
+    #![allow(unused_imports)]
+    #![allow(unused_mut)]
+
+    use regex::internal::{Char, CharInput, InputAt, Input, Inst};
+
+    let input = CharInput::new(input);
+    let at = input.at(start);
+    return Nfa {
+        input: input,
+        ncaps: caps.len(),
+    }.exec(&mut NfaThreads::new(), &mut caps, at);
+
+    struct Nfa<'t> {
+        input: CharInput<'t>,
+        ncaps: usize,
+    }
+
+    impl<'t> Nfa<'t> {
+        #[allow(unused_variables)]
+        fn exec(
+            &mut self,
+            mut q: &mut NfaThreads,
+            mut caps: &mut [Option<usize>],
+            mut at: InputAt,
+        ) -> bool {
+            let mut matched = false;
+            let (mut clist, mut nlist) = (&mut q.clist, &mut q.nlist);
+            clist.empty(); nlist.empty();
+'LOOP:      loop {
+                if clist.size == 0 {
+                    if matched || (!at.is_beginning() && $prefix_anchor) {
+                        break;
+                    }
+                    // TODO: Prefix matching... Hmm.
+                    // Prefix matching now uses a DFA, so I think this is
+                    // going to require encoding that DFA statically.
+                }
+                if clist.size == 0 || (!$prefix_anchor && !matched) {
+                    self.add(clist, &mut caps, 0, at);
+                }
+                let at_next = self.input.at(at.next_pos());
+                for i in 0..clist.size {
+                    let pc = clist.pc(i);
+                    let tcaps = clist.caps(i);
+                    if self.step(nlist, caps, tcaps, pc, at, at_next) {
+                        matched = true;
+                        if caps.len() == 0 {
+                            break 'LOOP;
+                        }
+                        break;
+                    }
+                }
+                if at.char().is_none() {
+                    break;
+                }
+                at = at_next;
+                ::std::mem::swap(&mut clist, &mut nlist);
+                nlist.empty();
+            }
+            matched
+        }
+
+        // Sometimes `nlist` is never used (for empty regexes).
+        #[allow(unused_variables)]
+        #[inline]
+        fn step(
+            &self,
+            nlist: &mut Threads,
+            caps: &mut [Option<usize>],
+            thread_caps: &mut [Option<usize>],
+            pc: usize,
+            at: InputAt,
+            at_next: InputAt,
+        ) -> bool {
+            $step_insts;
+            false
+        }
+
+        fn add(
+            &self,
+            nlist: &mut Threads,
+            thread_caps: &mut [Option<usize>],
+            pc: usize,
+            at: InputAt,
+        ) {
+            if nlist.contains(pc) {
+                return;
+            }
+            let ti = nlist.add(pc);
+            $add_insts
+        }
+    }
+
+    struct NfaThreads {
+        clist: Threads,
+        nlist: Threads,
+    }
+
+    struct Threads {
+        dense: [Thread; $num_insts],
+        sparse: [usize; $num_insts],
+        size: usize,
+    }
+
+    struct Thread {
+        pc: usize,
+        caps: [Option<usize>; $num_cap_locs],
+    }
+
+    impl NfaThreads {
+        fn new() -> NfaThreads {
+            NfaThreads {
+                clist: Threads::new(),
+                nlist: Threads::new(),
+            }
+        }
+
+        fn swap(&mut self) {
+            ::std::mem::swap(&mut self.clist, &mut self.nlist);
+        }
+    }
+
+    impl Threads {
+        fn new() -> Threads {
+            Threads {
+                // These unsafe blocks are used for performance reasons, as it
+                // gives us a zero-cost initialization of a sparse set. The
+                // trick is described in more detail here:
+                // http://research.swtch.com/sparse
+                // The idea here is to avoid initializing threads that never
+                // need to be initialized, particularly for larger regexs with
+                // a lot of instructions.
+                dense: unsafe { ::std::mem::uninitialized() },
+                sparse: unsafe { ::std::mem::uninitialized() },
+                size: 0,
+            }
+        }
+
+        #[inline]
+        fn add(&mut self, pc: usize) -> usize {
+            let i = self.size;
+            self.dense[i].pc = pc;
+            self.sparse[pc] = i;
+            self.size += 1;
+            i
+        }
+
+        #[inline]
+        fn thread(&mut self, i: usize) -> &mut Thread {
+            &mut self.dense[i]
+        }
+
+        #[inline]
+        fn contains(&self, pc: usize) -> bool {
+            let s = self.sparse[pc];
+            s < self.size && self.dense[s].pc == pc
+        }
+
+        #[inline]
+        fn empty(&mut self) {
+            self.size = 0;
+        }
+
+        #[inline]
+        fn pc(&self, i: usize) -> usize {
+            self.dense[i].pc
+        }
+
+        #[inline]
+        fn caps<'r>(&'r mut self, i: usize) -> &'r mut [Option<usize>] {
+            &mut self.dense[i].caps
+        }
+    }
+}
+
+::regex::internal::Native(::regex::internal::ExNative {
+    original: $regex,
+    names: &CAP_NAMES,
+    prog: exec,
+})
+        })
+    }
+
+    // Generates code for the `add` method, which is responsible for adding
+    // zero-width states to the next queue of states to visit.
+    fn add_insts(&self) -> P<ast::Expr> {
+        let arms = self.prog.insts.iter().enumerate().map(|(pc, inst)| {
+            let nextpc = pc + 1;
+            let body = match *inst {
+                Inst::EmptyLook(LookInst::StartLine) => {
+                    quote_expr!(self.cx, {
+                        let prev = self.input.previous_at(at.pos());
+                        if prev.char().is_none() || prev.char() == '\n' {
+                            self.add(nlist, thread_caps, $nextpc, at);
+                        }
+                    })
+                }
+                Inst::EmptyLook(LookInst::EndLine) => {
+                    quote_expr!(self.cx, {
+                        if at.char().is_none() || at.char() == '\n' {
+                            self.add(nlist, thread_caps, $nextpc, at);
+                        }
+                    })
+                }
+                Inst::EmptyLook(LookInst::StartText) => {
+                    quote_expr!(self.cx, {
+                        let prev = self.input.previous_at(at.pos());
+                        if prev.char().is_none() {
+                            self.add(nlist, thread_caps, $nextpc, at);
+                        }
+                    })
+                }
+                Inst::EmptyLook(LookInst::EndText) => {
+                    quote_expr!(self.cx, {
+                        if at.char().is_none() {
+                            self.add(nlist, thread_caps, $nextpc, at);
+                        }
+                    })
+                }
+                Inst::EmptyLook(ref wbty) => {
+                    let m = if *wbty == LookInst::WordBoundary {
+                        quote_expr!(self.cx, { w1 ^ w2 })
+                    } else {
+                        quote_expr!(self.cx, { !(w1 ^ w2) })
+                    };
+                    quote_expr!(self.cx, {
+                        let prev = self.input.previous_at(at.pos());
+                        let w1 = prev.char().is_word_char();
+                        let w2 = at.char().is_word_char();
+                        if $m {
+                            self.add(nlist, thread_caps, $nextpc, at);
+                        }
+                    })
+                }
+                Inst::Save(slot) => quote_expr!(self.cx, {
+                    if $slot >= self.ncaps {
+                        self.add(nlist, thread_caps, $nextpc, at);
+                    } else {
+                        let old = thread_caps[$slot];
+                        thread_caps[$slot] = Some(at.pos());
+                        self.add(nlist, thread_caps, $nextpc, at);
+                        thread_caps[$slot] = old;
+                    }
+                }),
+                Inst::Jump(to) => quote_expr!(self.cx, {
+                    self.add(nlist, thread_caps, $to, at);
+                }),
+                Inst::Split(x, y) => quote_expr!(self.cx, {
+                    self.add(nlist, thread_caps, $x, at);
+                    self.add(nlist, thread_caps, $y, at);
+                }),
+                // For Match, OneChar, CharClass, Any, AnyNoNL
+                _ => quote_expr!(self.cx, {
+                    let mut t = &mut nlist.thread(ti);
+                    for (slot, val) in t.caps.iter_mut().zip(thread_caps.iter()) {
+                        *slot = *val;
+                    }
+                }),
+            };
+            self.arm_inst(pc, body)
+        }).collect::<Vec<ast::Arm>>();
+        self.match_insts(arms)
+    }
+
+    // Generates the code for the `step` method, which processes all states
+    // in the current queue that consume a single character.
+    fn step_insts(&self) -> P<ast::Expr> {
+        let arms = self.prog.insts.iter().enumerate().map(|(pc, inst)| {
+            let nextpc = pc + 1;
+            let body = match *inst {
+                Inst::Match => quote_expr!(self.cx, {
+                    for (slot, val) in caps.iter_mut().zip(thread_caps.iter()) {
+                        *slot = *val;
+                    }
+                    return true;
+                }),
+                Inst::Char(OneChar { c, casei }) => quote_expr!(self.cx, {
+                    if $c == at.char() || ($casei && $c == at.char().case_fold()) {
+                        self.add(nlist, thread_caps, $nextpc, at_next);
+                    }
+                    return false;
+                }),
+                Inst::Ranges(CharRanges { ref ranges, casei }) => {
+                    let match_class = self.match_class(ranges);
+                    quote_expr!(self.cx, {
+                        let mut c = at.char();
+                        if $casei {
+                            c = c.case_fold();
+                        }
+                        if let Some(c) = c.as_char() {
+                            if $match_class {
+                                self.add(nlist, thread_caps, $nextpc, at_next);
+                            }
+                        }
+                        return false;
+                    })
+                }
+                // EmptyLook, Save, Jump, Split
+                _ => quote_expr!(self.cx, { return false; }),
+            };
+            self.arm_inst(pc, body)
+        }).collect::<Vec<ast::Arm>>();
+
+        self.match_insts(arms)
+    }
+
+    // Translates a character class into a match expression.
+    // This avoids a binary search (and is hopefully replaced by a jump
+    // table).
+    fn match_class(&self, ranges: &[(char, char)]) -> P<ast::Expr> {
+        let mut arms = ranges.iter().map(|&(start, end)| {
+            let pat = self.cx.pat(
+                self.sp, ast::PatRange(
+                    quote_expr!(self.cx, $start), quote_expr!(self.cx, $end)));
+            self.cx.arm(self.sp, vec!(pat), quote_expr!(self.cx, true))
+        }).collect::<Vec<ast::Arm>>();
+
+        arms.push(self.wild_arm_expr(quote_expr!(self.cx, false)));
+        let match_on = quote_expr!(self.cx, c);
+        self.cx.expr_match(self.sp, match_on, arms)
+    }
+
+    // Generates code for checking a literal prefix of the search string.
+    // The code is only generated if the regex *has* a literal prefix.
+    // Otherwise, a no-op is returned.
+    // fn check_prefix(&self) -> P<ast::Expr> {
+        // if self.prog.prefixes.len() == 0 {
+            // self.empty_block()
+        // } else {
+            // quote_expr!(self.cx,
+                // if clist.size == 0 {
+                    // let haystack = &self.input.as_bytes()[self.ic..];
+                    // match find_prefix(prefix_bytes, haystack) {
+                        // None => break,
+                        // Some(i) => {
+                            // self.ic += i;
+                            // next_ic = self.chars.set(self.ic);
+                        // }
+                    // }
+                // }
+            // )
+        // }
+    // }
+
+    // Builds a `match pc { ... }` expression from a list of arms, specifically
+    // for matching the current program counter with an instruction.
+    // A wild-card arm is automatically added that executes a no-op. It will
+    // never be used, but is added to satisfy the compiler complaining about
+    // non-exhaustive patterns.
+    fn match_insts(&self, mut arms: Vec<ast::Arm>) -> P<ast::Expr> {
+        arms.push(self.wild_arm_expr(self.empty_block()));
+        self.cx.expr_match(self.sp, quote_expr!(self.cx, pc), arms)
+    }
+
+    fn empty_block(&self) -> P<ast::Expr> {
+        quote_expr!(self.cx, {})
+    }
+
+    // Creates a match arm for the instruction at `pc` with the expression
+    // `body`.
+    fn arm_inst(&self, pc: usize, body: P<ast::Expr>) -> ast::Arm {
+        let pc_pat = self.cx.pat_lit(self.sp, quote_expr!(self.cx, $pc));
+
+        self.cx.arm(self.sp, vec!(pc_pat), body)
+    }
+
+    // Creates a wild-card match arm with the expression `body`.
+    fn wild_arm_expr(&self, body: P<ast::Expr>) -> ast::Arm {
+        ast::Arm {
+            attrs: vec!(),
+            pats: vec!(P(ast::Pat{
+                id: ast::DUMMY_NODE_ID,
+                span: self.sp,
+                node: ast::PatWild(ast::PatWildSingle),
+            })),
+            guard: None,
+            body: body,
+        }
+    }
+
+    // Converts `xs` to a `[x1, x2, .., xN]` expression by calling `to_expr`
+    // on each element in `xs`.
+    fn vec_expr<T, It: Iterator<Item=T>>(&self, xs: It,
+                                    to_expr: &mut FnMut(&ExtCtxt, T) -> P<ast::Expr>)
+                  -> P<ast::Expr> {
+        let exprs = xs.map(|x| to_expr(self.cx, x)).collect();
+        self.cx.expr_vec(self.sp, exprs)
+    }
+}
+
+/// Looks for a single string literal and returns it.
+/// Otherwise, logs an error with cx.span_err and returns None.
+fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
+    let mut parser = cx.new_parser_from_tts(tts);
+    let entry = cx.expander().fold_expr(parser.parse_expr());
+    let regex = match entry.node {
+        ast::ExprLit(ref lit) => {
+            match lit.node {
+                ast::LitStr(ref s, _) => s.to_string(),
+                _ => {
+                    cx.span_err(entry.span, &format!(
+                        "expected string literal but got `{}`",
+                        pprust::lit_to_string(&**lit)));
+                    return None
+                }
+            }
+        }
+        _ => {
+            cx.span_err(entry.span, &format!(
+                "expected string literal but got `{}`",
+                pprust::expr_to_string(&*entry)));
+            return None
+        }
+    };
+    if !parser.eat(&token::Eof).ok().unwrap() {
+        cx.span_err(parser.span, "only one string literal allowed");
+        return None;
+    }
+    Some(regex)
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex_syntax/lib.rs.html b/src/regex_syntax/lib.rs.html new file mode 100644 index 0000000..7c8b82b --- /dev/null +++ b/src/regex_syntax/lib.rs.html @@ -0,0 +1,2465 @@ + + + + + + + + + + lib.rs.html -- source + + + + + + + + + + + + + + + +
   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
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+This crate provides a regular expression parser and an abstract syntax for
+regular expressions. The abstract syntax is defined by the `Expr` type. The
+concrete syntax is enumerated in the
+[`regex`](../regex/index.html#syntax)
+crate documentation.
+
+Note that since this crate is first and foremost an implementation detail for
+the `regex` crate, it may experience more frequent breaking changes. It is
+exposed as a separate crate so that others may use it to do analysis on regular
+expressions or even build their own matching engine.
+
+# Example: parsing an expression
+
+Parsing a regular expression can be done with the `Expr::parse` function.
+
+```rust
+use regex_syntax::Expr;
+
+assert_eq!(Expr::parse(r"ab|yz").unwrap(), Expr::Alternate(vec![
+    Expr::Literal { chars: vec!['a', 'b'], casei: false },
+    Expr::Literal { chars: vec!['y', 'z'], casei: false },
+]));
+```
+
+# Example: inspecting an error
+
+The parser in this crate provides very detailed error values. For example,
+if an invalid character class range is given:
+
+```rust
+use regex_syntax::{Expr, ErrorKind};
+
+let err = Expr::parse(r"[z-a]").unwrap_err();
+assert_eq!(err.position(), 4);
+assert_eq!(err.kind(), &ErrorKind::InvalidClassRange {
+    start: 'z',
+    end: 'a',
+});
+```
+
+Or unbalanced parentheses:
+
+```rust
+use regex_syntax::{Expr, ErrorKind};
+
+let err = Expr::parse(r"ab(cd").unwrap_err();
+assert_eq!(err.position(), 2);
+assert_eq!(err.kind(), &ErrorKind::UnclosedParen);
+```
+*/
+
+#![deny(missing_docs)]
+
+#[cfg(test)] extern crate quickcheck;
+#[cfg(test)] extern crate rand;
+
+mod parser;
+mod unicode;
+
+use std::char;
+use std::cmp::{Ordering, max, min};
+use std::fmt;
+use std::iter::IntoIterator;
+use std::ops::Deref;
+use std::slice;
+use std::vec;
+
+use unicode::case_folding;
+
+use self::Expr::*;
+use self::Repeater::*;
+
+pub use parser::is_punct;
+
+/// A regular expression abstract syntax tree.
+///
+/// An `Expr` represents the abstract syntax of a regular expression.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum Expr {
+    /// An empty regex (which never matches any text).
+    Empty,
+    /// A sequence of one or more literal characters to be matched.
+    Literal {
+        /// The characters.
+        chars: Vec<char>,
+        /// Whether to match case insensitively.
+        casei: bool,
+    },
+    /// Match any character, excluding new line.
+    AnyChar,
+    /// Match any character.
+    AnyCharNoNL,
+    /// A character class.
+    Class(CharClass),
+    /// Match the start of a line or beginning of input.
+    StartLine,
+    /// Match the end of a line or end of input.
+    EndLine,
+    /// Match the beginning of input.
+    StartText,
+    /// Match the end of input.
+    EndText,
+    /// Match a word boundary (word character on one side and a non-word
+    /// character on the other).
+    WordBoundary,
+    /// Match a position that is not a word boundary (word or non-word
+    /// characters on both sides).
+    NotWordBoundary,
+    /// A group, possibly non-capturing.
+    Group {
+        /// The expression inside the group.
+        e: Box<Expr>,
+        /// The capture index (starting at `1`) only for capturing groups.
+        i: Option<usize>,
+        /// The capture name, only for capturing named groups.
+        name: Option<String>,
+    },
+    /// A repeat operator (`?`, `*`, `+` or `{m,n}`).
+    Repeat {
+        /// The expression to be repeated. Limited to literals, `.`, classes
+        /// or grouped expressions.
+        e: Box<Expr>,
+        /// The type of repeat operator used.
+        r: Repeater,
+        /// Whether the repeat is greedy (match the most) or not (match the
+        /// least).
+        greedy: bool,
+    },
+    /// A concatenation of expressions. Must be matched one after the other.
+    ///
+    /// N.B. A concat expression can only appear at the top-level or
+    /// immediately inside a group expression.
+    Concat(Vec<Expr>),
+    /// An alternation of expressions. Only one must match.
+    ///
+    /// N.B. An alternate expression can only appear at the top-level or
+    /// immediately inside a group expression.
+    Alternate(Vec<Expr>),
+}
+
+type CaptureIndex = Option<usize>;
+
+type CaptureName = Option<String>;
+
+/// The type of a repeat operator expression.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Repeater {
+    /// Match zero or one (`?`).
+    ZeroOrOne,
+    /// Match zero or more (`*`).
+    ZeroOrMore,
+    /// Match one or more (`+`).
+    OneOrMore,
+    /// Match for at least `min` and at most `max` (`{m,n}`).
+    ///
+    /// When `max` is `None`, there is no upper bound on the number of matches.
+    Range {
+        /// Lower bound on the number of matches.
+        min: u32,
+        /// Optional upper bound on the number of matches.
+        max: Option<u32>,
+    },
+}
+
+/// A character class.
+///
+/// A character class has a canonical format that the parser guarantees. Its
+/// canonical format is defined by the following invariants:
+///
+/// 1. Given any Unicode scalar value, it is matched by *at most* one character
+///    range in a canonical character class.
+/// 2. Every adjacent character range is separated by at least one Unicode
+///    scalar value.
+/// 3. Given any pair of character ranges `r1` and `r2`, if
+///    `r1.end < r2.start`, then `r1` comes before `r2` in a canonical
+///    character class.
+///
+/// In sum, any `CharClass` produced by this crate's parser is a sorted
+/// sequence of non-overlapping ranges. This makes it possible to test whether
+/// a character is matched by a class with a binary search.
+///
+/// Additionally, a character class may be marked *case insensitive*. If it's
+/// case insensitive, then:
+///
+/// 1. Simple case folding has been applied to all ranges.
+/// 2. Simple case folding must be applied to a character before testing
+///    whether it matches the character class.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct CharClass {
+    ranges: Vec<ClassRange>,
+    casei: bool,
+}
+
+/// A single inclusive range in a character class.
+///
+/// Since range boundaries are defined by Unicode scalar values, the boundaries
+/// can never be in the open interval `(0xD7FF, 0xE000)`. However, a range may
+/// *cover* codepoints that are not scalar values.
+///
+/// Note that this has a few convenient impls on `PartialEq` and `PartialOrd`
+/// for testing whether a character is contained inside a given range.
+#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
+pub struct ClassRange {
+    /// The start character of the range.
+    ///
+    /// This must be less than or equal to `end`.
+    pub start: char,
+
+    /// The end character of the range.
+    ///
+    /// This must be greater than or equal to `end`.
+    pub end: char,
+}
+
+impl Expr {
+    /// Parses a string in a regular expression syntax tree.
+    pub fn parse(s: &str) -> Result<Expr> {
+        parser::Parser::parse(s).map(|e| e.simplify())
+    }
+
+    /// Returns true iff the expression can be repeated by a quantifier.
+    fn can_repeat(&self) -> bool {
+        match *self {
+            Literal{..}
+            | AnyChar
+            | AnyCharNoNL
+            | Class(_)
+            | StartLine | EndLine | StartText | EndText
+            | WordBoundary | NotWordBoundary
+            | Group{..}
+            => true,
+            _ => false,
+        }
+    }
+
+    fn simplify(self) -> Expr {
+        fn combine_literals(es: &mut Vec<Expr>, e: Expr) {
+            match (es.pop(), e) {
+                (None, e) => es.push(e),
+                (Some(Literal { chars: mut chars1, casei: casei1 }),
+                 Literal { chars: chars2, casei: casei2 }) => {
+                    if casei1 == casei2 {
+                        chars1.extend(chars2);
+                        es.push(Literal { chars: chars1, casei: casei1 });
+                    } else {
+                        es.push(Literal { chars: chars1, casei: casei1 });
+                        es.push(Literal { chars: chars2, casei: casei2 });
+                    }
+                }
+                (Some(e1), e2) => {
+                    es.push(e1);
+                    es.push(e2);
+                }
+            }
+        }
+        match self {
+            Repeat { e, r, greedy } => Repeat {
+                e: Box::new(e.simplify()),
+                r: r,
+                greedy: greedy,
+            },
+            Group { e, i, name } => {
+                let e = e.simplify();
+                if i.is_none() && name.is_none() && e.can_repeat() {
+                    e
+                } else {
+                    Group { e: Box::new(e), i: i, name: name }
+                }
+            }
+            Concat(es) => {
+                let mut new_es = Vec::with_capacity(es.len());
+                for e in es {
+                    combine_literals(&mut new_es, e.simplify());
+                }
+                if new_es.len() == 1 {
+                    new_es.pop().unwrap()
+                } else {
+                    Concat(new_es)
+                }
+            }
+            Alternate(es) => Alternate(es.into_iter()
+                                         .map(|e| e.simplify())
+                                         .collect()),
+            e => e,
+        }
+    }
+}
+
+impl Deref for CharClass {
+    type Target = Vec<ClassRange>;
+    fn deref(&self) -> &Vec<ClassRange> { &self.ranges }
+}
+
+impl IntoIterator for CharClass {
+    type Item = ClassRange;
+    type IntoIter = vec::IntoIter<ClassRange>;
+    fn into_iter(self) -> vec::IntoIter<ClassRange> { self.ranges.into_iter() }
+}
+
+impl<'a> IntoIterator for &'a CharClass {
+    type Item = &'a ClassRange;
+    type IntoIter = slice::Iter<'a, ClassRange>;
+    fn into_iter(self) -> slice::Iter<'a, ClassRange> { self.iter() }
+}
+
+impl CharClass {
+    /// Create a new class from an existing set of ranges.
+    fn new(ranges: Vec<ClassRange>) -> CharClass {
+        CharClass { ranges: ranges, casei: false }
+    }
+
+    /// Create an empty class.
+    fn empty() -> CharClass {
+        CharClass::new(Vec::new())
+    }
+
+    /// Returns true if `c` is matched by this character class.
+    ///
+    /// If this character class is case insensitive, then simple case folding
+    /// is applied to `c` before checking for a match.
+    pub fn matches(&self, mut c: char) -> bool {
+        if self.is_case_insensitive() {
+            c = simple_case_fold(c)
+        }
+        self.binary_search_by(|range| c.partial_cmp(range).unwrap()).is_ok()
+    }
+
+    /// Returns true if this character class should be matched case
+    /// insensitively.
+    ///
+    /// When `true`, simple case folding has already been applied to the
+    /// class.
+    pub fn is_case_insensitive(&self) -> bool {
+        self.casei
+    }
+
+    /// Create a new empty class from this one.
+    ///
+    /// Namely, its capacity and case insensitive setting will be the same.
+    fn to_empty(&self) -> CharClass {
+        CharClass { ranges: Vec::with_capacity(self.len()), casei: self.casei }
+    }
+
+    /// Merge two classes and canonicalize them.
+    #[cfg(test)]
+    fn merge(mut self, other: CharClass) -> CharClass {
+        self.ranges.extend(other);
+        self.canonicalize()
+    }
+
+    /// Canonicalze any sequence of ranges.
+    ///
+    /// This is responsible for enforcing the canonical format invariants
+    /// as described on the docs for the `CharClass` type.
+    fn canonicalize(mut self) -> CharClass {
+        // TODO: Save some cycles here by checking if already canonicalized.
+        self.ranges.sort();
+        let mut ordered = self.to_empty(); // TODO: Do this in place?
+        for candidate in self {
+            // If the candidate overlaps with an existing range, then it must
+            // be the most recent range added because we process the candidates
+            // in order.
+            if let Some(or) = ordered.ranges.last_mut() {
+                if or.overlapping(candidate) {
+                    *or = or.merge(candidate);
+                    continue;
+                }
+            }
+            ordered.ranges.push(candidate);
+        }
+        ordered
+    }
+
+    /// Negates the character class.
+    ///
+    /// For all `c` where `c` is a Unicode scalar value, `c` matches `self`
+    /// if and only if `c` does not match `self.negate()`.
+    ///
+    /// Note that this cannot be called on a character class that has had
+    /// case folding applied to it. (Because case folding turns on a flag
+    /// and doesn't store every possible matching character. Therefore,
+    /// its negation is tricky to get right. Turns out, we don't need it
+    /// anyway!)
+    fn negate(mut self) -> CharClass {
+        fn range(s: char, e: char) -> ClassRange { ClassRange::new(s, e) }
+
+        // Never allow negating of a class that has been case folded!
+        assert!(!self.casei);
+
+        if self.is_empty() { return self; }
+        self = self.canonicalize();
+        let mut inv = self.to_empty();
+        if self[0].start > '\x00' {
+            inv.ranges.push(range('\x00', dec_char(self[0].start)));
+        }
+        for win in self.windows(2) {
+            inv.ranges.push(range(inc_char(win[0].end),
+                                  dec_char(win[1].start)));
+        }
+        if self[self.len() - 1].end < char::MAX {
+            inv.ranges.push(range(inc_char(self[self.len() - 1].end),
+                                  char::MAX));
+        }
+        inv
+    }
+
+    /// Apply case folding to this character class.
+    ///
+    /// One a class had been case folded, it cannot be negated.
+    fn case_fold(self) -> CharClass {
+        let mut folded = self.to_empty();
+        folded.casei = true;
+        for r in self {
+            // Applying case folding to a range is expensive because *every*
+            // character needed to be examined. Thus, we avoid that drudgery
+            // if no character in the current range is in our case folding
+            // table.
+            if r.needs_case_folding() {
+                folded.ranges.extend(r.case_fold());
+            } else {
+                folded.ranges.push(r);
+            }
+        }
+        folded.canonicalize()
+    }
+}
+
+impl ClassRange {
+    /// Create a new class range.
+    ///
+    /// If `end < start`, then the two values are swapped so that
+    /// the invariant `start <= end` is preserved.
+    fn new(start: char, end: char) -> ClassRange {
+        if start <= end {
+            ClassRange { start: start, end: end }
+        } else {
+            ClassRange { start: end, end: start }
+        }
+    }
+
+    /// Create a range of one character.
+    fn one(c: char) -> ClassRange {
+        ClassRange { start: c, end: c }
+    }
+
+    /// Returns true if and only if the two ranges are overlapping. Note that
+    /// since ranges are inclusive, `a-c` and `d-f` are overlapping!
+    fn overlapping(self, other: ClassRange) -> bool {
+        max(self.start, other.start) <= inc_char(min(self.end, other.end))
+    }
+
+    /// Creates a new range representing the union of `self` and `other.
+    fn merge(self, other: ClassRange) -> ClassRange {
+        ClassRange {
+            start: min(self.start, other.start),
+            end: max(self.end, other.end),
+        }
+    }
+
+    /// Returns true if and only if this range contains a character that is
+    /// in the case folding table.
+    fn needs_case_folding(self) -> bool {
+        case_folding::C_plus_S_table
+        .binary_search_by(|&(c, _)| self.partial_cmp(&c).unwrap()).is_ok()
+    }
+
+    /// Apply case folding to this range.
+    ///
+    /// Since case folding might add characters such that the range is no
+    /// longer contiguous, this returns multiple class ranges. They are in
+    /// canonical order.
+    fn case_fold(self) -> Vec<ClassRange> {
+        let (s, e) = (self.start as u32, self.end as u32 + 1);
+        let mut start = simple_case_fold(self.start);
+        let mut end = start;
+        let mut next_case_fold = self.start;
+        let mut ranges = Vec::with_capacity(100);
+        for mut c in (s+1..e).filter_map(char::from_u32) {
+            if c >= next_case_fold {
+                c = match simple_case_fold_result(c) {
+                    Ok(i) => case_folding::C_plus_S_table[i].1,
+                    Err(i) => {
+                        if i < case_folding::C_plus_S_table.len() {
+                            next_case_fold = case_folding::C_plus_S_table[i].0;
+                        } else {
+                            next_case_fold = '\u{10FFFF}'
+                        }
+                        c
+                    }
+                };
+            }
+            if c != inc_char(end) {
+                ranges.push(ClassRange::new(start, end));
+                start = c;
+            }
+            end = c;
+        }
+        ranges.push(ClassRange::new(start, end));
+        ranges
+    }
+}
+
+impl PartialEq<char> for ClassRange {
+    #[inline]
+    fn eq(&self, other: &char) -> bool {
+        self.start <= *other && *other <= self.end
+    }
+}
+
+impl PartialEq<ClassRange> for char {
+    #[inline]
+    fn eq(&self, other: &ClassRange) -> bool {
+        other.eq(self)
+    }
+}
+
+impl PartialOrd<char> for ClassRange {
+    #[inline]
+    fn partial_cmp(&self, other: &char) -> Option<Ordering> {
+        Some(if self == other {
+            Ordering::Equal
+        } else if *other > self.end {
+            Ordering::Greater
+        } else {
+            Ordering::Less
+        })
+    }
+}
+
+impl PartialOrd<ClassRange> for char {
+    #[inline]
+    fn partial_cmp(&self, other: &ClassRange) -> Option<Ordering> {
+        other.partial_cmp(self).map(|o| o.reverse())
+    }
+}
+
+/// This implementation of `Display` will write a regular expression from the
+/// syntax tree. It does not write the original string parsed.
+impl fmt::Display for Expr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            Empty => write!(f, ""),
+            Literal { ref chars, casei } => {
+                if casei { try!(write!(f, "(?i:")); }
+                for &c in chars {
+                    try!(write!(f, "{}", quote_char(c)));
+                }
+                if casei { try!(write!(f, ")")); }
+                Ok(())
+            }
+            AnyChar => write!(f, "(?s:.)"),
+            AnyCharNoNL => write!(f, "."),
+            Class(ref cls) => write!(f, "{}", cls),
+            StartLine => write!(f, "(?m:^)"),
+            EndLine => write!(f, "(?m:$)"),
+            StartText => write!(f, r"^"),
+            EndText => write!(f, r"$"),
+            WordBoundary => write!(f, r"\b"),
+            NotWordBoundary => write!(f, r"\B"),
+            Group { ref e, i: None, name: None } => write!(f, "(?:{})", e),
+            Group { ref e, name: None, .. } => write!(f, "({})", e),
+            Group { ref e, name: Some(ref n), .. } => {
+                write!(f, "(?P<{}>{})", n, e)
+            }
+            Repeat { ref e, r, greedy } => {
+                match &**e {
+                    &Literal { ref chars, .. } if chars.len() > 1 => {
+                        try!(write!(f, "(?:{}){}", e, r))
+                    }
+                    _ => try!(write!(f, "{}{}", e, r)),
+                }
+                if !greedy { try!(write!(f, "?")); }
+                Ok(())
+            }
+            Concat(ref es) => {
+                for e in es {
+                    try!(write!(f, "{}", e));
+                }
+                Ok(())
+            }
+            Alternate(ref es) => {
+                for (i, e) in es.iter().enumerate() {
+                    if i > 0 { try!(write!(f, "|")); }
+                    try!(write!(f, "{}", e));
+                }
+                Ok(())
+            }
+        }
+    }
+}
+
+impl fmt::Display for Repeater {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ZeroOrOne => write!(f, "?"),
+            ZeroOrMore => write!(f, "*"),
+            OneOrMore => write!(f, "+"),
+            Range { min: s, max: None } => write!(f, "{{{},}}", s),
+            Range { min: s, max: Some(e) } if s == e => write!(f, "{{{}}}", s),
+            Range { min: s, max: Some(e) } => write!(f, "{{{}, {}}}", s, e),
+        }
+    }
+}
+
+impl fmt::Display for CharClass {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.casei {
+            try!(write!(f, "(?i:"));
+        }
+        try!(write!(f, "["));
+        for range in self.iter() {
+            try!(write!(f, "{}", range));
+        }
+        try!(write!(f, "]"));
+        if self.casei {
+            try!(write!(f, ")"));
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Display for ClassRange {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}-{}", quote_char(self.start), quote_char(self.end))
+    }
+}
+
+/// An alias for computations that can return a `Error`.
+pub type Result<T> = ::std::result::Result<T, Error>;
+
+/// A parse error.
+///
+/// This includes details about the specific type of error and a rough
+/// approximation of where it occurred.
+#[derive(Clone, Debug, PartialEq)]
+pub struct Error {
+    pos: usize,
+    surround: String,
+    kind: ErrorKind,
+}
+
+/// The specific type of parse error that can occur.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ErrorKind {
+    /// A negation symbol is used twice in flag settings.
+    /// e.g., `(?-i-s)`.
+    DoubleFlagNegation,
+    /// The same capture name was used more than once.
+    /// e.g., `(?P<a>.)(?P<a>.)`.
+    DuplicateCaptureName(String),
+    /// An alternate is empty. e.g., `(|a)`.
+    EmptyAlternate,
+    /// A capture group name is empty. e.g., `(?P<>a)`.
+    EmptyCaptureName,
+    /// A negation symbol was not proceded by any flags. e.g., `(?i-)`.
+    EmptyFlagNegation,
+    /// A group is empty. e.g., `()`.
+    EmptyGroup,
+    /// An invalid number was used in a counted repetition. e.g., `a{b}`.
+    InvalidBase10(String),
+    /// An invalid hexadecimal number was used in an escape sequence.
+    /// e.g., `\xAG`.
+    InvalidBase16(String),
+    /// An invalid capture name was used. e.g., `(?P<0a>b)`.
+    InvalidCaptureName(String),
+    /// An invalid class range was givien. Specifically, when the start of the
+    /// range is greater than the end. e.g., `[z-a]`.
+    InvalidClassRange {
+        /// The first character specified in the range.
+        start: char,
+        /// The second character specified in the range.
+        end: char,
+    },
+    /// An escape sequence was used in a character class where it is not
+    /// allowed. e.g., `[a-\pN]` or `[\A]`.
+    InvalidClassEscape(Expr),
+    /// An invalid counted repetition min/max was given. e.g., `a{2,1}`.
+    InvalidRepeatRange {
+        /// The first number specified in the repetition.
+        min: u32,
+        /// The second number specified in the repetition.
+        max: u32,
+    },
+    /// An invalid Unicode scalar value was used in a long hexadecimal
+    /// sequence. e.g., `\x{D800}`.
+    InvalidScalarValue(u32),
+    /// An empty counted repetition operator. e.g., `a{}`.
+    MissingBase10,
+    /// A repetition operator was not applied to an expression. e.g., `*`.
+    RepeaterExpectsExpr,
+    /// A repetition operator was applied to an expression that cannot be
+    /// repeated. e.g., `a+*` or `a|*`.
+    RepeaterUnexpectedExpr(Expr),
+    /// A capture group name that is never closed. e.g., `(?P<a`.
+    UnclosedCaptureName(String),
+    /// An unclosed hexadecimal literal. e.g., `\x{a`.
+    UnclosedHex,
+    /// An unclosed parenthesis. e.g., `(a`.
+    UnclosedParen,
+    /// An unclosed counted repetition operator. e.g., `a{2`.
+    UnclosedRepeat,
+    /// An unclosed named Unicode class. e.g., `\p{Yi`.
+    UnclosedUnicodeName,
+    /// Saw end of regex before class was closed. e.g., `[a`.
+    UnexpectedClassEof,
+    /// Saw end of regex before escape sequence was closed. e.g., `\`.
+    UnexpectedEscapeEof,
+    /// Saw end of regex before flags were closed. e.g., `(?i`.
+    UnexpectedFlagEof,
+    /// Saw end of regex before two hexadecimal digits were seen. e.g., `\xA`.
+    UnexpectedTwoDigitHexEof,
+    /// Unopened parenthesis. e.g., `)`.
+    UnopenedParen,
+    /// Unrecognized escape sequence. e.g., `\q`.
+    UnrecognizedEscape(char),
+    /// Unrecognized flag. e.g., `(?a)`.
+    UnrecognizedFlag(char),
+    /// Unrecognized named Unicode class. e.g., `\p{Foo}`.
+    UnrecognizedUnicodeClass(String),
+    /// Hints that destructuring should not be exhaustive.
+    ///
+    /// This enum may grow additional variants, so this makes sure clients
+    /// don't count on exhaustive matching. (Otherwise, adding a new variant
+    /// could break existing code.)
+    #[doc(hidden)]
+    __Nonexhaustive,
+}
+
+impl Error {
+    /// Returns an approximate *character* offset at which the error occurred.
+    ///
+    /// The character offset may be equal to the number of characters in the
+    /// string, in which case it should be interpreted as pointing to the end
+    /// of the regex.
+    pub fn position(&self) -> usize {
+        self.pos
+    }
+
+    /// Returns the type of the regex parse error.
+    pub fn kind(&self) -> &ErrorKind {
+        &self.kind
+    }
+}
+
+impl ErrorKind {
+    fn description(&self) -> &str {
+        use ErrorKind::*;
+        match *self {
+            DoubleFlagNegation => "double flag negation",
+            DuplicateCaptureName(_) => "duplicate capture name",
+            EmptyAlternate => "empty alternate",
+            EmptyCaptureName => "empty capture name",
+            EmptyFlagNegation => "flag negation without any flags",
+            EmptyGroup => "empty group (e.g., '()')",
+            InvalidBase10(_) => "invalid base 10 number",
+            InvalidBase16(_) => "invalid base 16 number",
+            InvalidCaptureName(_) => "invalid capture name",
+            InvalidClassRange{..} => "invalid character class range",
+            InvalidClassEscape(_) => "invalid escape sequence in class",
+            InvalidRepeatRange{..} => "invalid counted repetition range",
+            InvalidScalarValue(_) => "invalid Unicode scalar value",
+            MissingBase10 => "missing count in repetition operator",
+            RepeaterExpectsExpr => "repetition operator missing expression",
+            RepeaterUnexpectedExpr(_) => "expression cannot be repeated",
+            UnclosedCaptureName(_) => "unclosed capture group name",
+            UnclosedHex => "unclosed hexadecimal literal",
+            UnclosedParen => "unclosed parenthesis",
+            UnclosedRepeat => "unclosed counted repetition operator",
+            UnclosedUnicodeName => "unclosed Unicode class literal",
+            UnexpectedClassEof => "unexpected EOF in character class",
+            UnexpectedEscapeEof => "unexpected EOF in escape sequence",
+            UnexpectedFlagEof => "unexpected EOF in flags",
+            UnexpectedTwoDigitHexEof => "unexpected EOF in hex literal",
+            UnopenedParen => "unopened parenthesis",
+            UnrecognizedEscape(_) => "unrecognized escape sequence",
+            UnrecognizedFlag(_) => "unrecognized flag",
+            UnrecognizedUnicodeClass(_) => "unrecognized Unicode class name",
+            __Nonexhaustive => unreachable!(),
+        }
+    }
+}
+
+impl ::std::error::Error for Error {
+    fn description(&self) -> &str {
+        self.kind.description()
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "Error parsing regex near '{}' at character offset {}: {}",
+               self.surround, self.pos, self.kind)
+    }
+}
+
+impl fmt::Display for ErrorKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use ErrorKind::*;
+        match *self {
+            DoubleFlagNegation =>
+                write!(f, "Only one negation symbol is allowed in flags."),
+            DuplicateCaptureName(ref s) =>
+                write!(f, "Capture name '{}' is used more than once.", s),
+            EmptyAlternate =>
+                write!(f, "Alternations cannot be empty."),
+            EmptyCaptureName =>
+                write!(f, "Capture names cannot be empty."),
+            EmptyFlagNegation =>
+                write!(f, "Flag negation requires setting at least one flag."),
+            EmptyGroup =>
+                write!(f, "Empty regex groups (e.g., '()') are not allowed."),
+            InvalidBase10(ref s) =>
+                write!(f, "Not a valid base 10 number: '{}'", s),
+            InvalidBase16(ref s) =>
+                write!(f, "Not a valid base 16 number: '{}'", s),
+            InvalidCaptureName(ref s) =>
+                write!(f, "Invalid capture name: '{}'. Capture names must \
+                           consist of [_a-zA-Z0-9] and are not allowed to \
+                           start with with a number.", s),
+            InvalidClassRange { start, end } =>
+                write!(f, "Invalid character class range '{}-{}'. \
+                           Character class ranges must start with the smaller \
+                           character, but {} > {}", start, end, start, end),
+            InvalidClassEscape(ref e) =>
+                write!(f, "Invalid escape sequence in character \
+                           class: '{}'.", e),
+            InvalidRepeatRange { min, max } =>
+                write!(f, "Invalid counted repetition range: {{{}, {}}}. \
+                           Counted repetition ranges must start with the \
+                           minimum, but {} > {}", min, max, min, max),
+            InvalidScalarValue(c) =>
+                write!(f, "Number does not correspond to a Unicode scalar \
+                           value: '{}'.", c),
+            MissingBase10 =>
+                write!(f, "Missing maximum in counted reptition operator."),
+            RepeaterExpectsExpr =>
+                write!(f, "Missing expression for reptition operator."),
+            RepeaterUnexpectedExpr(ref e) =>
+                write!(f, "Invalid application of reptition operator to: \
+                          '{}'.", e),
+            UnclosedCaptureName(ref s) =>
+                write!(f, "Capture name group for '{}' is not closed. \
+                           (Missing a '>'.)", s),
+            UnclosedHex =>
+                write!(f, "Unclosed hexadecimal literal (missing a '}}')."),
+            UnclosedParen =>
+                write!(f, "Unclosed parenthesis."),
+            UnclosedRepeat =>
+                write!(f, "Unclosed counted repetition (missing a '}}')."),
+            UnclosedUnicodeName =>
+                write!(f, "Unclosed Unicode literal (missing a '}}')."),
+            UnexpectedClassEof =>
+                write!(f, "Character class was not closed before the end of \
+                           the regex (missing a ']')."),
+            UnexpectedEscapeEof =>
+                write!(f, "Started an escape sequence that didn't finish \
+                           before the end of the regex."),
+            UnexpectedFlagEof =>
+                write!(f, "Inline flag settings was not closed before the end \
+                           of the regex (missing a ')' or ':')."),
+            UnexpectedTwoDigitHexEof =>
+                write!(f, "Unexpected end of two digit hexadecimal literal."),
+            UnopenedParen =>
+                write!(f, "Unopened parenthesis."),
+            UnrecognizedEscape(c) =>
+                write!(f, "Unrecognized escape sequence: '\\{}'.", c),
+            UnrecognizedFlag(c) =>
+                write!(f, "Unrecognized flag: '{}'. \
+                           (Allowed flags: i, s, m, U, x.)", c),
+            UnrecognizedUnicodeClass(ref s) =>
+                write!(f, "Unrecognized Unicode class name: '{}'.", s),
+            __Nonexhaustive => unreachable!(),
+        }
+    }
+}
+
+/// Returns the Unicode *simple* case folding of `c`.
+///
+/// N.B. This is hidden because it really isn't the responsibility of this
+/// crate to do simple case folding. One hopes that either another crate or
+/// the standard library will be able to do this for us. In any case, we still
+/// expose it because it is used inside the various Regex engines.
+#[doc(hidden)]
+pub fn simple_case_fold(c: char) -> char {
+    simple_case_fold_result(c)
+        .map(|i| case_folding::C_plus_S_table[i].1)
+        .unwrap_or(c)
+}
+
+/// The result of binary search on the simple case folding table.
+///
+/// This level of detail is exposed so that we can do case folding on a
+/// range of characters efficiently.
+fn simple_case_fold_result(c: char) -> ::std::result::Result<usize, usize> {
+    case_folding::C_plus_S_table.binary_search_by(|&(x, _)| x.cmp(&c))
+}
+
+/// Escapes all regular expression meta characters in `text`.
+///
+/// The string returned may be safely used as a literal in a regular
+/// expression.
+pub fn quote(text: &str) -> String {
+    let mut quoted = String::with_capacity(text.len());
+    for c in text.chars() {
+        if parser::is_punct(c) {
+            quoted.push('\\');
+        }
+        quoted.push(c);
+    }
+    quoted
+}
+
+fn quote_char(c: char) -> String {
+    let mut s = String::new();
+    if parser::is_punct(c) {
+        s.push('\\');
+    }
+    s.push(c);
+    s
+}
+
+fn inc_char(c: char) -> char {
+    match c {
+        char::MAX => char::MAX,
+        '\u{D7FF}' => '\u{E000}',
+        c => char::from_u32(c as u32 + 1).unwrap(),
+    }
+}
+
+fn dec_char(c: char) -> char {
+    match c {
+        '\x00' => '\x00',
+        '\u{E000}' => '\u{D7FF}',
+        c => char::from_u32(c as u32 - 1).unwrap(),
+    }
+}
+
+/// Returns true if and only if `c` is a word character.
+#[doc(hidden)]
+pub fn is_word_char(c: char) -> bool {
+    match c {
+        '_' | '0' ... '9' | 'a' ... 'z' | 'A' ... 'Z'  => true,
+        _ => ::unicode::regex::PERLW.binary_search_by(|&(start, end)| {
+            if c >= start && c <= end {
+                Ordering::Equal
+            } else if start > c {
+                Ordering::Greater
+            } else {
+                Ordering::Less
+            }
+        }).is_ok(),
+    }
+}
+
+#[cfg(test)]
+mod properties;
+
+#[cfg(test)]
+mod tests {
+    use {CharClass, ClassRange};
+
+    fn class(ranges: &[(char, char)]) -> CharClass {
+        let ranges = ranges.iter().cloned()
+                           .map(|(c1, c2)| ClassRange::new(c1, c2)).collect();
+        CharClass::new(ranges)
+    }
+
+    fn classi(ranges: &[(char, char)]) -> CharClass {
+        let mut cls = class(ranges);
+        cls.casei = true;
+        cls
+    }
+
+    #[test]
+    fn class_canon_no_change() {
+        let cls = class(&[('a', 'c'), ('x', 'z')]);
+        assert_eq!(cls.clone().canonicalize(), cls);
+    }
+
+    #[test]
+    fn class_canon_unordered() {
+        let cls = class(&[('x', 'z'), ('a', 'c')]);
+        assert_eq!(cls.canonicalize(), class(&[
+            ('a', 'c'), ('x', 'z'),
+        ]));
+    }
+
+    #[test]
+    fn class_canon_overlap() {
+        let cls = class(&[('x', 'z'), ('w', 'y')]);
+        assert_eq!(cls.canonicalize(), class(&[
+            ('w', 'z'),
+        ]));
+    }
+
+    #[test]
+    fn class_canon_overlap_many() {
+        let cls = class(&[
+            ('c', 'f'), ('a', 'g'), ('d', 'j'), ('a', 'c'),
+            ('m', 'p'), ('l', 's'),
+        ]);
+        assert_eq!(cls.clone().canonicalize(), class(&[
+            ('a', 'j'), ('l', 's'),
+        ]));
+    }
+
+    #[test]
+    fn class_canon_overlap_many_case_fold() {
+        let cls = class(&[
+            ('C', 'F'), ('A', 'G'), ('D', 'J'), ('A', 'C'),
+            ('M', 'P'), ('L', 'S'), ('c', 'f'),
+        ]);
+        assert_eq!(cls.case_fold(), classi(&[
+            ('a', 'j'), ('l', 's'),
+        ]));
+    }
+
+    #[test]
+    fn class_canon_overlap_boundary() {
+        let cls = class(&[('x', 'z'), ('u', 'w')]);
+        assert_eq!(cls.canonicalize(), class(&[
+            ('u', 'z'),
+        ]));
+    }
+
+    #[test]
+    fn class_canon_extreme_edge_case() {
+        let cls = class(&[('\x00', '\u{10FFFF}'), ('\x00', '\u{10FFFF}')]);
+        assert_eq!(cls.canonicalize(), class(&[
+            ('\x00', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_canon_singles() {
+        let cls = class(&[('a', 'a'), ('b', 'b')]);
+        assert_eq!(cls.canonicalize(), class(&[('a', 'b')]));
+    }
+
+    #[test]
+    fn class_negate_single() {
+        let cls = class(&[('a', 'a')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x00', '\x60'), ('\x62', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_singles() {
+        let cls = class(&[('a', 'a'), ('b', 'b')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x00', '\x60'), ('\x63', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_multiples() {
+        let cls = class(&[('a', 'c'), ('x', 'z')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x00', '\x60'), ('\x64', '\x77'), ('\x7b', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_min_scalar() {
+        let cls = class(&[('\x00', 'a')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x62', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_max_scalar() {
+        let cls = class(&[('a', '\u{10FFFF}')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x00', '\x60'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_everything() {
+        let cls = class(&[('\x00', '\u{10FFFF}')]);
+        assert_eq!(cls.negate(), class(&[]));
+    }
+
+    #[test]
+    fn class_negate_everything_sans_one() {
+        let cls = class(&[
+            ('\x00', '\u{10FFFD}'), ('\u{10FFFF}', '\u{10FFFF}')
+        ]);
+        assert_eq!(cls.negate(), class(&[
+            ('\u{10FFFE}', '\u{10FFFE}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_surrogates_min() {
+        let cls = class(&[('\x00', '\u{D7FF}')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\u{E000}', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_surrogates_min_edge() {
+        let cls = class(&[('\x00', '\u{D7FE}')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\u{D7FF}', '\u{10FFFF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_surrogates_max() {
+        let cls = class(&[('\u{E000}', '\u{10FFFF}')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x00', '\u{D7FF}'),
+        ]));
+    }
+
+    #[test]
+    fn class_negate_surrogates_max_edge() {
+        let cls = class(&[('\u{E001}', '\u{10FFFF}')]);
+        assert_eq!(cls.negate(), class(&[
+            ('\x00', '\u{E000}'),
+        ]));
+    }
+
+    #[test]
+    fn class_fold_retain_only_needed() {
+        let cls = class(&[('A', 'Z'), ('a', 'z')]);
+        assert_eq!(cls.case_fold(), classi(&[
+            ('a', 'z'),
+        ]));
+    }
+
+    #[test]
+    fn class_fold_az() {
+        let cls = class(&[('A', 'Z')]);
+        assert_eq!(cls.case_fold(), classi(&[
+            ('a', 'z'),
+        ]));
+    }
+
+    #[test]
+    fn class_fold_a_underscore() {
+        let cls = class(&[('A', 'A'), ('_', '_')]);
+        assert_eq!(cls.clone().canonicalize(), class(&[
+            ('A', 'A'), ('_', '_'),
+        ]));
+        assert_eq!(cls.case_fold(), classi(&[
+            ('_', '_'), ('a', 'a'),
+        ]));
+    }
+
+    #[test]
+    fn class_fold_a_equals() {
+        let cls = class(&[('A', 'A'), ('=', '=')]);
+        assert_eq!(cls.clone().canonicalize(), class(&[
+            ('=', '='), ('A', 'A'),
+        ]));
+        assert_eq!(cls.case_fold(), classi(&[
+            ('=', '='), ('a', 'a'),
+        ]));
+    }
+
+    #[test]
+    fn class_fold_no_folding_needed() {
+        let cls = class(&[('\x00', '\x10')]);
+        assert_eq!(cls.case_fold(), classi(&[
+            ('\x00', '\x10'),
+        ]));
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/regex_syntax/parser.rs.html b/src/regex_syntax/parser.rs.html new file mode 100644 index 0000000..3f94959 --- /dev/null +++ b/src/regex_syntax/parser.rs.html @@ -0,0 +1,4751 @@ + + + + + + + + + + parser.rs.html -- source + + + + + + + + + + + + + + + +
   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
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp::{max, min};
+
+use unicode::regex::UNICODE_CLASSES;
+
+use {
+    Expr, Repeater, CharClass, ClassRange, CaptureIndex, CaptureName,
+    Error, ErrorKind, Result,
+};
+
+/// Parser state.
+///
+/// Keeps the entire input in memory and maintains a cursor (char offset).
+///
+/// It also keeps an expression stack, which is responsible for managing
+/// grouped expressions and flag state.
+#[derive(Debug)]
+pub struct Parser {
+    chars: Vec<char>,
+    chari: usize,
+    stack: Vec<Build>,
+    caps: usize,
+    names: Vec<String>, // to check for duplicates
+    flags: Flags,
+}
+
+/// An empheral type for representing the expression stack.
+///
+/// Everything on the stack is either a regular expression or a marker
+/// indicating the opening of a group (possibly non-capturing). The opening
+/// of a group copies the current flag state, which is reset on the parser
+/// state once the group closes.
+#[derive(Debug)]
+enum Build {
+    Expr(Expr),
+    LeftParen {
+        i: CaptureIndex,
+        name: CaptureName,
+        chari: usize,
+        old_flags: Flags,
+    },
+}
+
+/// Flag state.
+#[derive(Clone, Copy, Debug)]
+struct Flags {
+    casei: bool,
+    multi: bool,
+    dotnl: bool,
+    swap_greed: bool,
+    ignore_space: bool,
+}
+
+// Primary expression parsing routines.
+impl Parser {
+    pub fn parse(s: &str) -> Result<Expr> {
+        Parser {
+            chars: s.chars().collect(),
+            chari: 0,
+            stack: vec![],
+            caps: 0,
+            names: vec![],
+            flags: Flags {
+                casei: false,
+                multi: false,
+                dotnl: false,
+                swap_greed: false,
+                ignore_space: false,
+            },
+        }.parse_expr()
+    }
+
+    // Top-level expression parser.
+    //
+    // Starts at the beginning of the input and consumes until either the end
+    // of input or an error.
+    fn parse_expr(mut self) -> Result<Expr> {
+        while !self.eof() {
+            let build_expr = match self.cur() {
+                '\\' => try!(self.parse_escape()),
+                '|' => { let e = try!(self.alternate()); self.bump(); e }
+                '?' => try!(self.parse_simple_repeat(Repeater::ZeroOrOne)),
+                '*' => try!(self.parse_simple_repeat(Repeater::ZeroOrMore)),
+                '+' => try!(self.parse_simple_repeat(Repeater::OneOrMore)),
+                '{' => try!(self.parse_counted_repeat()),
+                '[' => match self.maybe_parse_ascii() {
+                    None => try!(self.parse_class()),
+                    Some(cls) => Build::Expr(Expr::Class(cls)),
+                },
+                '^' => {
+                    if self.flags.multi {
+                        self.parse_one(Expr::StartLine)
+                    } else {
+                        self.parse_one(Expr::StartText)
+                    }
+                }
+                '$' => {
+                    if self.flags.multi {
+                        self.parse_one(Expr::EndLine)
+                    } else {
+                        self.parse_one(Expr::EndText)
+                    }
+                }
+                '.' => {
+                    if self.flags.dotnl {
+                        self.parse_one(Expr::AnyChar)
+                    } else {
+                        self.parse_one(Expr::AnyCharNoNL)
+                    }
+                }
+                '(' => try!(self.parse_group()),
+                ')' => {
+                    let (old_flags, e) = try!(self.close_paren());
+                    self.bump();
+                    self.flags = old_flags;
+                    e
+                }
+                _ => Build::Expr(Expr::Literal {
+                    chars: vec![self.bump()],
+                    casei: self.flags.casei,
+                }),
+            };
+            if !build_expr.is_empty() {
+                let build_expr = self.maybe_class_case_fold(build_expr);
+                self.stack.push(build_expr);
+            }
+        }
+        self.finish_concat()
+    }
+
+    // Parses an escape sequence, e.g., \Ax
+    //
+    // Start: `\`
+    // End:   `x`
+    fn parse_escape(&mut self) -> Result<Build> {
+        self.bump();
+        if self.eof() {
+            return Err(self.err(ErrorKind::UnexpectedEscapeEof));
+        }
+        let c = self.cur();
+        if is_punct(c) {
+            return Ok(Build::Expr(Expr::Literal {
+                chars: vec![self.bump()],
+                casei: self.flags.casei,
+            }));
+        }
+
+        fn lit(c: char) -> Build {
+            Build::Expr(Expr::Literal { chars: vec![c], casei: false })
+        }
+        match c {
+            'a' => { self.bump(); Ok(lit('\x07')) }
+            'f' => { self.bump(); Ok(lit('\x0C')) }
+            't' => { self.bump(); Ok(lit('\t')) }
+            'n' => { self.bump(); Ok(lit('\n')) }
+            'r' => { self.bump(); Ok(lit('\r')) }
+            'v' => { self.bump(); Ok(lit('\x0B')) }
+            'A' => { self.bump(); Ok(Build::Expr(Expr::StartText)) }
+            'z' => { self.bump(); Ok(Build::Expr(Expr::EndText)) }
+            'b' => { self.bump(); Ok(Build::Expr(Expr::WordBoundary)) }
+            'B' => { self.bump(); Ok(Build::Expr(Expr::NotWordBoundary)) }
+            '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7' => self.parse_octal(),
+            'x' => { self.bump(); self.parse_hex() }
+            'p'|'P' => {
+                self.bump();
+                self.parse_unicode_class(c == 'P')
+                    .map(|cls| Build::Expr(Expr::Class(cls)))
+            }
+            'd'|'s'|'w'|'D'|'S'|'W' => {
+                self.bump();
+                Ok(Build::Expr(Expr::Class(self.parse_perl_class(c))))
+            }
+            c => Err(self.err(ErrorKind::UnrecognizedEscape(c))),
+        }
+    }
+
+    // Parses a group, e.g., `(abc)`.
+    //
+    // Start: `(`
+    // End:   `a`
+    //
+    // A more interesting example, `(?P<foo>abc)`.
+    //
+    // Start: `(`
+    // End:   `a`
+    fn parse_group(&mut self) -> Result<Build> {
+        let chari = self.chari;
+        let mut name: CaptureName = None;
+        self.bump();
+        if self.bump_if("?P<") {
+            let n = try!(self.parse_group_name());
+            if self.names.iter().any(|n2| n2 == &n) {
+                return Err(self.err(ErrorKind::DuplicateCaptureName(n)));
+            }
+            self.names.push(n.clone());
+            name = Some(n);
+        } else if self.bump_if("?") {
+            // This can never be capturing. It's either setting flags for
+            // the current group, or it's opening a non-capturing group or
+            // it's opening a group with a specific set of flags (which is
+            // also non-capturing).
+            // Anything else is an error.
+            return self.parse_group_flags(chari);
+        }
+        self.caps = checkadd(self.caps, 1);
+        Ok(Build::LeftParen {
+            i: Some(self.caps),
+            name: name,
+            chari: chari,
+            old_flags: self.flags, // no flags changed if we're here
+        })
+    }
+
+    // Parses flags (inline or grouped), e.g., `(?s-i:abc)`.
+    //
+    // Start: `s`
+    // End:   `a`
+    //
+    // Another example, `(?s-i)a`.
+    //
+    // Start: `s`
+    // End:   `a`
+    fn parse_group_flags(&mut self, opening_chari: usize) -> Result<Build> {
+        let old_flags = self.flags;
+        let mut sign = true;
+        let mut saw_flag = false;
+        loop {
+            if self.eof() {
+                // e.g., (?i
+                return Err(self.err(ErrorKind::UnexpectedFlagEof));
+            }
+            match self.cur() {
+                'i' => { self.flags.casei = sign; saw_flag = true }
+                'm' => { self.flags.multi = sign; saw_flag = true }
+                's' => { self.flags.dotnl = sign; saw_flag = true }
+                'U' => { self.flags.swap_greed = sign; saw_flag = true }
+                'x' => { self.flags.ignore_space = sign; saw_flag = true }
+                '-' => {
+                    if !sign {
+                        // e.g., (?-i-s)
+                        return Err(self.err(ErrorKind::DoubleFlagNegation));
+                    }
+                    sign = false;
+                    saw_flag = false;
+                }
+                ')' => {
+                    if !saw_flag {
+                        // e.g., (?)
+                        return Err(self.err(ErrorKind::EmptyFlagNegation));
+                    }
+                    // At this point, we're just changing the flags inside
+                    // the current group, which means the old flags have
+                    // been saved elsewhere. Our modifications in place are
+                    // okey dokey!
+                    //
+                    // This particular flag expression only has a stateful
+                    // impact on a regex's AST, so nothing gets explicitly
+                    // added.
+                    self.bump();
+                    return Ok(Build::Expr(Expr::Empty));
+                }
+                ':' => {
+                    if !sign && !saw_flag {
+                        // e.g., (?i-:a)
+                        // Note that if there's no negation, it's OK not
+                        // to see flag, because you end up with a regular
+                        // non-capturing group: `(?:a)`.
+                        return Err(self.err(ErrorKind::EmptyFlagNegation));
+                    }
+                    self.bump();
+                    return Ok(Build::LeftParen {
+                        i: None,
+                        name: None,
+                        chari: opening_chari,
+                        old_flags: old_flags,
+                    });
+                }
+                // e.g., (?z:a)
+                c => return Err(self.err(ErrorKind::UnrecognizedFlag(c))),
+            }
+            self.bump();
+        }
+    }
+
+    // Parses a group name, e.g., `foo` in `(?P<foo>abc)`.
+    //
+    // Start: `f`
+    // End:   `a`
+    fn parse_group_name(&mut self) -> Result<String> {
+        let mut name = String::new();
+        while !self.eof() && !self.peek_is('>') {
+            name.push(self.bump());
+        }
+        if self.eof() {
+            // e.g., (?P<a
+            return Err(self.err(ErrorKind::UnclosedCaptureName(name)));
+        }
+        let all_valid = name.chars().all(is_valid_capture_char);
+        match name.chars().next() {
+            // e.g., (?P<>a)
+            None => Err(self.err(ErrorKind::EmptyCaptureName)),
+            Some(c) if (c >= '0' && c <= '9') || !all_valid => {
+                // e.g., (?P<a#>x)
+                // e.g., (?P<1a>x)
+                Err(self.err(ErrorKind::InvalidCaptureName(name)))
+            }
+            _ => {
+                self.bump(); // for `>`
+                Ok(name)
+            }
+        }
+    }
+
+    // Parses a counted repeition operator, e.g., `a{2,4}?z`.
+    //
+    // Start: `{`
+    // End:   `z`
+    fn parse_counted_repeat(&mut self) -> Result<Build> {
+        let e = try!(self.pop(ErrorKind::RepeaterExpectsExpr)); // e.g., ({5}
+        if !e.can_repeat() {
+            // e.g., a*{5}
+            return Err(self.err(ErrorKind::RepeaterUnexpectedExpr(e)));
+        }
+        self.bump();
+        let min = try!(self.parse_decimal(|c| c != ',' && c != '}'));
+        let mut max_opt = Some(min);
+        if self.bump_if(',') {
+            if self.peek_is('}') {
+                max_opt = None;
+            } else {
+                let max = try!(self.parse_decimal(|c| c != '}'));
+                if min > max {
+                    // e.g., a{2,1}
+                    return Err(self.err(ErrorKind::InvalidRepeatRange {
+                        min: min,
+                        max: max,
+                    }));
+                }
+                max_opt = Some(max);
+            }
+        }
+        if !self.bump_if('}') {
+            Err(self.err(ErrorKind::UnclosedRepeat))
+        } else {
+            Ok(Build::Expr(Expr::Repeat {
+                e: Box::new(e),
+                r: Repeater::Range { min: min, max: max_opt },
+                greedy: !self.bump_if('?') ^ self.flags.swap_greed,
+            }))
+        }
+    }
+
+    // Parses a simple repetition operator, e.g., `a+?z`.
+    //
+    // Start: `+`
+    // End:   `z`
+    //
+    // N.B. "simple" in this context means "not min/max repetition",
+    // e.g., `a{1,2}`.
+    fn parse_simple_repeat(&mut self, rep: Repeater) -> Result<Build> {
+        let e = try!(self.pop(ErrorKind::RepeaterExpectsExpr)); // e.g., (*
+        if !e.can_repeat() {
+            // e.g., a**
+            return Err(self.err(ErrorKind::RepeaterUnexpectedExpr(e)));
+        }
+        self.bump();
+        Ok(Build::Expr(Expr::Repeat {
+            e: Box::new(e),
+            r: rep,
+            greedy: !self.bump_if('?') ^ self.flags.swap_greed,
+        }))
+    }
+
+    // Parses a decimal number until the given character, e.g., `a{123,456}`.
+    //
+    // Start: `1`
+    // End:   `,` (where `until == ','`)
+    fn parse_decimal<B: Bumpable>(&mut self, until: B) -> Result<u32> {
+        match self.bump_get(until) {
+            // e.g., a{}
+            None => Err(self.err(ErrorKind::MissingBase10)),
+            Some(n) => {
+                // e.g., a{xyz
+                // e.g., a{9999999999}
+                let n = n.trim();
+                u32::from_str_radix(n, 10)
+                    .map_err(|_| self.err(ErrorKind::InvalidBase10(n.into())))
+            }
+        }
+    }
+
+    // Parses an octal number, up to 3 digits, e.g., `a\123b`
+    //
+    // Start: `1`
+    // End:   `b`
+    fn parse_octal(&mut self) -> Result<Build> {
+        use std::char;
+        let mut i = 0; // counter for limiting octal to 3 digits.
+        let n = self.bump_get(|c| { i += 1; i <= 3 && c >= '0' && c <= '7' })
+                    .expect("octal string"); // guaranteed at least 1 digit
+        // I think both of the following unwraps are impossible to fail.
+        // We limit it to a three digit octal number, which maxes out at
+        // `0777` or `511` in decimal. Since all digits are in `0...7`, we'll
+        // always have a valid `u32` number. Moreover, since all numbers in
+        // the range `0...511` are valid Unicode scalar values, it will always
+        // be a valid `char`.
+        //
+        // Hence, we `unwrap` with reckless abandon.
+        let n = u32::from_str_radix(&n, 8).ok().expect("valid octal number");
+        Ok(Build::Expr(Expr::Literal {
+            chars: vec![char::from_u32(n).expect("Unicode scalar value")],
+            casei: self.flags.casei,
+        }))
+    }
+
+    // Parses a hex number, e.g., `a\x5ab`.
+    //
+    // Start: `5`
+    // End:   `b`
+    //
+    // And also, `a\x{2603}b`.
+    //
+    // Start: `{`
+    // End:   `b`
+    fn parse_hex(&mut self) -> Result<Build> {
+        if self.bump_if('{') {
+            self.parse_hex_many_digits()
+        } else {
+            self.parse_hex_two_digits()
+        }
+    }
+
+    // Parses a many-digit hex number, e.g., `a\x{2603}b`.
+    //
+    // Start: `2`
+    // End:   `b`
+    fn parse_hex_many_digits(&mut self) -> Result<Build> {
+        use std::char;
+
+        let s = self.bump_get(|c| c != '}').unwrap_or("".into());
+        let n = try!(u32::from_str_radix(&s, 16)
+                         .map_err(|_| self.err(ErrorKind::InvalidBase16(s))));
+        let c = try!(char::from_u32(n)
+                          .ok_or(self.err(ErrorKind::InvalidScalarValue(n))));
+        if !self.bump_if('}') {
+            // e.g., a\x{d
+            return Err(self.err(ErrorKind::UnclosedHex));
+        }
+        Ok(Build::Expr(Expr::Literal {
+            chars: vec![c],
+            casei: self.flags.casei,
+        }))
+    }
+
+    // Parses a two-digit hex number, e.g., `a\x5ab`.
+    //
+    // Start: `5`
+    // End:   `b`
+    fn parse_hex_two_digits(&mut self) -> Result<Build> {
+        use std::char;
+
+        let mut i = 0;
+        let s = self.bump_get(|_| { i += 1; i <= 2 }).unwrap_or("".into());
+        if s.len() < 2 {
+            // e.g., a\x
+            // e.g., a\xf
+            return Err(self.err(ErrorKind::UnexpectedTwoDigitHexEof));
+        }
+        let n = try!(u32::from_str_radix(&s, 16)
+                         .map_err(|_| self.err(ErrorKind::InvalidBase16(s))));
+        Ok(Build::Expr(Expr::Literal {
+            // Because 0...255 are all valid Unicode scalar values.
+            chars: vec![char::from_u32(n).expect("Unicode scalar value")],
+            casei: self.flags.casei,
+        }))
+    }
+
+    // Parses a character class, e.g., `[^a-zA-Z0-9]+`.
+    //
+    // Start: `[`
+    // End:   `+`
+    fn parse_class(&mut self) -> Result<Build> {
+        self.bump();
+        let negated = self.bump_if('^');
+        let mut class = CharClass::empty();
+        while self.bump_if('-') {
+            class.ranges.push(ClassRange::one('-'));
+        }
+        loop {
+            if self.eof() {
+                // e.g., [a
+                return Err(self.err(ErrorKind::UnexpectedClassEof));
+            }
+            match self.cur() {
+                // If no ranges have been added, then `]` is the first
+                // character (sans, perhaps, the `^` symbol), so it should
+                // be interpreted as a `]` instead of a closing class bracket.
+                ']' if class.len() > 0 => { self.bump(); break }
+                '[' => match self.maybe_parse_ascii() {
+                    Some(class2) => class.ranges.extend(class2),
+                    None => {
+                        self.bump();
+                        try!(self.parse_class_range(&mut class, '['))
+                    }
+                },
+                '\\' => match try!(self.parse_escape()) {
+                    Build::Expr(Expr::Class(class2)) => {
+                        class.ranges.extend(class2);
+                    }
+                    Build::Expr(Expr::Literal { chars, .. }) => {
+                        try!(self.parse_class_range(&mut class, chars[0]));
+                    }
+                    Build::Expr(e) => {
+                        let err = ErrorKind::InvalidClassEscape(e);
+                        return Err(self.err(err));
+                    }
+                    // Because `parse_escape` can never return `LeftParen`.
+                    _ => unreachable!(),
+                },
+                start => {
+                    self.bump();
+                    try!(self.parse_class_range(&mut class, start));
+                }
+            }
+        }
+        if negated {
+            class = class.negate();
+        }
+        Ok(Build::Expr(Expr::Class(class.canonicalize())))
+    }
+
+    // Parses a single range in a character class.
+    //
+    // Since this is a helper for `parse_class`, its signature sticks out.
+    // Namely, it requires the start character of the range and the char
+    // class to mutate.
+    //
+    // e.g., `[a-z]`
+    //
+    // Start: `-` (with start == `a`)
+    // End:   `]`
+    fn parse_class_range(&mut self, class: &mut CharClass, start: char)
+                        -> Result<()> {
+        if !self.bump_if('-') {
+            // Not a range, so just push a singleton range.
+            class.ranges.push(ClassRange::one(start));
+            return Ok(());
+        }
+        if self.eof() {
+            // e.g., [a-
+            return Err(self.err(ErrorKind::UnexpectedClassEof));
+        }
+        if self.peek_is(']') {
+            // This is the end of the class, so we permit use of `-` as a
+            // regular char (just like we do in the beginning).
+            class.ranges.push(ClassRange::one(start));
+            class.ranges.push(ClassRange::one('-'));
+            return Ok(());
+        }
+
+        // We have a real range. Just need to check to parse literal and
+        // make sure it's a valid range.
+        let end = match self.cur() {
+            '\\' => match try!(self.parse_escape()) {
+                Build::Expr(Expr::Literal { chars, .. }) => chars[0],
+                Build::Expr(e) => {
+                    return Err(self.err(ErrorKind::InvalidClassEscape(e)));
+                }
+                // Because `parse_escape` can never return `LeftParen`.
+                _ => unreachable!(),
+            },
+            _ => self.bump(),
+        };
+        if end < start {
+            // e.g., [z-a]
+            return Err(self.err(ErrorKind::InvalidClassRange {
+                start: start,
+                end: end,
+            }));
+        }
+        class.ranges.push(ClassRange::new(start, end));
+        Ok(())
+    }
+
+    // Parses an ASCII class, e.g., `[:alnum:]+`.
+    //
+    // Start: `[`
+    // End:   `+`
+    //
+    // Also supports negation, e.g., `[:^alnum:]`.
+    //
+    // This parsing routine is distinct from the others in that it doesn't
+    // actually report any errors. Namely, if it fails, then the parser should
+    // fall back to parsing a regular class.
+    //
+    // This method will only make progress in the parser if it succeeds.
+    // Otherwise, the input remains where it started.
+    fn maybe_parse_ascii(&mut self) -> Option<CharClass> {
+        fn parse(p: &mut Parser) -> Option<CharClass> {
+            p.bump(); // the `[`
+            if !p.bump_if(':') { return None; }
+            let negate = p.bump_if('^');
+            let name = match p.bump_get(|c| c != ':') {
+                None => return None,
+                Some(name) => name,
+            };
+            if !p.bump_if(":]") { return None; }
+            ascii_class(&name).map(|c| if !negate { c } else { c.negate() })
+        }
+        let start = self.chari;
+        match parse(self) {
+            None => { self.chari = start; None }
+            result => result,
+        }
+    }
+
+    // Parses a Uncode class name, e.g., `a\pLb`.
+    //
+    // Start: `L`
+    // End:   `b`
+    //
+    // And also, `a\p{Greek}b`.
+    //
+    // Start: `{`
+    // End:   `b`
+    //
+    // `negate` is true when the class name is used with `\P`.
+    fn parse_unicode_class(&mut self, neg: bool) -> Result<CharClass> {
+        let name =
+            if self.bump_if('{') {
+                let n = self.bump_get(|c| c != '}').unwrap_or("".into());
+                if n.is_empty() || !self.bump_if('}') {
+                    // e.g., \p{Greek
+                    return Err(self.err(ErrorKind::UnclosedUnicodeName));
+                }
+                n
+            } else {
+                if self.eof() {
+                    // e.g., \p
+                    return Err(self.err(ErrorKind::UnexpectedEscapeEof));
+                }
+                self.bump().to_string()
+            };
+        match unicode_class(&name) {
+            None => Err(self.err(ErrorKind::UnrecognizedUnicodeClass(name))),
+            Some(cls) => if neg { Ok(cls.negate()) } else { Ok(cls) },
+        }
+    }
+
+    // Parses a perl character class with Unicode support.
+    //
+    // `name` must be one of d, s, w, D, S, W. If not, this function panics.
+    //
+    // No parser state is changed.
+    fn parse_perl_class(&mut self, name: char) -> CharClass {
+        use unicode::regex::{PERLD, PERLS, PERLW};
+        match name {
+            'd' => raw_class_to_expr(PERLD),
+            'D' => raw_class_to_expr(PERLD).negate(),
+            's' => raw_class_to_expr(PERLS),
+            'S' => raw_class_to_expr(PERLS).negate(),
+            'w' => raw_class_to_expr(PERLW),
+            'W' => raw_class_to_expr(PERLW).negate(),
+            _ => unreachable!(),
+        }
+    }
+
+    // Always bump to the next input and return the given expression as a
+    // `Build`.
+    //
+    // This is mostly for convenience when the surrounding context implies
+    // that the next character corresponds to the given expression.
+    fn parse_one(&mut self, e: Expr) -> Build {
+        self.bump();
+        Build::Expr(e)
+    }
+}
+
+// Auxiliary helper methods.
+impl Parser {
+    fn chars(&self) -> Chars {
+        Chars::new(&self.chars[self.chari..], self.flags.ignore_space)
+    }
+
+    fn bump(&mut self) -> char {
+        let c = self.cur();
+        self.chari = checkadd(self.chari, self.chars().next_count());
+        c
+    }
+
+    fn cur(&self) -> char { self.chars().next().unwrap() }
+
+    fn eof(&self) -> bool { self.chars().next().is_none() }
+
+    fn bump_get<B: Bumpable>(&mut self, s: B) -> Option<String> {
+        let n = s.match_end(self);
+        if n == 0 {
+            None
+        } else {
+            let end = checkadd(self.chari, n);
+            let s = self.chars[self.chari..end]
+                        .iter().cloned().collect::<String>();
+            self.chari = end;
+            Some(s)
+        }
+    }
+
+    fn bump_if<B: Bumpable>(&mut self, s: B) -> bool {
+        let n = s.match_end(self);
+        if n == 0 {
+            false
+        } else {
+            self.chari = checkadd(self.chari, n);
+            true
+        }
+    }
+
+    fn peek_is<B: Bumpable>(&self, s: B) -> bool {
+        s.match_end(self) > 0
+    }
+
+    fn err(&self, kind: ErrorKind) -> Error {
+        self.errat(self.chari, kind)
+    }
+
+    fn errat(&self, pos: usize, kind: ErrorKind) -> Error {
+        Error { pos: pos, surround: self.windowat(pos), kind: kind }
+    }
+
+    fn windowat(&self, pos: usize) -> String {
+        let s = max(5, pos) - 5;
+        let e = min(self.chars.len(), checkadd(pos, 5));
+        self.chars[s..e].iter().cloned().collect()
+    }
+
+    fn pop(&mut self, expected: ErrorKind) -> Result<Expr> {
+        match self.stack.pop() {
+            None | Some(Build::LeftParen{..}) => Err(self.err(expected)),
+            Some(Build::Expr(e)) => Ok(e),
+        }
+    }
+
+    // If the current contexts calls for case insensitivity and if the expr
+    // given is a character class, do case folding on it and return the new
+    // class.
+    //
+    // Otherwise, return the expression unchanged.
+    fn maybe_class_case_fold(&mut self, bexpr: Build) -> Build {
+        match bexpr {
+            Build::Expr(Expr::Class(cls)) => {
+                Build::Expr(Expr::Class(
+                    if self.flags.casei && !cls.casei {
+                        cls.case_fold()
+                    } else {
+                        cls
+                    }
+                ))
+            }
+            bexpr => bexpr,
+        }
+    }
+}
+
+struct Chars<'a> {
+    chars: &'a [char],
+    cur: usize,
+    ignore_space: bool,
+    in_comment: bool,
+}
+
+impl<'a> Iterator for Chars<'a> {
+    type Item = char;
+    fn next(&mut self) -> Option<char> {
+        self.skip();
+        if self.cur < self.chars.len() {
+            let c = self.chars[self.cur];
+            self.cur = checkadd(self.cur, 1);
+            Some(c)
+        } else {
+            None
+        }
+    }
+}
+
+impl<'a> Chars<'a> {
+    fn new(chars: &[char], ignore_space: bool) -> Chars {
+        Chars {
+            chars: chars,
+            cur: 0,
+            ignore_space: ignore_space,
+            in_comment: false,
+        }
+    }
+
+    /// Skip line comments and whitespace
+    fn skip(&mut self) {
+        if !self.ignore_space { return; }
+        while self.cur < self.chars.len() {
+            // Handle escaping of `#`, i.e. don't start a comment with `\#`.
+            let next_cur = checkadd(self.cur, 1);
+            if !self.in_comment && self.c() == '\\'
+                && next_cur < self.chars.len()
+                && self.chars[next_cur] == '#'
+            {
+                self.cur = next_cur;
+                break;
+            }
+
+            if !self.in_comment && self.c() == '#' {
+                self.in_comment = true;
+            } else if self.in_comment && self.c() == '\n' {
+                self.in_comment = false;
+            }
+
+            if self.in_comment || self.c().is_whitespace() {
+                self.cur = next_cur;
+            } else {
+                break;
+            }
+        }
+    }
+
+    fn c(&self) -> char {
+        self.chars[self.cur]
+    }
+
+    fn next_count(&mut self) -> usize {
+        self.next();
+        self.cur
+    }
+}
+
+// Auxiliary methods for manipulating the expression stack.
+impl Parser {
+    // Called whenever an alternate (`|`) is found.
+    //
+    // This pops the expression stack until:
+    //
+    //  1. The stack is empty. Pushes an alternation with one arm.
+    //  2. An opening parenthesis is found. Leave the parenthesis
+    //     on the stack and push an alternation with one arm.
+    //  3. An alternate (`|`) is found. Pop the existing alternation,
+    //     add an arm and push the modified alternation.
+    //
+    // Each "arm" in the above corresponds to the concatenation of all
+    // popped expressions.
+    //
+    // In the first two cases, the stack is left in an invalid state
+    // because an alternation with one arm is not allowed. This
+    // particular state will be detected by `finish_concat` and an
+    // error will be reported.
+    //
+    // In none of the cases is an empty arm allowed. If an empty arm
+    // is found, an error is reported.
+    fn alternate(&mut self) -> Result<Build> {
+        let mut concat = vec![];
+        let alts = |es| Ok(Build::Expr(Expr::Alternate(es)));
+        loop {
+            match self.stack.pop() {
+                None => {
+                    if concat.is_empty() {
+                        // e.g., |a
+                        return Err(self.err(ErrorKind::EmptyAlternate));
+                    }
+                    return alts(vec![rev_concat(concat)]);
+                }
+                Some(e @ Build::LeftParen{..}) => {
+                    if concat.is_empty() {
+                        // e.g., (|a)
+                        return Err(self.err(ErrorKind::EmptyAlternate));
+                    }
+                    self.stack.push(e);
+                    return alts(vec![rev_concat(concat)]);
+                }
+                Some(Build::Expr(Expr::Alternate(mut es))) => {
+                    if concat.is_empty() {
+                        // e.g., a||
+                        return Err(self.err(ErrorKind::EmptyAlternate));
+                    }
+                    es.push(rev_concat(concat));
+                    return alts(es);
+                }
+                Some(Build::Expr(e)) => { concat.push(e); }
+            }
+        }
+    }
+
+    // Called whenever a closing parenthesis (`)`) is found.
+    //
+    // This pops the expression stack until:
+    //
+    //  1. The stack is empty. An error is reported because this
+    //     indicates an unopened parenthesis.
+    //  2. An opening parenthesis is found. Pop the opening parenthesis
+    //     and push a `Group` expression.
+    //  3. An alternate (`|`) is found. Pop the existing alternation
+    //     and an arm to it in place. Pop one more item from the stack.
+    //     If the stack was empty, then report an unopened parenthesis
+    //     error, otherwise assume it is an opening parenthesis and
+    //     push a `Group` expression with the popped alternation.
+    //     (We can assume this is an opening parenthesis because an
+    //     alternation either corresponds to the entire Regex or it
+    //     corresponds to an entire group. This is guaranteed by the
+    //     `alternate` method.)
+    //
+    // Each "arm" in the above corresponds to the concatenation of all
+    // popped expressions.
+    //
+    // Empty arms nor empty groups are allowed.
+    fn close_paren(&mut self) -> Result<(Flags, Build)> {
+        let mut concat = vec![];
+        loop {
+            match self.stack.pop() {
+                // e.g., )
+                None => return Err(self.err(ErrorKind::UnopenedParen)),
+                Some(Build::LeftParen { i, name, old_flags, .. }) => {
+                    if concat.is_empty() {
+                        // e.g., ()
+                        return Err(self.err(ErrorKind::EmptyGroup));
+                    }
+                    return Ok((old_flags, Build::Expr(Expr::Group {
+                        e: Box::new(rev_concat(concat)),
+                        i: i,
+                        name: name,
+                    })));
+                }
+                Some(Build::Expr(Expr::Alternate(mut es))) => {
+                    if concat.is_empty() {
+                        // e.g., (a|)
+                        return Err(self.err(ErrorKind::EmptyAlternate));
+                    }
+                    es.push(rev_concat(concat));
+                    match self.stack.pop() {
+                        // e.g., a|b)
+                        None => return Err(self.err(ErrorKind::UnopenedParen)),
+                        Some(Build::Expr(_)) => unreachable!(),
+                        Some(Build::LeftParen { i, name, old_flags, .. }) => {
+                            return Ok((old_flags, Build::Expr(Expr::Group {
+                                e: Box::new(Expr::Alternate(es)),
+                                i: i,
+                                name: name,
+                            })));
+                        }
+                    }
+                }
+                Some(Build::Expr(e)) => { concat.push(e); }
+            }
+        }
+    }
+
+    // Called only when the parser reaches the end of input.
+    //
+    // This pops the expression stack until:
+    //
+    //  1. The stack is empty. Return concatenation of popped
+    //     expressions. This concatenation may be empty!
+    //  2. An alternation is found. Pop the alternation and push
+    //     a new arm. Return the alternation as the entire Regex.
+    //
+    // If an opening parenthesis is popped, then an error is
+    // returned since it indicates an unclosed parenthesis.
+    fn finish_concat(&mut self) -> Result<Expr> {
+        let mut concat = vec![];
+        loop {
+            match self.stack.pop() {
+                None => { return Ok(rev_concat(concat)); }
+                Some(Build::LeftParen{ chari, ..}) => {
+                    // e.g., a(b
+                    return Err(self.errat(chari, ErrorKind::UnclosedParen));
+                }
+                Some(Build::Expr(Expr::Alternate(mut es))) => {
+                    if concat.is_empty() {
+                        // e.g., a|
+                        return Err(self.err(ErrorKind::EmptyAlternate));
+                    }
+                    es.push(rev_concat(concat));
+                    return Ok(Expr::Alternate(es));
+                }
+                Some(Build::Expr(e)) => { concat.push(e); }
+            }
+        }
+    }
+}
+
+impl Build {
+    fn is_empty(&self) -> bool {
+        match *self {
+            Build::Expr(Expr::Empty) => true,
+            _ => false,
+        }
+    }
+}
+
+// Make it ergonomic to conditionally bump the parser.
+// i.e., `bump_if('a')` or `bump_if("abc")`.
+trait Bumpable {
+    fn match_end(self, p: &Parser) -> usize;
+}
+
+impl Bumpable for char {
+    fn match_end(self, p: &Parser) -> usize {
+        let mut chars = p.chars();
+        if chars.next().map(|c| c == self).unwrap_or(false) {
+            chars.cur
+        } else {
+            0
+        }
+    }
+}
+
+impl<'a> Bumpable for &'a str {
+    fn match_end(self, p: &Parser) -> usize {
+        let mut search = self.chars();
+        let mut rest = p.chars();
+        let mut count = 0;
+        loop {
+            match (rest.next(), search.next()) {
+                (Some(c1), Some(c2)) if c1 == c2 => count = rest.cur,
+                (_, None) => return count,
+                _ => return 0,
+            }
+        }
+    }
+}
+
+impl<F: FnMut(char) -> bool> Bumpable for F {
+    fn match_end(mut self, p: &Parser) -> usize {
+        let mut chars = p.chars();
+        let mut count = 0;
+        while let Some(c) = chars.next() {
+            if !self(c) {
+                break
+            }
+            count = chars.cur;
+        }
+        count
+    }
+}
+
+// Turn a sequence of expressions into a concatenation.
+// This only uses `Concat` if there are 2 or more expressions.
+fn rev_concat(mut exprs: Vec<Expr>) -> Expr {
+    if exprs.len() == 0 {
+        Expr::Empty
+    } else if exprs.len() == 1 {
+        exprs.pop().unwrap()
+    } else {
+        exprs.reverse();
+        Expr::Concat(exprs)
+    }
+}
+
+// Returns true if and only if the given character is allowed in a capture
+// name. Note that the first char of a capture name must not be numeric.
+fn is_valid_capture_char(c: char) -> bool {
+    c == '_' || (c >= '0' && c <= '9')
+    || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+/// Returns true if the give character has significance in a regex.
+#[doc(hidden)]
+pub fn is_punct(c: char) -> bool {
+    match c {
+        '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' |
+        '[' | ']' | '{' | '}' | '^' | '$' | '#' => true,
+        _ => false,
+    }
+}
+
+fn checkadd(x: usize, y: usize) -> usize {
+    x.checked_add(y).expect("regex length overflow")
+}
+
+fn unicode_class(name: &str) -> Option<CharClass> {
+    UNICODE_CLASSES.binary_search_by(|&(s, _)| s.cmp(name)).ok().map(|i| {
+        raw_class_to_expr(UNICODE_CLASSES[i].1)
+    })
+}
+
+fn ascii_class(name: &str) -> Option<CharClass> {
+    ASCII_CLASSES.binary_search_by(|&(s, _)| s.cmp(name)).ok().map(|i| {
+        raw_class_to_expr(ASCII_CLASSES[i].1)
+    })
+}
+
+fn raw_class_to_expr(raw: &[(char, char)]) -> CharClass {
+    let range = |&(s, e)| ClassRange { start: s, end: e };
+    CharClass::new(raw.iter().map(range).collect())
+}
+
+type Class = &'static [(char, char)];
+type NamedClasses = &'static [(&'static str, Class)];
+
+const ASCII_CLASSES: NamedClasses = &[
+    // Classes must be in alphabetical order so that bsearch works.
+    // [:alnum:]      alphanumeric (== [0-9A-Za-z])
+    // [:alpha:]      alphabetic (== [A-Za-z])
+    // [:ascii:]      ASCII (== [\x00-\x7F])
+    // [:blank:]      blank (== [\t ])
+    // [:cntrl:]      control (== [\x00-\x1F\x7F])
+    // [:digit:]      digits (== [0-9])
+    // [:graph:]      graphical (== [!-~])
+    // [:lower:]      lower case (== [a-z])
+    // [:print:]      printable (== [ -~] == [ [:graph:]])
+    // [:punct:]      punctuation (== [!-/:-@[-`{-~])
+    // [:space:]      whitespace (== [\t\n\v\f\r ])
+    // [:upper:]      upper case (== [A-Z])
+    // [:word:]       word characters (== [0-9A-Za-z_])
+    // [:xdigit:]     hex digit (== [0-9A-Fa-f])
+    // Taken from: http://golang.org/pkg/regex/syntax/
+    ("alnum", &ALNUM),
+    ("alpha", &ALPHA),
+    ("ascii", &ASCII),
+    ("blank", &BLANK),
+    ("cntrl", &CNTRL),
+    ("digit", &DIGIT),
+    ("graph", &GRAPH),
+    ("lower", &LOWER),
+    ("print", &PRINT),
+    ("punct", &PUNCT),
+    ("space", &SPACE),
+    ("upper", &UPPER),
+    ("word", &WORD),
+    ("xdigit", &XDIGIT),
+];
+
+const ALNUM: Class = &[('0', '9'), ('A', 'Z'), ('a', 'z')];
+const ALPHA: Class = &[('A', 'Z'), ('a', 'z')];
+const ASCII: Class = &[('\x00', '\x7F')];
+const BLANK: Class = &[(' ', ' '), ('\t', '\t')];
+const CNTRL: Class = &[('\x00', '\x1F'), ('\x7F', '\x7F')];
+const DIGIT: Class = &[('0', '9')];
+const GRAPH: Class = &[('!', '~')];
+const LOWER: Class = &[('a', 'z')];
+const PRINT: Class = &[(' ', '~')];
+const PUNCT: Class = &[('!', '/'), (':', '@'), ('[', '`'), ('{', '~')];
+const SPACE: Class = &[('\t', '\t'), ('\n', '\n'), ('\x0B', '\x0B'),
+                       ('\x0C', '\x0C'), ('\r', '\r'), (' ', ' ')];
+const UPPER: Class = &[('A', 'Z')];
+const WORD: Class = &[('0', '9'), ('A', 'Z'), ('a', 'z'), ('_', '_')];
+const XDIGIT: Class = &[('0', '9'), ('A', 'F'), ('a', 'f')];
+
+#[cfg(test)]
+mod tests {
+    use { CharClass, ClassRange, Expr, Repeater, ErrorKind };
+    use unicode::regex::{PERLD, PERLS, PERLW};
+    use super::Parser;
+    use super::{LOWER, UPPER};
+
+    static YI: &'static [(char, char)] = &[
+        ('\u{a000}', '\u{a48c}'), ('\u{a490}', '\u{a4c6}'),
+    ];
+
+    fn p(s: &str) -> Expr { Parser::parse(s).unwrap() }
+    fn lit(c: char) -> Expr { Expr::Literal { chars: vec![c], casei: false } }
+    fn liti(c: char) -> Expr { Expr::Literal { chars: vec![c], casei: true } }
+    fn b<T>(v: T) -> Box<T> { Box::new(v) }
+    fn c(es: &[Expr]) -> Expr { Expr::Concat(es.to_vec()) }
+
+    fn class(ranges: &[(char, char)]) -> CharClass {
+        let ranges = ranges.iter().cloned()
+                           .map(|(c1, c2)| ClassRange::new(c1, c2)).collect();
+        CharClass::new(ranges)
+    }
+
+    fn classes(classes: &[&[(char, char)]]) -> CharClass {
+        let mut cls = CharClass::empty();
+        for &ranges in classes {
+            cls.ranges.extend(class(ranges));
+        }
+        cls.canonicalize()
+    }
+
+    #[test]
+    fn empty() {
+        assert_eq!(p(""), Expr::Empty);
+    }
+
+    #[test]
+    fn literal() {
+        assert_eq!(p("a"), lit('a'));
+    }
+
+    #[test]
+    fn literal_string() {
+        assert_eq!(p("ab"), Expr::Concat(vec![lit('a'), lit('b')]));
+    }
+
+    #[test]
+    fn start_literal() {
+        assert_eq!(p("^a"), Expr::Concat(vec![
+            Expr::StartText,
+            Expr::Literal { chars: vec!['a'], casei: false },
+        ]));
+    }
+
+    #[test]
+    fn repeat_zero_or_one_greedy() {
+        assert_eq!(p("a?"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::ZeroOrOne,
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn repeat_zero_or_one_greedy_concat() {
+        assert_eq!(p("ab?"), Expr::Concat(vec![
+            lit('a'),
+            Expr::Repeat {
+                e: b(lit('b')),
+                r: Repeater::ZeroOrOne,
+                greedy: true,
+            },
+        ]));
+    }
+
+    #[test]
+    fn repeat_zero_or_one_nongreedy() {
+        assert_eq!(p("a??"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::ZeroOrOne,
+            greedy: false,
+        });
+    }
+
+    #[test]
+    fn repeat_one_or_more_greedy() {
+        assert_eq!(p("a+"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::OneOrMore,
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn repeat_one_or_more_nongreedy() {
+        assert_eq!(p("a+?"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::OneOrMore,
+            greedy: false,
+        });
+    }
+
+    #[test]
+    fn repeat_zero_or_more_greedy() {
+        assert_eq!(p("a*"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::ZeroOrMore,
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn repeat_zero_or_more_nongreedy() {
+        assert_eq!(p("a*?"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::ZeroOrMore,
+            greedy: false,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_exact() {
+        assert_eq!(p("a{5}"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: Some(5) },
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_min() {
+        assert_eq!(p("a{5,}"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: None },
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_min_max() {
+        assert_eq!(p("a{5,10}"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: Some(10) },
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_exact_nongreedy() {
+        assert_eq!(p("a{5}?"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: Some(5) },
+            greedy: false,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_min_nongreedy() {
+        assert_eq!(p("a{5,}?"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: None },
+            greedy: false,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_min_max_nongreedy() {
+        assert_eq!(p("a{5,10}?"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: Some(10) },
+            greedy: false,
+        });
+    }
+
+    #[test]
+    fn repeat_counted_whitespace() {
+        assert_eq!(p("a{ 5   }"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: Some(5) },
+            greedy: true,
+        });
+        assert_eq!(p("a{ 5 , 10 }"), Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::Range { min: 5, max: Some(10) },
+            greedy: true,
+        });
+    }
+
+    #[test]
+    fn group_literal() {
+        assert_eq!(p("(a)"), Expr::Group {
+            e: b(lit('a')),
+            i: Some(1),
+            name: None,
+        });
+    }
+
+    #[test]
+    fn group_literal_concat() {
+        assert_eq!(p("(ab)"), Expr::Group {
+            e: b(c(&[lit('a'), lit('b')])),
+            i: Some(1),
+            name: None,
+        });
+    }
+
+    #[test]
+    fn alt_two() {
+        assert_eq!(p("a|b"), Expr::Alternate(vec![lit('a'), lit('b')]));
+    }
+
+    #[test]
+    fn alt_many() {
+        assert_eq!(p("a|b|c"), Expr::Alternate(vec![
+            lit('a'), lit('b'), lit('c'),
+        ]));
+    }
+
+    #[test]
+    fn alt_many_concat() {
+        assert_eq!(p("ab|bc|cd"), Expr::Alternate(vec![
+            c(&[lit('a'), lit('b')]),
+            c(&[lit('b'), lit('c')]),
+            c(&[lit('c'), lit('d')]),
+        ]));
+    }
+
+    #[test]
+    fn alt_group_two() {
+        assert_eq!(p("(a|b)"), Expr::Group {
+            e: b(Expr::Alternate(vec![lit('a'), lit('b')])),
+            i: Some(1),
+            name: None,
+        });
+    }
+
+    #[test]
+    fn alt_group_many() {
+        assert_eq!(p("(a|b|c)"), Expr::Group {
+            e: b(Expr::Alternate(vec![lit('a'), lit('b'), lit('c')])),
+            i: Some(1),
+            name: None,
+        });
+    }
+
+    #[test]
+    fn alt_group_many_concat() {
+        assert_eq!(p("(ab|bc|cd)"), Expr::Group {
+            e: b(Expr::Alternate(vec![
+                c(&[lit('a'), lit('b')]),
+                c(&[lit('b'), lit('c')]),
+                c(&[lit('c'), lit('d')]),
+            ])),
+            i: Some(1),
+            name: None,
+        });
+    }
+
+    #[test]
+    fn alt_group_nested() {
+        assert_eq!(p("(ab|(bc|(cd)))"), Expr::Group {
+            e: b(Expr::Alternate(vec![
+                c(&[lit('a'), lit('b')]),
+                Expr::Group {
+                    e: b(Expr::Alternate(vec![
+                        c(&[lit('b'), lit('c')]),
+                        Expr::Group {
+                            e: b(c(&[lit('c'), lit('d')])),
+                            i: Some(3),
+                            name: None,
+                        }
+                    ])),
+                    i: Some(2),
+                    name: None,
+                },
+            ])),
+            i: Some(1),
+            name: None,
+        });
+    }
+
+    #[test]
+    fn group_name() {
+        assert_eq!(p("(?P<foo>a)"), Expr::Group {
+            e: b(lit('a')),
+            i: Some(1),
+            name: Some("foo".into()),
+        });
+    }
+
+    #[test]
+    fn group_no_capture() {
+        assert_eq!(p("(?:a)"), Expr::Group {
+            e: b(lit('a')),
+            i: None,
+            name: None,
+        });
+    }
+
+    #[test]
+    fn group_flags() {
+        assert_eq!(p("(?i:a)"), Expr::Group {
+            e: b(liti('a')),
+            i: None,
+            name: None,
+        });
+    }
+
+    #[test]
+    fn group_flags_returned() {
+        assert_eq!(p("(?i:a)a"), c(&[
+            Expr::Group {
+                e: b(liti('a')),
+                i: None,
+                name: None,
+            },
+            lit('a'),
+        ]));
+    }
+
+    #[test]
+    fn group_flags_retained() {
+        assert_eq!(p("(?i)(?-i:a)a"), c(&[
+            Expr::Group {
+                e: b(lit('a')),
+                i: None,
+                name: None,
+            },
+            liti('a'),
+        ]));
+    }
+
+    #[test]
+    fn flags_inline() {
+        assert_eq!(p("(?i)a"), liti('a'));
+    }
+
+    #[test]
+    fn flags_inline_multiple() {
+        assert_eq!(p("(?is)a."), c(&[liti('a'), Expr::AnyChar]));
+    }
+
+    #[test]
+    fn flags_inline_multiline() {
+        assert_eq!(p("(?m)^(?-m)$"), c(&[Expr::StartLine, Expr::EndText]));
+    }
+
+    #[test]
+    fn flags_inline_swap_greed() {
+        assert_eq!(p("(?U)a*a*?(?i-U)a*a*?"), c(&[
+            Expr::Repeat {
+                e: b(lit('a')),
+                r: Repeater::ZeroOrMore,
+                greedy: false,
+            },
+            Expr::Repeat {
+                e: b(lit('a')),
+                r: Repeater::ZeroOrMore,
+                greedy: true,
+            },
+            Expr::Repeat {
+                e: b(liti('a')),
+                r: Repeater::ZeroOrMore,
+                greedy: true,
+            },
+            Expr::Repeat {
+                e: b(liti('a')),
+                r: Repeater::ZeroOrMore,
+                greedy: false,
+            },
+        ]));
+    }
+
+    #[test]
+    fn flags_inline_multiple_negate_one() {
+        assert_eq!(p("(?is)a.(?i-s)a."), c(&[
+            liti('a'), Expr::AnyChar, liti('a'), Expr::AnyCharNoNL,
+        ]));
+    }
+
+    #[test]
+    fn flags_inline_negate() {
+        assert_eq!(p("(?i)a(?-i)a"), c(&[liti('a'), lit('a')]));
+    }
+
+    #[test]
+    fn flags_group_inline() {
+        assert_eq!(p("(a(?i)a)a"), c(&[
+            Expr::Group {
+                e: b(c(&[lit('a'), liti('a')])),
+                i: Some(1),
+                name: None,
+            },
+            lit('a'),
+        ]));
+    }
+
+    #[test]
+    fn flags_group_inline_retain() {
+        assert_eq!(p("(?i)((?-i)a)a"), c(&[
+            Expr::Group {
+                e: b(lit('a')),
+                i: Some(1),
+                name: None,
+            },
+            liti('a'),
+        ]));
+    }
+
+    #[test]
+    fn escape_simple() {
+        assert_eq!(p(r"\a\f\t\n\r\v"), c(&[
+            lit('\x07'), lit('\x0C'), lit('\t'),
+            lit('\n'), lit('\r'), lit('\x0B'),
+        ]));
+    }
+
+    #[test]
+    fn escape_boundaries() {
+        assert_eq!(p(r"\A\z\b\B"), c(&[
+            Expr::StartText, Expr::EndText,
+            Expr::WordBoundary, Expr::NotWordBoundary,
+        ]));
+    }
+
+    #[test]
+    fn escape_punctuation() {
+        assert_eq!(p(r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#"), c(&[
+            lit('\\'), lit('.'), lit('+'), lit('*'), lit('?'),
+            lit('('), lit(')'), lit('|'), lit('['), lit(']'),
+            lit('{'), lit('}'), lit('^'), lit('$'), lit('#'),
+        ]));
+    }
+
+    #[test]
+    fn escape_octal() {
+        assert_eq!(p(r"\123"), lit('S'));
+        assert_eq!(p(r"\1234"), c(&[lit('S'), lit('4')]));
+    }
+
+    #[test]
+    fn escape_hex2() {
+        assert_eq!(p(r"\x53"), lit('S'));
+        assert_eq!(p(r"\x534"), c(&[lit('S'), lit('4')]));
+    }
+
+    #[test]
+    fn escape_hex() {
+        assert_eq!(p(r"\x{53}"), lit('S'));
+        assert_eq!(p(r"\x{53}4"), c(&[lit('S'), lit('4')]));
+        assert_eq!(p(r"\x{2603}"), lit('\u{2603}'));
+    }
+
+    #[test]
+    fn escape_unicode_name() {
+        assert_eq!(p(r"\p{Yi}"), Expr::Class(class(YI)));
+    }
+
+    #[test]
+    fn escape_unicode_letter() {
+        assert_eq!(p(r"\pZ"), Expr::Class(class(&[
+            ('\u{20}', '\u{20}'), ('\u{a0}', '\u{a0}'),
+            ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'),
+            ('\u{2028}', '\u{2029}'), ('\u{202f}', '\u{202f}'),
+            ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}'),
+        ])));
+    }
+
+    #[test]
+    fn escape_unicode_name_case_fold() {
+        assert_eq!(p(r"(?i)\p{Yi}"), Expr::Class(class(YI).case_fold()));
+    }
+
+    #[test]
+    fn escape_unicode_letter_case_fold() {
+        assert_eq!(p(r"(?i)\pZ"), Expr::Class(class(&[
+            ('\u{20}', '\u{20}'), ('\u{a0}', '\u{a0}'),
+            ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'),
+            ('\u{2028}', '\u{2029}'), ('\u{202f}', '\u{202f}'),
+            ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}'),
+        ]).case_fold()));
+    }
+
+    #[test]
+    fn escape_unicode_name_negate() {
+        assert_eq!(p(r"\P{Yi}"), Expr::Class(class(YI).negate()));
+    }
+
+    #[test]
+    fn escape_unicode_letter_negate() {
+        assert_eq!(p(r"\PZ"), Expr::Class(class(&[
+            ('\u{20}', '\u{20}'), ('\u{a0}', '\u{a0}'),
+            ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'),
+            ('\u{2028}', '\u{2029}'), ('\u{202f}', '\u{202f}'),
+            ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}'),
+        ]).negate()));
+    }
+
+    #[test]
+    fn escape_unicode_name_negate_case_fold() {
+        assert_eq!(p(r"(?i)\P{Yi}"),
+                   Expr::Class(class(YI).negate().case_fold()));
+    }
+
+    #[test]
+    fn escape_unicode_letter_negate_case_fold() {
+        assert_eq!(p(r"(?i)\PZ"), Expr::Class(class(&[
+            ('\u{20}', '\u{20}'), ('\u{a0}', '\u{a0}'),
+            ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'),
+            ('\u{2028}', '\u{2029}'), ('\u{202f}', '\u{202f}'),
+            ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}'),
+        ]).negate().case_fold()));
+    }
+
+    #[test]
+    fn escape_perl_d() {
+        assert_eq!(p(r"\d"), Expr::Class(class(PERLD)));
+    }
+
+    #[test]
+    fn escape_perl_s() {
+        assert_eq!(p(r"\s"), Expr::Class(class(PERLS)));
+    }
+
+    #[test]
+    fn escape_perl_w() {
+        assert_eq!(p(r"\w"), Expr::Class(class(PERLW)));
+    }
+
+    #[test]
+    fn escape_perl_d_negate() {
+        assert_eq!(p(r"\D"), Expr::Class(class(PERLD).negate()));
+    }
+
+    #[test]
+    fn escape_perl_s_negate() {
+        assert_eq!(p(r"\S"), Expr::Class(class(PERLS).negate()));
+    }
+
+    #[test]
+    fn escape_perl_w_negate() {
+        assert_eq!(p(r"\W"), Expr::Class(class(PERLW).negate()));
+    }
+
+    #[test]
+    fn escape_perl_d_case_fold() {
+        assert_eq!(p(r"(?i)\d"), Expr::Class(class(PERLD).case_fold()));
+    }
+
+    #[test]
+    fn escape_perl_s_case_fold() {
+        assert_eq!(p(r"(?i)\s"), Expr::Class(class(PERLS).case_fold()));
+    }
+
+    #[test]
+    fn escape_perl_w_case_fold() {
+        assert_eq!(p(r"(?i)\w"), Expr::Class(class(PERLW).case_fold()));
+    }
+
+    #[test]
+    fn escape_perl_d_case_fold_negate() {
+        assert_eq!(p(r"(?i)\D"),
+                   Expr::Class(class(PERLD).negate().case_fold()));
+    }
+
+    #[test]
+    fn escape_perl_s_case_fold_negate() {
+        assert_eq!(p(r"(?i)\S"),
+                   Expr::Class(class(PERLS).negate().case_fold()));
+    }
+
+    #[test]
+    fn escape_perl_w_case_fold_negate() {
+        assert_eq!(p(r"(?i)\W"),
+                   Expr::Class(class(PERLW).negate().case_fold()));
+    }
+
+    #[test]
+    fn class_singleton() {
+        assert_eq!(p(r"[a]"), Expr::Class(class(&[('a', 'a')])));
+        assert_eq!(p(r"[\x00]"), Expr::Class(class(&[('\x00', '\x00')])));
+        assert_eq!(p(r"[\n]"), Expr::Class(class(&[('\n', '\n')])));
+        assert_eq!(p("[\n]"), Expr::Class(class(&[('\n', '\n')])));
+    }
+
+    #[test]
+    fn class_singleton_negate() {
+        assert_eq!(p(r"[^a]"), Expr::Class(class(&[
+            ('\x00', '\x60'), ('\x62', '\u{10FFFF}'),
+        ])));
+        assert_eq!(p(r"[^\x00]"), Expr::Class(class(&[
+            ('\x01', '\u{10FFFF}'),
+        ])));
+        assert_eq!(p(r"[^\n]"), Expr::Class(class(&[
+            ('\x00', '\x09'), ('\x0b', '\u{10FFFF}'),
+        ])));
+        assert_eq!(p("[^\n]"), Expr::Class(class(&[
+            ('\x00', '\x09'), ('\x0b', '\u{10FFFF}'),
+        ])));
+    }
+
+    #[test]
+    fn class_singleton_class() {
+        assert_eq!(p(r"[\d]"), Expr::Class(class(PERLD)));
+        assert_eq!(p(r"[\p{Yi}]"), Expr::Class(class(YI)));
+    }
+
+    #[test]
+    fn class_singleton_class_negate() {
+        assert_eq!(p(r"[^\d]"), Expr::Class(class(PERLD).negate()));
+        assert_eq!(p(r"[^\w]"), Expr::Class(class(PERLW).negate()));
+        assert_eq!(p(r"[^\s]"), Expr::Class(class(PERLS).negate()));
+    }
+
+    #[test]
+    fn class_singleton_class_negate_negate() {
+        assert_eq!(p(r"[^\D]"), Expr::Class(class(PERLD)));
+        assert_eq!(p(r"[^\W]"), Expr::Class(class(PERLW)));
+        assert_eq!(p(r"[^\S]"), Expr::Class(class(PERLS)));
+    }
+
+    #[test]
+    fn class_singleton_class_casei() {
+        assert_eq!(p(r"(?i)[\d]"), Expr::Class(class(PERLD).case_fold()));
+        assert_eq!(p(r"(?i)[\p{Yi}]"), Expr::Class(class(YI).case_fold()));
+    }
+
+    #[test]
+    fn class_singleton_class_negate_casei() {
+        assert_eq!(p(r"(?i)[^\d]"),
+                   Expr::Class(class(PERLD).negate().case_fold()));
+        assert_eq!(p(r"(?i)[^\w]"),
+                   Expr::Class(class(PERLW).negate().case_fold()));
+        assert_eq!(p(r"(?i)[^\s]"),
+                   Expr::Class(class(PERLS).negate().case_fold()));
+    }
+
+    #[test]
+    fn class_singleton_class_negate_negate_casei() {
+        assert_eq!(p(r"(?i)[^\D]"), Expr::Class(class(PERLD).case_fold()));
+        assert_eq!(p(r"(?i)[^\W]"), Expr::Class(class(PERLW).case_fold()));
+        assert_eq!(p(r"(?i)[^\S]"), Expr::Class(class(PERLS).case_fold()));
+    }
+
+    #[test]
+    fn class_multiple_class() {
+        assert_eq!(p(r"[\d\p{Yi}]"), Expr::Class(classes(&[
+            PERLD, YI,
+        ])));
+    }
+
+    #[test]
+    fn class_multiple_class_negate() {
+        assert_eq!(p(r"[^\d\p{Yi}]"), Expr::Class(classes(&[
+            PERLD, YI,
+        ]).negate()));
+    }
+
+    #[test]
+    fn class_multiple_class_negate_negate() {
+        let nperld = class(PERLD).negate();
+        let nyi = class(YI).negate();
+        let cls = CharClass::empty().merge(nperld).merge(nyi);
+        assert_eq!(p(r"[^\D\P{Yi}]"), Expr::Class(cls.negate()));
+    }
+
+    #[test]
+    fn class_multiple_class_casei() {
+        assert_eq!(p(r"(?i)[\d\p{Yi}]"), Expr::Class(classes(&[
+            PERLD, YI,
+        ]).case_fold()));
+    }
+
+    #[test]
+    fn class_multiple_class_negate_casei() {
+        assert_eq!(p(r"(?i)[^\d\p{Yi}]"), Expr::Class(classes(&[
+            PERLD, YI,
+        ]).negate().case_fold()));
+    }
+
+    #[test]
+    fn class_multiple_class_negate_negate_casei() {
+        let nperld = class(PERLD).negate();
+        let nyi = class(YI).negate();
+        let class = CharClass::empty().merge(nperld).merge(nyi);
+        assert_eq!(p(r"(?i)[^\D\P{Yi}]"),
+                   Expr::Class(class.negate().case_fold()));
+    }
+
+    #[test]
+    fn class_class_hypen() {
+        assert_eq!(p(r"[\p{Yi}-]"), Expr::Class(classes(&[
+            &[('-', '-')], YI,
+        ])));
+        assert_eq!(p(r"[\p{Yi}-a]"), Expr::Class(classes(&[
+            &[('-', '-')], &[('a', 'a')], YI,
+        ])));
+    }
+
+    #[test]
+    fn class_brackets() {
+        assert_eq!(p("[]]"), Expr::Class(class(&[(']', ']')])));
+        assert_eq!(p("[][]"), Expr::Class(class(&[('[', '['), (']', ']')])));
+        assert_eq!(p("[[]]"), Expr::Concat(vec![
+            Expr::Class(class(&[('[', '[')])),
+            lit(']'),
+        ]));
+    }
+
+    #[test]
+    fn class_brackets_hypen() {
+        assert_eq!(p("[]-]"), Expr::Class(class(&[('-', '-'), (']', ']')])));
+        assert_eq!(p("[-]]"), Expr::Concat(vec![
+            Expr::Class(class(&[('-', '-')])),
+            lit(']'),
+        ]));
+    }
+
+    #[test]
+    fn class_overlapping() {
+        assert_eq!(p("[a-fd-h]"), Expr::Class(class(&[('a', 'h')])));
+        assert_eq!(p("[a-fg-m]"), Expr::Class(class(&[('a', 'm')])));
+    }
+
+    #[test]
+    fn ascii_class() {
+        assert_eq!(p("[:upper:]"), Expr::Class(class(UPPER)));
+        assert_eq!(p("[[:upper:]]"), Expr::Class(class(UPPER)));
+    }
+
+    #[test]
+    fn ascii_class_not() {
+        assert_eq!(p("[:abc:]"),
+                   Expr::Class(class(&[(':', ':'), ('a', 'c')])));
+    }
+
+    #[test]
+    fn ascii_class_multiple() {
+        assert_eq!(p("[[:lower:][:upper:]]"),
+                   Expr::Class(classes(&[UPPER, LOWER])));
+    }
+
+    #[test]
+    fn ascii_class_negate() {
+        assert_eq!(p("[[:^upper:]]"), Expr::Class(class(UPPER).negate()));
+        assert_eq!(p("[^[:^upper:]]"), Expr::Class(class(UPPER)));
+    }
+
+    #[test]
+    fn ascii_class_negate_multiple() {
+        let (nlower, nupper) = (class(LOWER).negate(), class(UPPER).negate());
+        let cls = CharClass::empty().merge(nlower).merge(nupper);
+        assert_eq!(p("[[:^lower:][:^upper:]]"), Expr::Class(cls.clone()));
+        assert_eq!(p("[^[:^lower:][:^upper:]]"), Expr::Class(cls.negate()));
+    }
+
+    #[test]
+    fn ascii_class_case_fold() {
+        assert_eq!(p("(?i)[:upper:]"), Expr::Class(class(UPPER).case_fold()));
+        assert_eq!(p("(?i)[[:upper:]]"),
+                   Expr::Class(class(UPPER).case_fold()));
+    }
+
+    #[test]
+    fn ascii_class_negate_case_fold() {
+        assert_eq!(p("(?i)[[:^upper:]]"),
+                   Expr::Class(class(UPPER).negate().case_fold()));
+        assert_eq!(p("(?i)[^[:^upper:]]"),
+                   Expr::Class(class(UPPER).case_fold()));
+    }
+
+    #[test]
+    fn ignore_space_literal() {
+        assert_eq!(p("(?x) a b c"), Expr::Concat(vec![
+            lit('a'), lit('b'), lit('c'),
+        ]));
+    }
+
+    #[test]
+    fn ignore_space_literal_off() {
+        assert_eq!(p("(?x) a b c(?-x) a"), Expr::Concat(vec![
+            lit('a'), lit('b'), lit('c'), lit(' '), lit('a'),
+        ]));
+    }
+
+    #[test]
+    fn ignore_space_class() {
+        assert_eq!(p("(?x)[a
+        - z
+]"), Expr::Class(class(&[('a', 'z')])));
+        assert_eq!(p("(?x)[  ^   a
+        - z
+]"), Expr::Class(class(&[('a', 'z')]).negate()));
+    }
+
+    #[test]
+    fn ignore_space_escape() {
+        assert_eq!(p(r"(?x)\ d"), Expr::Class(class(PERLD)));
+        assert_eq!(p(r"(?x)\
+                     D"), Expr::Class(class(PERLD).negate()));
+    }
+
+    #[test]
+    fn ignore_space_comments() {
+        assert_eq!(p(r"(?x)(?P<foo>
+    a # comment 1
+)(?P<bar>
+    z # comment 2
+)"), Expr::Concat(vec![
+        Expr::Group {
+            e: Box::new(lit('a')),
+            i: Some(1),
+            name: Some("foo".into()),
+        },
+        Expr::Group {
+            e: Box::new(lit('z')),
+            i: Some(2),
+            name: Some("bar".into()),
+        },
+    ]));
+    }
+
+    #[test]
+    fn ignore_space_comments_re_enable() {
+        assert_eq!(p(r"(?x)a # hi
+(?-x:#) # sweet"), Expr::Concat(vec![
+            lit('a'),
+            Expr::Group {
+                e: Box::new(lit('#')),
+                i: None,
+                name: None,
+            },
+        ]));
+    }
+
+    #[test]
+    fn ignore_space_escape_punctuation() {
+        assert_eq!(p(r"(?x)\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#"), c(&[
+            lit('\\'), lit('.'), lit('+'), lit('*'), lit('?'),
+            lit('('), lit(')'), lit('|'), lit('['), lit(']'),
+            lit('{'), lit('}'), lit('^'), lit('$'), lit('#'),
+        ]));
+    }
+
+    #[test]
+    fn ignore_space_escape_hash() {
+        assert_eq!(p(r"(?x)a\# # hi there"), Expr::Concat(vec![
+            lit('a'),
+            lit('#'),
+        ]));
+    }
+
+    // Test every single possible error case.
+
+    macro_rules! test_err {
+        ($re:expr, $pos:expr, $kind:expr) => {{
+            let err = Parser::parse($re).unwrap_err();
+            assert_eq!($pos, err.pos);
+            assert_eq!($kind, err.kind);
+            assert!($re.contains(&err.surround));
+        }}
+    }
+
+    #[test]
+    fn error_repeat_no_expr_simple() {
+        test_err!("(*", 1, ErrorKind::RepeaterExpectsExpr);
+    }
+
+    #[test]
+    fn error_repeat_no_expr_counted() {
+        test_err!("({5}", 1, ErrorKind::RepeaterExpectsExpr);
+    }
+
+    #[test]
+    fn error_repeat_beginning_counted() {
+        test_err!("{5}", 0, ErrorKind::RepeaterExpectsExpr);
+    }
+
+    #[test]
+    fn error_repeat_illegal_exprs_simple() {
+        test_err!("a**", 2, ErrorKind::RepeaterUnexpectedExpr(Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::ZeroOrMore,
+            greedy: true,
+        }));
+        test_err!("a|*", 2,
+            ErrorKind::RepeaterUnexpectedExpr(Expr::Alternate(vec![lit('a')]))
+        );
+    }
+
+    #[test]
+    fn error_repeat_illegal_exprs_counted() {
+        test_err!("a*{5}", 2, ErrorKind::RepeaterUnexpectedExpr(Expr::Repeat {
+            e: b(lit('a')),
+            r: Repeater::ZeroOrMore,
+            greedy: true,
+        }));
+        test_err!("a|{5}", 2,
+            ErrorKind::RepeaterUnexpectedExpr(Expr::Alternate(vec![lit('a')]))
+        );
+    }
+
+    #[test]
+    fn error_repeat_empty_number() {
+        test_err!("a{}", 2, ErrorKind::MissingBase10);
+    }
+
+    #[test]
+    fn error_repeat_eof() {
+        test_err!("a{5", 3, ErrorKind::UnclosedRepeat);
+    }
+
+    #[test]
+    fn error_repeat_empty_number_eof() {
+        test_err!("a{xyz", 5, ErrorKind::InvalidBase10("xyz".into()));
+        test_err!("a{12,xyz", 8, ErrorKind::InvalidBase10("xyz".into()));
+    }
+
+    #[test]
+    fn error_repeat_invalid_number() {
+        test_err!("a{9999999999}", 12,
+                  ErrorKind::InvalidBase10("9999999999".into()));
+        test_err!("a{1,9999999999}", 14,
+                  ErrorKind::InvalidBase10("9999999999".into()));
+    }
+
+    #[test]
+    fn error_repeat_invalid_number_extra() {
+        test_err!("a{12x}", 5, ErrorKind::InvalidBase10("12x".into()));
+        test_err!("a{1,12x}", 7, ErrorKind::InvalidBase10("12x".into()));
+    }
+
+    #[test]
+    fn error_repeat_invalid_range() {
+        test_err!("a{2,1}", 5,
+                  ErrorKind::InvalidRepeatRange { min: 2, max: 1 });
+    }
+
+    #[test]
+    fn error_alternate_empty() {
+        test_err!("|a", 0, ErrorKind::EmptyAlternate);
+    }
+
+    #[test]
+    fn error_alternate_empty_with_group() {
+        test_err!("(|a)", 1, ErrorKind::EmptyAlternate);
+    }
+
+    #[test]
+    fn error_alternate_empty_with_alternate() {
+        test_err!("a||", 2, ErrorKind::EmptyAlternate);
+    }
+
+    #[test]
+    fn error_close_paren_unopened_empty() {
+        test_err!(")", 0, ErrorKind::UnopenedParen);
+    }
+
+    #[test]
+    fn error_close_paren_unopened() {
+        test_err!("ab)", 2, ErrorKind::UnopenedParen);
+    }
+
+    #[test]
+    fn error_close_paren_unopened_with_alt() {
+        test_err!("a|b)", 3, ErrorKind::UnopenedParen);
+    }
+
+    #[test]
+    fn error_close_paren_empty_alt() {
+        test_err!("(a|)", 3, ErrorKind::EmptyAlternate);
+    }
+
+    #[test]
+    fn error_close_paren_empty_group() {
+        test_err!("()", 1, ErrorKind::EmptyGroup);
+    }
+
+    #[test]
+    fn error_close_paren_empty_group_with_name() {
+        test_err!("(?P<foo>)", 8, ErrorKind::EmptyGroup);
+    }
+
+    #[test]
+    fn error_finish_concat_unclosed() {
+        test_err!("ab(xy", 2, ErrorKind::UnclosedParen);
+    }
+
+    #[test]
+    fn error_finish_concat_empty_alt() {
+        test_err!("a|", 2, ErrorKind::EmptyAlternate);
+    }
+
+    #[test]
+    fn error_group_name_invalid() {
+        test_err!("(?P<a#>x)", 6, ErrorKind::InvalidCaptureName("a#".into()));
+    }
+
+    #[test]
+    fn error_group_name_invalid_leading() {
+        test_err!("(?P<1a>a)", 6, ErrorKind::InvalidCaptureName("1a".into()));
+    }
+
+    #[test]
+    fn error_group_name_unexpected_eof() {
+        test_err!("(?P<a", 5, ErrorKind::UnclosedCaptureName("a".into()));
+    }
+
+    #[test]
+    fn error_group_name_empty() {
+        test_err!("(?P<>a)", 4, ErrorKind::EmptyCaptureName);
+    }
+
+    #[test]
+    fn error_group_opts_unrecognized_flag() {
+        test_err!("(?z:a)", 2, ErrorKind::UnrecognizedFlag('z'));
+    }
+
+    #[test]
+    fn error_group_opts_unexpected_eof() {
+        test_err!("(?i", 3, ErrorKind::UnexpectedFlagEof);
+    }
+
+    #[test]
+    fn error_group_opts_double_negation() {
+        test_err!("(?-i-s:a)", 4, ErrorKind::DoubleFlagNegation);
+    }
+
+    #[test]
+    fn error_group_opts_empty_negation() {
+        test_err!("(?i-:a)", 4, ErrorKind::EmptyFlagNegation);
+    }
+
+    #[test]
+    fn error_group_opts_empty() {
+        test_err!("(?)", 2, ErrorKind::EmptyFlagNegation);
+    }
+
+    #[test]
+    fn error_escape_unexpected_eof() {
+        test_err!(r"\", 1, ErrorKind::UnexpectedEscapeEof);
+    }
+
+    #[test]
+    fn error_escape_unrecognized() {
+        test_err!(r"\m", 1, ErrorKind::UnrecognizedEscape('m'));
+    }
+
+    #[test]
+    fn error_escape_hex2_eof0() {
+        test_err!(r"\x", 2, ErrorKind::UnexpectedTwoDigitHexEof);
+    }
+
+    #[test]
+    fn error_escape_hex2_eof1() {
+        test_err!(r"\xA", 3, ErrorKind::UnexpectedTwoDigitHexEof);
+    }
+
+    #[test]
+    fn error_escape_hex2_invalid() {
+        test_err!(r"\xAG", 4, ErrorKind::InvalidBase16("AG".into()));
+    }
+
+    #[test]
+    fn error_escape_hex_eof0() {
+        test_err!(r"\x{", 3, ErrorKind::InvalidBase16("".into()));
+    }
+
+    #[test]
+    fn error_escape_hex_eof1() {
+        test_err!(r"\x{A", 4, ErrorKind::UnclosedHex);
+    }
+
+    #[test]
+    fn error_escape_hex_invalid() {
+        test_err!(r"\x{AG}", 5, ErrorKind::InvalidBase16("AG".into()));
+    }
+
+    #[test]
+    fn error_escape_hex_invalid_scalar_value_surrogate() {
+        test_err!(r"\x{D800}", 7, ErrorKind::InvalidScalarValue(0xD800));
+    }
+
+    #[test]
+    fn error_escape_hex_invalid_scalar_value_high() {
+        test_err!(r"\x{110000}", 9, ErrorKind::InvalidScalarValue(0x110000));
+    }
+
+    #[test]
+    fn error_escape_hex_invalid_u32() {
+        test_err!(r"\x{9999999999}", 13,
+                  ErrorKind::InvalidBase16("9999999999".into()));
+    }
+
+    #[test]
+    fn error_unicode_unclosed() {
+        test_err!(r"\p{", 3, ErrorKind::UnclosedUnicodeName);
+        test_err!(r"\p{Greek", 8, ErrorKind::UnclosedUnicodeName);
+    }
+
+    #[test]
+    fn error_unicode_no_letter() {
+        test_err!(r"\p", 2, ErrorKind::UnexpectedEscapeEof);
+    }
+
+    #[test]
+    fn error_unicode_unknown_letter() {
+        test_err!(r"\pA", 3, ErrorKind::UnrecognizedUnicodeClass("A".into()));
+    }
+
+    #[test]
+    fn error_unicode_unknown_name() {
+        test_err!(r"\p{Yii}", 7,
+                  ErrorKind::UnrecognizedUnicodeClass("Yii".into()));
+    }
+
+    #[test]
+    fn error_class_eof_empty() {
+        test_err!("[", 1, ErrorKind::UnexpectedClassEof);
+        test_err!("[^", 2, ErrorKind::UnexpectedClassEof);
+    }
+
+    #[test]
+    fn error_class_eof_non_empty() {
+        test_err!("[a", 2, ErrorKind::UnexpectedClassEof);
+        test_err!("[^a", 3, ErrorKind::UnexpectedClassEof);
+    }
+
+    #[test]
+    fn error_class_eof_range() {
+        test_err!("[a-", 3, ErrorKind::UnexpectedClassEof);
+        test_err!("[^a-", 4, ErrorKind::UnexpectedClassEof);
+        test_err!("[---", 4, ErrorKind::UnexpectedClassEof);
+    }
+
+    #[test]
+    fn error_class_invalid_escape() {
+        test_err!(r"[\pA]", 4,
+                  ErrorKind::UnrecognizedUnicodeClass("A".into()));
+    }
+
+    #[test]
+    fn error_class_valid_escape_not_allowed() {
+        test_err!(r"[\A]", 3, ErrorKind::InvalidClassEscape(Expr::StartText));
+    }
+
+    #[test]
+    fn error_class_range_valid_escape_not_allowed() {
+        test_err!(r"[a-\d]", 5,
+                  ErrorKind::InvalidClassEscape(Expr::Class(class(PERLD))));
+        test_err!(r"[a-\A]", 5,
+                  ErrorKind::InvalidClassEscape(Expr::StartText));
+        test_err!(r"[\A-a]", 3,
+                  ErrorKind::InvalidClassEscape(Expr::StartText));
+    }
+
+    #[test]
+    fn error_class_invalid_range() {
+        test_err!("[z-a]", 4, ErrorKind::InvalidClassRange {
+            start: 'z',
+            end: 'a',
+        });
+    }
+
+    #[test]
+    fn error_class_empty_range() {
+        test_err!("[]", 2, ErrorKind::UnexpectedClassEof);
+        test_err!("[^]", 3, ErrorKind::UnexpectedClassEof);
+    }
+
+    #[test]
+    fn error_duplicate_capture_name() {
+        test_err!("(?P<a>.)(?P<a>.)", 14,
+                  ErrorKind::DuplicateCaptureName("a".into()));
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3