<commit_before>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;
use imp::TlsConnectorBuilderExt;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

mod tests {
    use super::*;

    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[test]
    #[cfg(target_os = "windows")]
    fn schannel_verify_callback() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        builder.verify_callback(|validation_result| {
            assert!(validation_result.result().is_err());
            Ok(())
        });
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<commit_msg>Add comment exaplining reason for nested mod<commit_after>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;
use imp::TlsConnectorBuilderExt;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

// This nested mod is needed for ios testing with rust-test-ios
mod tests {
    use super::*;

    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[test]
    #[cfg(target_os = "windows")]
    fn schannel_verify_callback() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        builder.verify_callback(|validation_result| {
            assert!(validation_result.result().is_err());
            Ok(())
        });
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::kinds::marker;
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Chars<'a> {
    data: *const gchar,
    lifetime: marker::ContravariantLifetime<'a>
}

impl<'a> UTF8Chars<'a> {
    pub unsafe fn wrap(ptr: *const gchar) -> UTF8Chars<'a> {
        UTF8Chars { data: ptr, lifetime: marker::ContravariantLifetime }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const u8)
        }
    }
}

#[inline]
fn utf8_cont_bits(p: *const gchar) -> u32 {
    let byte = unsafe { *(p as *const u8) };
    debug_assert!((byte & 0xC0) == 0x80);
    (byte & 0x3F) as u32
}

impl<'a> Iterator<char> for UTF8Chars<'a> {
    fn next(&mut self) -> Option<char> {
        let p = self.data;
        let first_byte = unsafe { *(p as *const u8) };
        if first_byte == 0 {
            return None;
        }
        unsafe {
            let mut wc: u32;
            if first_byte < 0xC0 {
                debug_assert!(first_byte < 0x80);
                wc = first_byte as u32;
                self.data = p.offset(1);
            } else {
                let c1 = utf8_cont_bits(p.offset(1));
                if first_byte < 0xE0 {
                    wc = ((first_byte & 0x1F) as u32 << 6) | c1;
                    debug_assert!(wc >= 0x80);
                    self.data = p.offset(2);
                } else {
                    let c2 = utf8_cont_bits(p.offset(2));
                    if first_byte < 0xF0 {
                        wc = ((first_byte & 0x0F) as u32 << 12)
                             | (c1 << 6) | c2;
                        debug_assert!(wc >= 0x0800);
                        debug_assert!((wc & 0xF800) != 0xD800);
                        self.data = p.offset(3);
                    } else {
                        debug_assert!(first_byte <= 0xF4);
                        let c3 = utf8_cont_bits(p.offset(3));
                        wc = ((first_byte & 0x07) as u32 << 18)
                             | (c1 << 12) | (c2 << 6) | c3;
                        debug_assert!(wc >= 0x010000 && wc <= 0x10FFFF);
                        self.data = p.offset(4);
                    }
                }
            }
            Some(transmute(wc))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = libc::malloc(len as libc::size_t + 1) as *mut c_char;
    if copy.is_null() {
        ::alloc::oom();
    }
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl<'a> ToCStr for UTF8Chars<'a> {

    #[inline]
    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.data, libc::strlen(self.data) as uint)
    }

    fn with_c_str<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }
}

pub struct UTF8Buf {
    data: *const gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data as *const gchar }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> {
        unsafe { UTF8Chars::wrap(self.data) }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    #[inline]
    pub fn to_string(&self) -> String { self.chars().to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data))
        }
    }
}

impl ToCStr for UTF8Buf {

    #[inline]
    fn to_c_str(&self) -> CString {
        self.chars().to_c_str()
    }

    #[inline]
    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.chars().to_c_str_unchecked()
    }

    fn with_c_str<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

const NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> { self.buf.chars() }

    pub fn len(&self) -> uint { return self.len }

    pub fn is_empty(&self) -> bool { return self.len == 0 }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data, self.len)
    }

    fn with_c_str<T>(&self, f: |*const c_char| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const c_char| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 for Sized? {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl<'a> WithUTF8 for UTF8Chars<'a> {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data)
    }
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl WithUTF8 for str {
    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl<'a, Sized? T: WithUTF8> WithUTF8 for &'a T {
    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        (**self).with_utf8_c_str(f)
    }
}

impl WithUTF8 for String {
    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<commit_msg>Added .as_ptr() for UTF8Chars<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::kinds::marker;
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Chars<'a> {
    data: *const gchar,
    lifetime: marker::ContravariantLifetime<'a>
}

impl<'a> UTF8Chars<'a> {
    pub unsafe fn wrap(ptr: *const gchar) -> UTF8Chars<'a> {
        UTF8Chars { data: ptr, lifetime: marker::ContravariantLifetime }
    }

    pub fn as_ptr(&self) -> *const gchar { self.data }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const u8)
        }
    }
}

#[inline]
fn utf8_cont_bits(p: *const gchar) -> u32 {
    let byte = unsafe { *(p as *const u8) };
    debug_assert!((byte & 0xC0) == 0x80);
    (byte & 0x3F) as u32
}

impl<'a> Iterator<char> for UTF8Chars<'a> {
    fn next(&mut self) -> Option<char> {
        let p = self.data;
        let first_byte = unsafe { *(p as *const u8) };
        if first_byte == 0 {
            return None;
        }
        unsafe {
            let mut wc: u32;
            if first_byte < 0xC0 {
                debug_assert!(first_byte < 0x80);
                wc = first_byte as u32;
                self.data = p.offset(1);
            } else {
                let c1 = utf8_cont_bits(p.offset(1));
                if first_byte < 0xE0 {
                    wc = ((first_byte & 0x1F) as u32 << 6) | c1;
                    debug_assert!(wc >= 0x80);
                    self.data = p.offset(2);
                } else {
                    let c2 = utf8_cont_bits(p.offset(2));
                    if first_byte < 0xF0 {
                        wc = ((first_byte & 0x0F) as u32 << 12)
                             | (c1 << 6) | c2;
                        debug_assert!(wc >= 0x0800);
                        debug_assert!((wc & 0xF800) != 0xD800);
                        self.data = p.offset(3);
                    } else {
                        debug_assert!(first_byte <= 0xF4);
                        let c3 = utf8_cont_bits(p.offset(3));
                        wc = ((first_byte & 0x07) as u32 << 18)
                             | (c1 << 12) | (c2 << 6) | c3;
                        debug_assert!(wc >= 0x010000 && wc <= 0x10FFFF);
                        self.data = p.offset(4);
                    }
                }
            }
            Some(transmute(wc))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = libc::malloc(len as libc::size_t + 1) as *mut c_char;
    if copy.is_null() {
        ::alloc::oom();
    }
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl<'a> ToCStr for UTF8Chars<'a> {

    #[inline]
    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.data, libc::strlen(self.data) as uint)
    }

    fn with_c_str<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }
}

pub struct UTF8Buf {
    data: *const gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data as *const gchar }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> {
        unsafe { UTF8Chars::wrap(self.data) }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    #[inline]
    pub fn to_string(&self) -> String { self.chars().to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data))
        }
    }
}

impl ToCStr for UTF8Buf {

    #[inline]
    fn to_c_str(&self) -> CString {
        self.chars().to_c_str()
    }

    #[inline]
    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.chars().to_c_str_unchecked()
    }

    fn with_c_str<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const c_char| -> T) -> T {
        f(self.data)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

const NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> { self.buf.chars() }

    pub fn len(&self) -> uint { return self.len }

    pub fn is_empty(&self) -> bool { return self.len == 0 }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data, self.len)
    }

    fn with_c_str<T>(&self, f: |*const c_char| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const c_char| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 for Sized? {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl<'a> WithUTF8 for UTF8Chars<'a> {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data)
    }
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl WithUTF8 for str {
    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl<'a, Sized? T: WithUTF8> WithUTF8 for &'a T {
    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        (**self).with_utf8_c_str(f)
    }
}

impl WithUTF8 for String {
    #[inline]
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_uint};
use std::mem::zeroed;
use std::process;

use x11::xlib;

use xproto;

#[macro_export]
macro_rules! x_disable_error_unsafe {
    ( $display: expr, $s: block ) => {
        unsafe {
            debug!("grab server");
            xlib::XGrabServer($display);
            xlib::XSetErrorHandler(Some(util::xerror_dummy));
            $s
            xlib::XSync($display, 0);
            xlib::XSetErrorHandler(Some(util::xerror));
            xlib::XUngrabServer($display);
            debug!("ungrab server");
        }
    }
}

#[macro_export]
macro_rules! define_tags (
    ( $modkey: expr, $mod_mask: expr, [$($x: expr), *]) => {
        (&[
            $(($modkey, $x as c_uint, &|w| w.select_tag($x as c_uchar)), )*
            $(($modkey | $mod_mask, $x as c_uint, &|w| w.add_tag($x as c_uchar)),)*
        ], &[$($x as c_uchar, )*])
    };
);

#[allow(unused_variables)]
pub extern "C" fn xerror_dummy(display: *mut xlib::Display,
                               event: *mut xlib::XErrorEvent)
                               -> c_int {
    let e: xlib::XErrorEvent = unsafe { *event };
    debug!("[WARN] Got error {} from request {}",
         e.error_code,
         e.request_code);
    0
}

pub fn get_text_prop(display: *mut xlib::Display,
                     window: xlib::Window,
                     atom: xlib::Atom)
                     -> Option<String> {
    let mut list: *mut (*mut c_char) = unsafe { zeroed() };
    let mut name: xlib::XTextProperty = unsafe { zeroed() };
    let mut n: c_int = 0;
    let mut result = None;
    unsafe {
        xlib::XGetTextProperty(display, window, &mut name, atom);
        if name.nitems == 0 {
            return None;
        }
        if name.encoding == xlib::XA_STRING {
            let st = CString::from_raw(name.value as *mut c_char)
                .to_string_lossy()
                .to_string();
            result = Some(st);
        } else {
            if xlib::Xutf8TextPropertyToTextList(display, &mut name, &mut list, &mut n) >=
               xlib::Success as c_int && n > 0 && !(*list).is_null() {
                let st = CString::from_raw(*list).to_string_lossy().to_string();
                result = Some(st);
                // xlib::XFreeStringList(list);
            }
        }
        // TODO: Possible memory leak but adding the following statement will result in double
        // free.
        // xlib::XFree(name.value as *mut c_void);
    }
    result
}

pub fn get_root_pointer(display: *mut xlib::Display, root: xlib::Window) -> Option<(c_int, c_int)> {
    let mut x = 0;
    let mut y = 0;
    let mut di = 0;
    let mut dui = 0;
    let mut ddui = 0;
    let mut dummy: xlib::Window = 0;

    let result = unsafe {
        xlib::XQueryPointer(display,
                            root,
                            &mut dummy,
                            &mut dummy,
                            &mut x,
                            &mut y,
                            &mut dui,
                            &mut di,
                            &mut ddui)
    };

    if result == 0 { None } else { Some((x, y)) }
}

pub fn clean_mask(keycode: c_uint) -> c_uint {
    keycode & !xlib::LockMask &
    (xlib::Mod1Mask | xlib::Mod2Mask | xlib::Mod3Mask | xlib::Mod4Mask | xlib::Mod5Mask |
     xlib::ShiftMask | xlib::ControlMask)
}

pub fn spawn(command: &str, args: &[&str]) {
    match process::Command::new(command).args(args).spawn() {
        Ok(_) => (),
        Err(s) => debug!("fail to spawn process {}, error: {}", command, s),
    }
}

pub fn truncate(s: &str, max_chars: usize) -> &str {
    match s.char_indices().nth(max_chars) {
        None => s,
        Some((idx, _)) => &s[..idx],
    }
}

#[allow(unused_variables)]
pub extern "C" fn xerror(dpy: *mut xlib::Display, err: *mut xlib::XErrorEvent) -> c_int {
    let ee = unsafe { *err };
    if ee.error_code == xlib::BadWindow ||
       (ee.request_code == xproto::X_SetInputFocus && ee.error_code == xlib::BadMatch) ||
       (ee.request_code == xproto::X_PolyText8 && ee.error_code == xlib::BadDrawable) ||
       (ee.request_code == xproto::X_PolyFillRectangle && ee.error_code == xlib::BadDrawable) ||
       (ee.request_code == xproto::X_PolySegment && ee.error_code == xlib::BadDrawable) ||
       (ee.request_code == xproto::X_ConfigureWindow && ee.error_code == xlib::BadMatch) ||
       (ee.request_code == xproto::X_GrabButton && ee.error_code == xlib::BadAccess) ||
       (ee.request_code == xproto::X_GrabKey && ee.error_code == xlib::BadAccess) ||
       (ee.request_code == xproto::X_CopyArea && ee.error_code == xlib::BadDrawable) {
        debug!("rswm: error: request code={}, error code={}", ee.request_code, ee.error_code);
        return 0;
    }
    error!("rswm: fatal error: request code={}, error code={}\n",
			ee.request_code, ee.error_code);
    process::exit(1);
}
<commit_msg>change logger level for spawn.<commit_after>use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_uint};
use std::mem::zeroed;
use std::process;

use x11::xlib;

use xproto;

#[macro_export]
macro_rules! x_disable_error_unsafe {
    ( $display: expr, $s: block ) => {
        unsafe {
            debug!("grab server");
            xlib::XGrabServer($display);
            xlib::XSetErrorHandler(Some(util::xerror_dummy));
            $s
            xlib::XSync($display, 0);
            xlib::XSetErrorHandler(Some(util::xerror));
            xlib::XUngrabServer($display);
            debug!("ungrab server");
        }
    }
}

#[macro_export]
macro_rules! define_tags (
    ( $modkey: expr, $mod_mask: expr, [$($x: expr), *]) => {
        (&[
            $(($modkey, $x as c_uint, &|w| w.select_tag($x as c_uchar)), )*
            $(($modkey | $mod_mask, $x as c_uint, &|w| w.add_tag($x as c_uchar)),)*
        ], &[$($x as c_uchar, )*])
    };
);

#[allow(unused_variables)]
pub extern "C" fn xerror_dummy(display: *mut xlib::Display,
                               event: *mut xlib::XErrorEvent)
                               -> c_int {
    let e: xlib::XErrorEvent = unsafe { *event };
    debug!("got error {} from request {}",
         e.error_code,
         e.request_code);
    0
}

pub fn get_text_prop(display: *mut xlib::Display,
                     window: xlib::Window,
                     atom: xlib::Atom)
                     -> Option<String> {
    let mut list: *mut (*mut c_char) = unsafe { zeroed() };
    let mut name: xlib::XTextProperty = unsafe { zeroed() };
    let mut n: c_int = 0;
    let mut result = None;
    unsafe {
        xlib::XGetTextProperty(display, window, &mut name, atom);
        if name.nitems == 0 {
            return None;
        }
        if name.encoding == xlib::XA_STRING {
            let st = CString::from_raw(name.value as *mut c_char)
                .to_string_lossy()
                .to_string();
            result = Some(st);
        } else {
            if xlib::Xutf8TextPropertyToTextList(display, &mut name, &mut list, &mut n) >=
               xlib::Success as c_int && n > 0 && !(*list).is_null() {
                let st = CString::from_raw(*list).to_string_lossy().to_string();
                result = Some(st);
                // xlib::XFreeStringList(list);
            }
        }
        // TODO: Possible memory leak but adding the following statement will result in double
        // free.
        // xlib::XFree(name.value as *mut c_void);
    }
    result
}

pub fn get_root_pointer(display: *mut xlib::Display, root: xlib::Window) -> Option<(c_int, c_int)> {
    let mut x = 0;
    let mut y = 0;
    let mut di = 0;
    let mut dui = 0;
    let mut ddui = 0;
    let mut dummy: xlib::Window = 0;

    let result = unsafe {
        xlib::XQueryPointer(display,
                            root,
                            &mut dummy,
                            &mut dummy,
                            &mut x,
                            &mut y,
                            &mut dui,
                            &mut di,
                            &mut ddui)
    };

    if result == 0 { None } else { Some((x, y)) }
}

pub fn clean_mask(keycode: c_uint) -> c_uint {
    keycode & !xlib::LockMask &
    (xlib::Mod1Mask | xlib::Mod2Mask | xlib::Mod3Mask | xlib::Mod4Mask | xlib::Mod5Mask |
     xlib::ShiftMask | xlib::ControlMask)
}

pub fn spawn(command: &str, args: &[&str]) {
    match process::Command::new(command).args(args).spawn() {
        Ok(_) => (),
        Err(s) => error!("fail to spawn process {}, error: {}", command, s),
    }
}

pub fn truncate(s: &str, max_chars: usize) -> &str {
    match s.char_indices().nth(max_chars) {
        None => s,
        Some((idx, _)) => &s[..idx],
    }
}

#[allow(unused_variables)]
pub extern "C" fn xerror(dpy: *mut xlib::Display, err: *mut xlib::XErrorEvent) -> c_int {
    let ee = unsafe { *err };
    if ee.error_code == xlib::BadWindow ||
       (ee.request_code == xproto::X_SetInputFocus && ee.error_code == xlib::BadMatch) ||
       (ee.request_code == xproto::X_PolyText8 && ee.error_code == xlib::BadDrawable) ||
       (ee.request_code == xproto::X_PolyFillRectangle && ee.error_code == xlib::BadDrawable) ||
       (ee.request_code == xproto::X_PolySegment && ee.error_code == xlib::BadDrawable) ||
       (ee.request_code == xproto::X_ConfigureWindow && ee.error_code == xlib::BadMatch) ||
       (ee.request_code == xproto::X_GrabButton && ee.error_code == xlib::BadAccess) ||
       (ee.request_code == xproto::X_GrabKey && ee.error_code == xlib::BadAccess) ||
       (ee.request_code == xproto::X_CopyArea && ee.error_code == xlib::BadDrawable) {
        debug!("rswm: error: request code={}, error code={}", ee.request_code, ee.error_code);
        return 0;
    }
    error!("rswm: fatal error: request code={}, error code={}\n",
			ee.request_code, ee.error_code);
    process::exit(1);
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::Write;

use parity_wasm;
use cargo_shim::BuildConfig;

use wasm_gc;

use wasm_context::Context;
use wasm_inline_js;
use wasm_export_main;
use wasm_export_table;
use wasm_hook_grow;
use wasm_intrinsics;
use wasm_runtime::{self, RuntimeKind};
use wasm_js_export;

pub fn process_wasm_file< P: AsRef< Path > + ?Sized >( runtime: RuntimeKind, build: &BuildConfig, prepend_js: &str, artifact: &P ) -> Option< PathBuf > {
    if !build.triplet.as_ref().map( |triplet| triplet == "wasm32-unknown-unknown" ).unwrap_or( false ) {
        return None;
    }

    let path = artifact.as_ref();
    if !path.extension().map( |ext| ext == "wasm" ).unwrap_or( false ) {
        return None;
    }

    let js_path = path.with_extension( "js" );
    if js_path.exists() {
        let js_mtime = fs::metadata( &js_path ).unwrap().modified().unwrap();
        let wasm_mtime = fs::metadata( path ).unwrap().modified().unwrap();
        if js_mtime >= wasm_mtime {
            // We've already ran; nothing to do here.
            return Some( js_path );
        }
    }

    eprintln!( "    Garbage collecting {:?}...", path.file_name().unwrap() );
    wasm_gc::run( &path, &path );

    eprintln!( "    Processing {:?}...", path.file_name().unwrap() );
    let mut module = parity_wasm::deserialize_file( &path ).unwrap();
    let mut ctx = Context::from_module( module );
    let snippets = wasm_inline_js::process_and_extract( &mut ctx );
    let intrinsics = wasm_intrinsics::process( &mut ctx );
    let main_symbol = wasm_export_main::process( &mut ctx );
    let exports = wasm_js_export::process( &mut ctx );
    wasm_export_main::process( &mut ctx );
    wasm_export_table::process( &mut ctx );
    wasm_hook_grow::process( &mut ctx );
    module = ctx.into_module();

    // At least on Linux when a `.wasm` file is built it's
    // hard-linked from two places:
    //    1) target/wasm32-unknown-unknown/release/$name.wasm
    //    2) target/wasm32-unknown-unknown/release/deps/$name.wasm
    //
    // If you trigger a `cargo build` in a case where your project
    // doesn't need to be rebuilt it will just recreate
    // the `deps/$name.wasm` -> `$name.wasm` hard-link
    // and report that the file was rebuilt. (Even though it wasn't!)
    //
    // This wouldn't normally be a problem, however since we
    // modify the `.wasm` file we end up modifying *both* of
    // them which breaks any subsequent builds.
    //
    // So we forcefully remove the `$name.wasm` here before
    // overwriting it to get rid of the hard-link.
    let _ = fs::remove_file( path );

    parity_wasm::serialize_to_file( path, module ).unwrap();

    let all_snippets: Vec< _ > = snippets.into_iter().chain( intrinsics.into_iter() ).collect();
    let js = wasm_runtime::generate_js( runtime, main_symbol, path, prepend_js, &all_snippets, &exports );
    let mut fp = File::create( &js_path ).unwrap();
    fp.write_all( js.as_bytes() ).unwrap();

    eprintln!( "    Finished processing of {:?}!", path.file_name().unwrap() );
    Some( js_path )
}
<commit_msg>Decide whenever to regenerate the `.js` file based on `.wasm`'s hash<commit_after>use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::{self, Read, Write};

use sha1::Sha1;
use parity_wasm;
use cargo_shim::BuildConfig;
use serde_json;

use wasm_gc;

use wasm_context::Context;
use wasm_inline_js;
use wasm_export_main;
use wasm_export_table;
use wasm_hook_grow;
use wasm_intrinsics;
use wasm_runtime::{self, RuntimeKind};
use wasm_js_export;

#[derive(Serialize, Deserialize)]
struct Metadata {
    wasm_hash: String
}

fn get_sha1sum< P: AsRef< Path > >( path: P ) -> io::Result< String > {
    let path = path.as_ref();
    let mut fp = File::open( path )?;
    let mut hasher = Sha1::new();

    let mut buffer = Vec::new();
    buffer.resize( 1024 * 1024, 0 );
    loop {
        match fp.read( &mut buffer )? {
            0 => break,
            count => hasher.update( &buffer[ 0..count ] )
        }
    }

    Ok( format!( "{}", hasher.digest() ) )
}

pub fn process_wasm_file< P: AsRef< Path > + ?Sized >( runtime: RuntimeKind, build: &BuildConfig, prepend_js: &str, artifact: &P ) -> Option< PathBuf > {
    if !build.triplet.as_ref().map( |triplet| triplet == "wasm32-unknown-unknown" ).unwrap_or( false ) {
        return None;
    }

    let path = artifact.as_ref();
    if !path.extension().map( |ext| ext == "wasm" ).unwrap_or( false ) {
        return None;
    }

    let wasm_hash = get_sha1sum( path ).expect( "cannot calculate sha1sum of the `.wasm` file" );
    debug!( "Hash of {:?}: {}", path, wasm_hash );

    let js_path = path.with_extension( "js" );
    let metadata_path = path.with_extension( "cargoweb-metadata" );
    if js_path.exists() && metadata_path.exists() {
        // TODO: This is just a quick workaround. We should always regenerate the `.js` file.
        let fp = File::open( &metadata_path ).expect( "cannot open the metadata file" );
        let metadata: Metadata = serde_json::from_reader( fp ).expect( "cannot deserialize metadata; delete your `target` directory" );
        if metadata.wasm_hash == wasm_hash {
            debug!( "Skipping `.js` generation and `.wasm` processing!" );
            return Some( js_path );
        }
    }

    eprintln!( "    Garbage collecting {:?}...", path.file_name().unwrap() );
    wasm_gc::run( &path, &path );

    eprintln!( "    Processing {:?}...", path.file_name().unwrap() );
    let mut module = parity_wasm::deserialize_file( &path ).unwrap();
    let mut ctx = Context::from_module( module );
    let snippets = wasm_inline_js::process_and_extract( &mut ctx );
    let intrinsics = wasm_intrinsics::process( &mut ctx );
    let main_symbol = wasm_export_main::process( &mut ctx );
    let exports = wasm_js_export::process( &mut ctx );
    wasm_export_main::process( &mut ctx );
    wasm_export_table::process( &mut ctx );
    wasm_hook_grow::process( &mut ctx );
    module = ctx.into_module();

    // At least on Linux when a `.wasm` file is built it's
    // hard-linked from two places:
    //    1) target/wasm32-unknown-unknown/release/$name.wasm
    //    2) target/wasm32-unknown-unknown/release/deps/$name.wasm
    //
    // If you trigger a `cargo build` in a case where your project
    // doesn't need to be rebuilt it will just recreate
    // the `deps/$name.wasm` -> `$name.wasm` hard-link
    // and report that the file was rebuilt. (Even though it wasn't!)
    //
    // This wouldn't normally be a problem, however since we
    // modify the `.wasm` file we end up modifying *both* of
    // them which breaks any subsequent builds.
    //
    // So we forcefully remove the `$name.wasm` here before
    // overwriting it to get rid of the hard-link.
    let _ = fs::remove_file( path );

    parity_wasm::serialize_to_file( path, module ).unwrap();

    let all_snippets: Vec< _ > = snippets.into_iter().chain( intrinsics.into_iter() ).collect();
    let js = wasm_runtime::generate_js( runtime, main_symbol, path, prepend_js, &all_snippets, &exports );
    let mut fp = File::create( &js_path ).unwrap();
    fp.write_all( js.as_bytes() ).unwrap();

    let new_wasm_hash = get_sha1sum( path ).expect( "cannot calculate sha1sum of the `.wasm` file" );
    debug!( "New hash of {:?}: {}", path, new_wasm_hash );

    let fp = File::create( &metadata_path ).unwrap();
    serde_json::to_writer( fp, &Metadata { wasm_hash: new_wasm_hash } ).unwrap();

    eprintln!( "    Finished processing of {:?}!", path.file_name().unwrap() );
    Some( js_path )
}
<|endoftext|>


<commit_before>use native;
use std::comm::channel;

struct WorkUnit {
    arg: int,
    callback: Sender<int>,
}

enum MessageToWorker {
    Work(WorkUnit),
    Halt,
}

enum MessageToDispatcher {
    Dispatch(WorkUnit),
    HaltAll,
    RegisterWorker(Sender<Sender<Sender<MessageToWorker>>>),
}

struct WorkQueue {
    dispatcher: Sender<MessageToDispatcher>,
}

impl WorkQueue {
    pub fn create() -> WorkQueue {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher>();

        // dispatcher
        native::task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });
        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn register_worker(&self) -> Sender<Sender<MessageToWorker>> {
        let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker>>>();
        self.dispatcher.send(RegisterWorker(reg_s));
        return reg_r.recv();
    }

    pub fn spawn_worker(&self) {
        let want_work = self.register_worker();
        native::task::spawn(proc() {
            let want_work = want_work;
            loop {
                let (idle, get_work_unit) = channel::<MessageToWorker>();
                want_work.send(idle);
                let work_unit = match get_work_unit.recv() {
                    Work(wu) => wu,
                    Halt     => return
                };
                let rv = work_unit.arg * 2;
                work_unit.callback.send(rv);
            }
        });
    }

    pub fn execute(&self, arg: int) -> Receiver<int> {
        let (callback, wait_for_rv) = channel::<int>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, callback: callback}));
        return wait_for_rv;
    }
}

impl Drop for WorkQueue {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

#[test]
fn test_queue() {
    let queue = WorkQueue::create();
    for _ in range(0, 3) {
        queue.spawn_worker();
    }
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let rv = queue.execute(c);
        promise_list.push(rv);
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
<commit_msg>move worker outside of WorkQueue<commit_after>use native;
use std::comm::channel;

struct WorkUnit {
    arg: int,
    callback: Sender<int>,
}

enum MessageToWorker {
    Work(WorkUnit),
    Halt,
}

enum MessageToDispatcher {
    Dispatch(WorkUnit),
    HaltAll,
    RegisterWorker(Sender<Sender<Sender<MessageToWorker>>>),
}

struct WorkQueue {
    dispatcher: Sender<MessageToDispatcher>,
}

impl WorkQueue {
    pub fn create() -> WorkQueue {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher>();

        // dispatcher
        native::task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });
        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn register_worker(&self) -> Sender<Sender<MessageToWorker>> {
        let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker>>>();
        self.dispatcher.send(RegisterWorker(reg_s));
        return reg_r.recv();
    }

    pub fn execute(&self, arg: int) -> Receiver<int> {
        let (callback, wait_for_rv) = channel::<int>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, callback: callback}));
        return wait_for_rv;
    }
}

impl Drop for WorkQueue {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

#[test]
fn test_queue() {
    let queue = WorkQueue::create();
    for _ in range(0, 3) {
        let want_work = queue.register_worker();
        native::task::spawn(proc() {
            let want_work = want_work;
            loop {
                let (idle, get_work_unit) = channel::<MessageToWorker>();
                want_work.send(idle);
                let work_unit = match get_work_unit.recv() {
                    Work(wu) => wu,
                    Halt     => return
                };
                let rv = work_unit.arg * 2;
                work_unit.callback.send(rv);
            }
        });
    }
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let rv = queue.execute(c);
        promise_list.push(rv);
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
<|endoftext|>


<commit_before>//! A ZoneAllocator to allocate arbitrary object sizes (up to `ZoneAllocator::MAX_ALLOC_SIZE`)
//!
//! The ZoneAllocator achieves this by having many `SCAllocator`

use crate::*;

/// Creates an instance of a zone, we do this in a macro because we
/// re-use the code in const and non-const functions
///
/// We can get rid of this once the const fn feature is fully stabilized.
macro_rules! new_zone {
    () => {
        ZoneAllocator {
            // TODO(perf): We should probably pick better classes
            // rather than powers-of-two (see SuperMalloc etc.)
            small_slabs: [
                SCAllocator::new(1 << 3),  // 8
                SCAllocator::new(1 << 4),  // 16
                SCAllocator::new(1 << 5),  // 32
                SCAllocator::new(1 << 6),  // 64
                SCAllocator::new(1 << 7),  // 128
                SCAllocator::new(1 << 8),  // 256
                SCAllocator::new(1 << 9),  // 512
                SCAllocator::new(1 << 10), // 1024 (TODO: maybe get rid of this class?)
                SCAllocator::new(1 << 11), // 2048 (TODO: maybe get rid of this class?)
                SCAllocator::new(4016), // 4016 (can't do 4096 because of metadata in ObjectPage)
            ],
            big_slabs: [
                SCAllocator::new(1 << 13), // 8192
                SCAllocator::new(1 << 14), // 16384
                SCAllocator::new(1 << 15), // 32767
                SCAllocator::new(1 << 16), // 65536
                SCAllocator::new(1 << 17), // 131072
            ],
        }
    };
}

/// A zone allocator for arbitrary sized allocations.
///
/// Has a bunch of `SCAllocator` and through that can serve allocation
/// requests for many different object sizes up to (MAX_SIZE_CLASSES) by selecting
/// the right `SCAllocator` for allocation and deallocation.
///
/// The allocator provides to refill functions `refill` and `refill_large`
/// to provide the underlying `SCAllocator` with more memory in case it runs out.
pub struct ZoneAllocator<'a> {
    small_slabs: [SCAllocator<'a, ObjectPage<'a>>; ZoneAllocator::MAX_BASE_SIZE_CLASSES],
    big_slabs: [SCAllocator<'a, LargeObjectPage<'a>>; ZoneAllocator::MAX_LARGE_SIZE_CLASSES],
}

impl<'a> Default for ZoneAllocator<'a> {
    fn default() -> ZoneAllocator<'a> {
        new_zone!()
    }
}

enum Slab {
    Base(usize),
    Large(usize),
    Unsupported,
}

impl<'a> ZoneAllocator<'a> {
    /// Maximum size that allocated within LargeObjectPages (2 MiB).
    /// This is also the maximum object size that this allocator can handle.
    pub const MAX_ALLOC_SIZE: usize = 1 << 17;

    /// Maximum size which is allocated with ObjectPages (4 KiB pages).
    ///
    /// e.g. this is 4 KiB - 80 bytes of meta-data.
    pub const MAX_BASE_ALLOC_SIZE: usize = 4016;

    /// How many allocators of type SCAllocator<ObjectPage> we have.
    const MAX_BASE_SIZE_CLASSES: usize = 10;

    /// How many allocators of type SCAllocator<LargeObjectPage> we have.
    const MAX_LARGE_SIZE_CLASSES: usize = 5;

    #[cfg(feature = "unstable")]
    pub const fn new() -> ZoneAllocator<'a> {
        new_zone!()
    }

    #[cfg(not(feature = "unstable"))]
    pub fn new() -> ZoneAllocator<'a> {
        new_zone!()
    }

    /// Return maximum size an object of size `current_size` can use.
    ///
    /// Used to optimize `realloc`.
    pub fn get_max_size(current_size: usize) -> Option<usize> {
        match current_size {
            0..=8 => Some(8),
            9..=16 => Some(16),
            17..=32 => Some(32),
            33..=64 => Some(64),
            65..=128 => Some(128),
            129..=256 => Some(256),
            257..=512 => Some(512),
            513..=1024 => Some(1024),
            1025..=2048 => Some(2048),
            2049..=4016 => Some(4016),
            4017..=8192 => Some(8192),
            8193..=16384 => Some(16384),
            16385..=32767 => Some(32767),
            32768..=65536 => Some(65536),
            65537..=131_072 => Some(131_072),
            _ => None,
        }
    }

    /// Figure out index into zone array to get the correct slab allocator for that size.
    fn get_slab(requested_size: usize) -> Slab {
        match requested_size {
            0..=8 => Slab::Base(0),
            9..=16 => Slab::Base(1),
            17..=32 => Slab::Base(2),
            33..=64 => Slab::Base(3),
            65..=128 => Slab::Base(4),
            129..=256 => Slab::Base(5),
            257..=512 => Slab::Base(6),
            513..=1024 => Slab::Base(7),
            1025..=2048 => Slab::Base(8),
            2049..=4016 => Slab::Base(9),
            4017..=8192 => Slab::Large(0),
            8193..=16384 => Slab::Large(1),
            16385..=32767 => Slab::Large(2),
            32768..=65536 => Slab::Large(3),
            65537..=131_072 => Slab::Large(4),
            _ => Slab::Unsupported,
        }
    }
}

unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> {
    /// Allocate a pointer to a block of memory described by `layout`.
    fn allocate(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(idx) => self.small_slabs[idx].allocate(layout),
            Slab::Large(idx) => self.big_slabs[idx].allocate(layout),
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }

    /// Deallocates a pointer to a block of memory, which was
    /// previously allocated by `allocate`.
    ///
    /// # Arguments
    ///  * `ptr` - Address of the memory location to free.
    ///  * `layout` - Memory layout of the block pointed to by `ptr`.
    fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) -> Result<(), AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout),
            Slab::Large(idx) => self.big_slabs[idx].deallocate(ptr, layout),
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }

    /// Refills the SCAllocator for a given Layout with an ObjectPage.
    ///
    /// # Safety
    /// ObjectPage needs to be emtpy etc.
    unsafe fn refill(
        &mut self,
        layout: Layout,
        new_page: &'a mut ObjectPage<'a>,
    ) -> Result<(), AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(idx) => {
                self.small_slabs[idx].refill(new_page);
                Ok(())
            }
            Slab::Large(_idx) => Err(AllocationError::InvalidLayout),
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }

    /// Refills the SCAllocator for a given Layout with an ObjectPage.
    ///
    /// # Safety
    /// ObjectPage needs to be emtpy etc.
    unsafe fn refill_large(
        &mut self,
        layout: Layout,
        new_page: &'a mut LargeObjectPage<'a>,
    ) -> Result<(), AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(_idx) => Err(AllocationError::InvalidLayout),
            Slab::Large(idx) => {
                self.big_slabs[idx].refill(new_page);
                Ok(())
            }
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }
}
<commit_msg>Move more size-classes to use large-pages.<commit_after>//! A ZoneAllocator to allocate arbitrary object sizes (up to `ZoneAllocator::MAX_ALLOC_SIZE`)
//!
//! The ZoneAllocator achieves this by having many `SCAllocator`

use crate::*;

/// Creates an instance of a zone, we do this in a macro because we
/// re-use the code in const and non-const functions
///
/// We can get rid of this once the const fn feature is fully stabilized.
macro_rules! new_zone {
    () => {
        ZoneAllocator {
            // TODO(perf): We should probably pick better classes
            // rather than powers-of-two (see SuperMalloc etc.)
            small_slabs: [
                SCAllocator::new(1 << 3), // 8
                SCAllocator::new(1 << 4), // 16
                SCAllocator::new(1 << 5), // 32
                SCAllocator::new(1 << 6), // 64
                SCAllocator::new(1 << 7), // 128
                SCAllocator::new(1 << 8), // 256
            ],
            big_slabs: [
                SCAllocator::new(1 << 9),  // 512
                SCAllocator::new(1 << 10), // 1024
                SCAllocator::new(1 << 11), // 2048
                SCAllocator::new(1 << 12), // 4096
                SCAllocator::new(1 << 13), // 8192
                SCAllocator::new(1 << 14), // 16384
                SCAllocator::new(1 << 15), // 32767
                SCAllocator::new(1 << 16), // 65536
                SCAllocator::new(1 << 17), // 131072
            ],
        }
    };
}

/// A zone allocator for arbitrary sized allocations.
///
/// Has a bunch of `SCAllocator` and through that can serve allocation
/// requests for many different object sizes up to (MAX_SIZE_CLASSES) by selecting
/// the right `SCAllocator` for allocation and deallocation.
///
/// The allocator provides to refill functions `refill` and `refill_large`
/// to provide the underlying `SCAllocator` with more memory in case it runs out.
pub struct ZoneAllocator<'a> {
    small_slabs: [SCAllocator<'a, ObjectPage<'a>>; ZoneAllocator::MAX_BASE_SIZE_CLASSES],
    big_slabs: [SCAllocator<'a, LargeObjectPage<'a>>; ZoneAllocator::MAX_LARGE_SIZE_CLASSES],
}

impl<'a> Default for ZoneAllocator<'a> {
    fn default() -> ZoneAllocator<'a> {
        new_zone!()
    }
}

enum Slab {
    Base(usize),
    Large(usize),
    Unsupported,
}

impl<'a> ZoneAllocator<'a> {
    /// Maximum size that allocated within LargeObjectPages (2 MiB).
    /// This is also the maximum object size that this allocator can handle.
    pub const MAX_ALLOC_SIZE: usize = 1 << 17;

    /// Maximum size which is allocated with ObjectPages (4 KiB pages).
    ///
    /// e.g. this is 4 KiB - 80 bytes of meta-data.
    pub const MAX_BASE_ALLOC_SIZE: usize = 256;

    /// How many allocators of type SCAllocator<ObjectPage> we have.
    const MAX_BASE_SIZE_CLASSES: usize = 6;

    /// How many allocators of type SCAllocator<LargeObjectPage> we have.
    const MAX_LARGE_SIZE_CLASSES: usize = 9;

    #[cfg(feature = "unstable")]
    pub const fn new() -> ZoneAllocator<'a> {
        new_zone!()
    }

    #[cfg(not(feature = "unstable"))]
    pub fn new() -> ZoneAllocator<'a> {
        new_zone!()
    }

    /// Return maximum size an object of size `current_size` can use.
    ///
    /// Used to optimize `realloc`.
    pub fn get_max_size(current_size: usize) -> Option<usize> {
        match current_size {
            0..=8 => Some(8),
            9..=16 => Some(16),
            17..=32 => Some(32),
            33..=64 => Some(64),
            65..=128 => Some(128),
            129..=256 => Some(256),
            257..=512 => Some(512),
            513..=1024 => Some(1024),
            1025..=2048 => Some(2048),
            2049..=4096 => Some(4016),
            4097..=8192 => Some(8192),
            8193..=16384 => Some(16384),
            16385..=32767 => Some(32767),
            32768..=65536 => Some(65536),
            65537..=131_072 => Some(131_072),
            _ => None,
        }
    }

    /// Figure out index into zone array to get the correct slab allocator for that size.
    fn get_slab(requested_size: usize) -> Slab {
        match requested_size {
            0..=8 => Slab::Base(0),
            9..=16 => Slab::Base(1),
            17..=32 => Slab::Base(2),
            33..=64 => Slab::Base(3),
            65..=128 => Slab::Base(4),
            129..=256 => Slab::Base(5),
            257..=512 => Slab::Large(0),
            513..=1024 => Slab::Large(1),
            1025..=2048 => Slab::Large(2),
            2049..=4096 => Slab::Large(3),
            4097..=8192 => Slab::Large(4),
            8193..=16384 => Slab::Large(5),
            16385..=32767 => Slab::Large(6),
            32768..=65536 => Slab::Large(7),
            65537..=131_072 => Slab::Large(8),
            _ => Slab::Unsupported,
        }
    }
}

unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> {
    /// Allocate a pointer to a block of memory described by `layout`.
    fn allocate(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(idx) => self.small_slabs[idx].allocate(layout),
            Slab::Large(idx) => self.big_slabs[idx].allocate(layout),
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }

    /// Deallocates a pointer to a block of memory, which was
    /// previously allocated by `allocate`.
    ///
    /// # Arguments
    ///  * `ptr` - Address of the memory location to free.
    ///  * `layout` - Memory layout of the block pointed to by `ptr`.
    fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) -> Result<(), AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout),
            Slab::Large(idx) => self.big_slabs[idx].deallocate(ptr, layout),
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }

    /// Refills the SCAllocator for a given Layout with an ObjectPage.
    ///
    /// # Safety
    /// ObjectPage needs to be emtpy etc.
    unsafe fn refill(
        &mut self,
        layout: Layout,
        new_page: &'a mut ObjectPage<'a>,
    ) -> Result<(), AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(idx) => {
                self.small_slabs[idx].refill(new_page);
                Ok(())
            }
            Slab::Large(_idx) => Err(AllocationError::InvalidLayout),
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }

    /// Refills the SCAllocator for a given Layout with an ObjectPage.
    ///
    /// # Safety
    /// ObjectPage needs to be emtpy etc.
    unsafe fn refill_large(
        &mut self,
        layout: Layout,
        new_page: &'a mut LargeObjectPage<'a>,
    ) -> Result<(), AllocationError> {
        match ZoneAllocator::get_slab(layout.size()) {
            Slab::Base(_idx) => Err(AllocationError::InvalidLayout),
            Slab::Large(idx) => {
                self.big_slabs[idx].refill(new_page);
                Ok(())
            }
            Slab::Unsupported => Err(AllocationError::InvalidLayout),
        }
    }
}
<|endoftext|>


<commit_before>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate rx;

use rx::{Never, Observable, Observer, Subject};
use std::cell::RefCell;
use std::rc::Rc;

// Generator tests

#[test]
fn never() {
    let mut never = Never::new();
    let _subscription = never.subscribe_error(
        |_x: u8| panic!("never observable should not produce a value"),
        || panic!("never observable should not complete"),
        |_err: ()| panic!("never observable should not fail")
    );

    // Without something like a message loop, the observable cannot suddenly
    // start pushing values, so if it did not produce anything here, it never
    // will.
}

// Option tests

#[test]
fn option_subscribe_next() {
    let mut received = None;

    // Subscribing to `Some` should push the value.
    Some(19).subscribe_next(|x| received = Some(x));
    assert_eq!(Some(19), received);

    None.subscribe_next(|_x: u32| panic!("none should not push a value"));
}

#[test]
fn option_subscribe_completed() {
    let mut received = None;
    let mut completed = false;

    // Subscribing to `Some` should complete after pushing the value.
    Some(19).subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(19), received);
    assert!(completed);

    // Subscribing to `None` should complete without pushing a value.
    completed = false;
    None.subscribe_completed(
        |_x: u32| panic!("none should not push a value"),
        || completed = true
    );
    assert!(completed);
}

#[test]
fn option_subscribe_error() {
    let mut received = None;
    let mut completed = false;

    Some(23).subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("some observable should not fail")
    );
    assert_eq!(Some(23), received);
    assert!(completed);

    completed = false;
    None.subscribe_error(
        |_x: u32| panic!("none should not push a value"),
        || completed = true,
        |_err| panic!("none observable should not fail")
    );
    assert!(completed);
}

// Result tests

#[test]
fn result_subscribe_next_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    result.subscribe_next(|x| received = Some(x));
    assert_eq!(Some(13), received);
}

#[test]
#[should_panic]
fn result_subscribe_next_err() {
    let mut result: Result<u32, ()> = Err(());
    let mut received = None;

    // This should panic, because we did not provide an error handler.
    result.subscribe_next(|x| received = Some(x));
}

#[test]
fn result_subscribe_completed_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("ok result should not be a failing observable")
    );
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_err() {
    let mut result: Result<(), u32> = Err(17);
    let mut error = None;
    result.subscribe_error(
        |_x| panic!("err result should not push a value"),
        || panic!("err result should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(17), error);
}

// Slice tests

#[test]
fn slice_subscribe_next() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    values.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn slice_subscribe_completed() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    values.subscribe_completed(|&x| received.push(x), || completed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
}

#[test]
fn slice_subscribe_error() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    let mut failed = false;
    values.subscribe_error(|&x| received.push(x), || completed = true, |_err| failed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
    assert!(!failed);
}

#[test]
fn slice_subscribe_option() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[Some(2u8), Some(3), Some(5), Some(7), Some(11), Some(13), None];
    let mut received = Vec::new();
    values.subscribe_option(|x| received.push(x.cloned()));
    assert_eq!(&received[..], &expected[..]);
}

#[test]
fn slice_subscribe_result() {
    let mut values = &[2u8, 3, 5, 7];
    let expected = &[Ok(Some(2u8)), Ok(Some(3)), Ok(Some(5)), Ok(Some(7)), Ok(None)];
    let mut received = Vec::new();
    values.subscribe_result(|x| received.push(x.map(|y| y.cloned())));
    assert_eq!(&received[..], &expected[..]);
}

// Subject tests

#[test]
fn subject_on_next() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _subscription = subject.observable().subscribe_next(|x| received.push(x));

    // Subject should not push anything upon subscription.
    assert_eq!(0, received.len());

    let values = &[2u8, 3, 5, 7, 11, 13];
    for i in 0..values.len() {
        subject.on_next(values[i]);
        assert_eq!(&values[..i + 1], &received[..]);
    }
}

#[test]
fn subject_on_completed() {
    let mut subject = Subject::<u8, ()>::new();
    let mut completed = false;
    let _subscription = subject.observable().subscribe_completed(
        |_x| panic!("no value should be pushed"),
        || completed = true
    );

    // Subject should not push anything upon subscription.
    assert!(!completed);

    subject.on_completed();
    assert!(completed);
}

#[test]
fn subject_on_error() {
    let mut subject = Subject::<u8, u8>::new();
    let mut error = 0;
    let _subscription = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed"),
        || panic!("subject should not complete"),
        |err| error = err
    );

    // Subject should not fail upon subscription.
    assert_eq!(0, error);

    subject.on_error(41);
    assert_eq!(41, error);
}

/// Helper for the `subject_clones_once_per_observer()` test.
struct CloneCounter {
    counter: Rc<RefCell<u32>>,
}

impl Clone for CloneCounter {
    fn clone(&self) -> CloneCounter {
        let count: u32 = *self.counter.borrow();
        *self.counter.borrow_mut() = count + 1;
        CloneCounter {
            counter: self.counter.clone(),
        }
    }
}

#[test]
fn subject_clones_once_per_observer() {
    let mut subject = Subject::<CloneCounter, ()>::new();
    let mut first_called = false;
    let mut second_called = false;
    let counter = CloneCounter {
        counter: Rc::new(RefCell::new(0)),
    };

    // Subscribe twice.
    let _s1 = subject.observable().subscribe_next(|_x| first_called = true);
    let _s2 = subject.observable().subscribe_next(|_x| second_called = true);

    // Nothing should have been cloned yet.
    assert_eq!(0, *counter.counter.borrow());

    subject.on_next(counter.clone());

    // We cloned once, and the subject should have cloned once per subscription.
    assert_eq!(3, *counter.counter.borrow());
    assert!(first_called);
    assert!(second_called);
}

#[test]
fn subject_drop_subscription() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let subscription = subject.observable().subscribe_next(|x| received.push(x));

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);

    assert_eq!(&[2u8, 3, 5], &received[..]);

    drop(subscription);

    subject.on_next(7);
    subject.on_next(11);

    // Values pushed after drop should not have been invoked.
    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_drop_subscription_multi() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _s1 = subject.observable().subscribe_next(|x| received.push(x));
    let s2 = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed after dropping subscription"),
        || panic!("completion should not be signalled after dropping subscription"),
        |_err| panic!("failure should not be signalled after dropping subscription")
    );

    drop(s2);

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);
    subject.on_completed();

    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_continue_with() {
    use std::mem;
    let mut first = Subject::<u8, ()>::new();
    let mut second = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let mut completed = false;
    {
        let subscription = first.observable()
            .continue_with(&mut second.observable())
            .subscribe_completed(|x| received.push(x), || completed = true);

        // TODO: How can I keep this alive without the compiler complaining about borrows?
        mem::forget(subscription);
    }

    first.on_next(2);
    assert_eq!(&[2u8][..], &received[..]);

    // If `second` produces a value, it should not be pushed,
    // because `first` has not yet completed.
    second.on_next(3);
    assert_eq!(&[2u8][..], &received[..]);

    first.on_next(5);
    assert_eq!(&[2u8, 5][..], &received[..]);

    // Completing `first` should not complete the continuation,
    // nor should it push a value.
    first.on_completed();
    assert_eq!(&[2u8, 5][..], &received[..]);
    assert!(!completed);

    // Now pushing to `second` should have an effect, because `first` completed.
    second.on_next(7);
    assert_eq!(&[2u8, 5, 7][..], &received[..]);

    second.on_completed();
    assert!(completed);
}

// TODO: Test multiple subscriptions and combinations of values and completed/error.
// TODO: Add better tests for dropping the subject subscription.

// Transform tests

#[test]
fn map() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[4u8, 6, 10, 14, 22, 26];
    let mut received = Vec::new();
    let mut mapped = values.map(|x| x * 2);
    mapped.subscribe_next(|x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}

#[test]
fn map_does_not_change_error() {
    let mut error = None;
    let mut mapped = Err(23_u32).map(|x: u32| format!("{}", x));
    mapped.subscribe_error(
        |_x: String| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(23), error);
}

#[test]
fn map_error() {
    let mut error = None;
    let mut observable = Err(23_u32);
    let mut mapped = observable.map_error(|x| x * 2);
    mapped.subscribe_error(
        |_x: u32| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(46), error);
}

#[test]
fn map_error_does_not_change_values() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut mapped = values.map_error(|_unit| 17u8);
    mapped.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn continue_with() {
    let (mut first, mut second) = (&[2u8, 3, 5, 7], &[11u8, 13, 17, 19]);
    let expected = &[2u8, 3, 5, 7, 11, 13, 17, 19];
    let mut received = Vec::new();
    let mut continued = first.continue_with(&mut second);
    continued.subscribe_next(|&x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}
<commit_msg>Add test for dropping subscription from handler<commit_after>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate rx;

use rx::{Never, Observable, Observer, Subject};
use std::cell::RefCell;
use std::rc::Rc;

// Generator tests

#[test]
fn never() {
    let mut never = Never::new();
    let _subscription = never.subscribe_error(
        |_x: u8| panic!("never observable should not produce a value"),
        || panic!("never observable should not complete"),
        |_err: ()| panic!("never observable should not fail")
    );

    // Without something like a message loop, the observable cannot suddenly
    // start pushing values, so if it did not produce anything here, it never
    // will.
}

// Option tests

#[test]
fn option_subscribe_next() {
    let mut received = None;

    // Subscribing to `Some` should push the value.
    Some(19).subscribe_next(|x| received = Some(x));
    assert_eq!(Some(19), received);

    None.subscribe_next(|_x: u32| panic!("none should not push a value"));
}

#[test]
fn option_subscribe_completed() {
    let mut received = None;
    let mut completed = false;

    // Subscribing to `Some` should complete after pushing the value.
    Some(19).subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(19), received);
    assert!(completed);

    // Subscribing to `None` should complete without pushing a value.
    completed = false;
    None.subscribe_completed(
        |_x: u32| panic!("none should not push a value"),
        || completed = true
    );
    assert!(completed);
}

#[test]
fn option_subscribe_error() {
    let mut received = None;
    let mut completed = false;

    Some(23).subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("some observable should not fail")
    );
    assert_eq!(Some(23), received);
    assert!(completed);

    completed = false;
    None.subscribe_error(
        |_x: u32| panic!("none should not push a value"),
        || completed = true,
        |_err| panic!("none observable should not fail")
    );
    assert!(completed);
}

// Result tests

#[test]
fn result_subscribe_next_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    result.subscribe_next(|x| received = Some(x));
    assert_eq!(Some(13), received);
}

#[test]
#[should_panic]
fn result_subscribe_next_err() {
    let mut result: Result<u32, ()> = Err(());
    let mut received = None;

    // This should panic, because we did not provide an error handler.
    result.subscribe_next(|x| received = Some(x));
}

#[test]
fn result_subscribe_completed_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("ok result should not be a failing observable")
    );
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_err() {
    let mut result: Result<(), u32> = Err(17);
    let mut error = None;
    result.subscribe_error(
        |_x| panic!("err result should not push a value"),
        || panic!("err result should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(17), error);
}

// Slice tests

#[test]
fn slice_subscribe_next() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    values.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn slice_subscribe_completed() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    values.subscribe_completed(|&x| received.push(x), || completed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
}

#[test]
fn slice_subscribe_error() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    let mut failed = false;
    values.subscribe_error(|&x| received.push(x), || completed = true, |_err| failed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
    assert!(!failed);
}

#[test]
fn slice_subscribe_option() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[Some(2u8), Some(3), Some(5), Some(7), Some(11), Some(13), None];
    let mut received = Vec::new();
    values.subscribe_option(|x| received.push(x.cloned()));
    assert_eq!(&received[..], &expected[..]);
}

#[test]
fn slice_subscribe_result() {
    let mut values = &[2u8, 3, 5, 7];
    let expected = &[Ok(Some(2u8)), Ok(Some(3)), Ok(Some(5)), Ok(Some(7)), Ok(None)];
    let mut received = Vec::new();
    values.subscribe_result(|x| received.push(x.map(|y| y.cloned())));
    assert_eq!(&received[..], &expected[..]);
}

// Subject tests

#[test]
fn subject_on_next() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _subscription = subject.observable().subscribe_next(|x| received.push(x));

    // Subject should not push anything upon subscription.
    assert_eq!(0, received.len());

    let values = &[2u8, 3, 5, 7, 11, 13];
    for i in 0..values.len() {
        subject.on_next(values[i]);
        assert_eq!(&values[..i + 1], &received[..]);
    }
}

#[test]
fn subject_on_completed() {
    let mut subject = Subject::<u8, ()>::new();
    let mut completed = false;
    let _subscription = subject.observable().subscribe_completed(
        |_x| panic!("no value should be pushed"),
        || completed = true
    );

    // Subject should not push anything upon subscription.
    assert!(!completed);

    subject.on_completed();
    assert!(completed);
}

#[test]
fn subject_on_error() {
    let mut subject = Subject::<u8, u8>::new();
    let mut error = 0;
    let _subscription = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed"),
        || panic!("subject should not complete"),
        |err| error = err
    );

    // Subject should not fail upon subscription.
    assert_eq!(0, error);

    subject.on_error(41);
    assert_eq!(41, error);
}

/// Helper for the `subject_clones_once_per_observer()` test.
struct CloneCounter {
    counter: Rc<RefCell<u32>>,
}

impl Clone for CloneCounter {
    fn clone(&self) -> CloneCounter {
        let count: u32 = *self.counter.borrow();
        *self.counter.borrow_mut() = count + 1;
        CloneCounter {
            counter: self.counter.clone(),
        }
    }
}

#[test]
fn subject_clones_once_per_observer() {
    let mut subject = Subject::<CloneCounter, ()>::new();
    let mut first_called = false;
    let mut second_called = false;
    let counter = CloneCounter {
        counter: Rc::new(RefCell::new(0)),
    };

    // Subscribe twice.
    let _s1 = subject.observable().subscribe_next(|_x| first_called = true);
    let _s2 = subject.observable().subscribe_next(|_x| second_called = true);

    // Nothing should have been cloned yet.
    assert_eq!(0, *counter.counter.borrow());

    subject.on_next(counter.clone());

    // We cloned once, and the subject should have cloned once per subscription.
    assert_eq!(3, *counter.counter.borrow());
    assert!(first_called);
    assert!(second_called);
}

#[test]
fn subject_drop_subscription() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let subscription = subject.observable().subscribe_next(|x| received.push(x));

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);

    assert_eq!(&[2u8, 3, 5], &received[..]);

    drop(subscription);

    subject.on_next(7);
    subject.on_next(11);

    // Values pushed after drop should not have been invoked.
    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_drop_subscription_multi() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _s1 = subject.observable().subscribe_next(|x| received.push(x));
    let s2 = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed after dropping subscription"),
        || panic!("completion should not be signalled after dropping subscription"),
        |_err| panic!("failure should not be signalled after dropping subscription")
    );

    drop(s2);

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);
    subject.on_completed();

    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_drop_in_handler() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let mut subscription_opt: Option<Box<Drop>> = None;
    let subscription = subject.observable().subscribe_next(|x| {
        received.push(x);
        assert!(subscription_opt.is_some());
        drop(subscription_opt.take().unwrap());
    });
    // TODO: this assignment is not unused, or this code doing something illegal.
    // Either way, this is a bug in rustc.
    subscription_opt = Some(Box::new(subscription));

    subject.on_next(2);
    assert_eq!(&[2u8], &received[..]);

    subject.on_next(3);
    assert_eq!(&[2u8], &received[..]);
}

#[test]
fn subject_continue_with() {
    use std::mem;
    let mut first = Subject::<u8, ()>::new();
    let mut second = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let mut completed = false;
    {
        let subscription = first.observable()
            .continue_with(&mut second.observable())
            .subscribe_completed(|x| received.push(x), || completed = true);

        // TODO: How can I keep this alive without the compiler complaining about borrows?
        mem::forget(subscription);
    }

    first.on_next(2);
    assert_eq!(&[2u8][..], &received[..]);

    // If `second` produces a value, it should not be pushed,
    // because `first` has not yet completed.
    second.on_next(3);
    assert_eq!(&[2u8][..], &received[..]);

    first.on_next(5);
    assert_eq!(&[2u8, 5][..], &received[..]);

    // Completing `first` should not complete the continuation,
    // nor should it push a value.
    first.on_completed();
    assert_eq!(&[2u8, 5][..], &received[..]);
    assert!(!completed);

    // Now pushing to `second` should have an effect, because `first` completed.
    second.on_next(7);
    assert_eq!(&[2u8, 5, 7][..], &received[..]);

    second.on_completed();
    assert!(completed);
}

// TODO: Test multiple subscriptions and combinations of values and completed/error.
// TODO: Add better tests for dropping the subject subscription.

// Transform tests

#[test]
fn map() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[4u8, 6, 10, 14, 22, 26];
    let mut received = Vec::new();
    let mut mapped = values.map(|x| x * 2);
    mapped.subscribe_next(|x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}

#[test]
fn map_does_not_change_error() {
    let mut error = None;
    let mut mapped = Err(23_u32).map(|x: u32| format!("{}", x));
    mapped.subscribe_error(
        |_x: String| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(23), error);
}

#[test]
fn map_error() {
    let mut error = None;
    let mut observable = Err(23_u32);
    let mut mapped = observable.map_error(|x| x * 2);
    mapped.subscribe_error(
        |_x: u32| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(46), error);
}

#[test]
fn map_error_does_not_change_values() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut mapped = values.map_error(|_unit| 17u8);
    mapped.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn continue_with() {
    let (mut first, mut second) = (&[2u8, 3, 5, 7], &[11u8, 13, 17, 19]);
    let expected = &[2u8, 3, 5, 7, 11, 13, 17, 19];
    let mut received = Vec::new();
    let mut continued = first.continue_with(&mut second);
    continued.subscribe_next(|&x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}
<|endoftext|>


<commit_before>extern crate cheddar;

fn main() {
    // Generate mp4parse.h.
    cheddar::Cheddar::new().expect("could not read manifest")
        .insert_code("// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n")
        .insert_code("// This Source Code Form is subject to the terms of the Mozilla Public\n")
        .insert_code("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")
        .insert_code("// file, You can obtain one at https://mozilla.org/MPL/2.0/.")
        .run_build("include/mp4parse.h");
}
<commit_msg>Avoid rebuilds triggered by build.rs unless src/lib.rs actually changed.<commit_after>extern crate cheddar;

fn main() {
    println!("cargo:rerun-if-changed=src/lib.rs");
    // Generate mp4parse.h.
    cheddar::Cheddar::new().expect("could not read manifest")
        .insert_code("// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n")
        .insert_code("// This Source Code Form is subject to the terms of the Mozilla Public\n")
        .insert_code("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")
        .insert_code("// file, You can obtain one at https://mozilla.org/MPL/2.0/.")
        .run_build("include/mp4parse.h");
}
<|endoftext|>