<commit_before>extern crate libc;
extern crate libarchive3_sys;

use self::libarchive3_sys::ffi;
use std::ffi::{CStr, CString};
use std::marker;
use std::ptr;
use std::io::{Result, Error, SeekFrom, Read, Seek, ErrorKind};
use std::error::Error as STDError;
use fs::{SeekableRead, SeekExt};
use std::cmp::min;
use std::path::PathBuf;

struct Proxy<R: SeekableRead> {
    r: R,
    buf: Vec<u8>,
    pos: u64,
}

impl<R: SeekableRead> Proxy<R> {
    fn new(r: R) -> Proxy<R> {
        let mut v = Vec::new();
        v.resize(4096, 0);
        Proxy {
            r: r,
            buf: v,
            pos: 0,
        }
    }

    fn read(&mut self) -> Result<&[u8]> {
        let n = self.r.read(&mut self.buf[..])?;
        self.pos += n as u64;
        Ok(&self.buf[..n])
    }

    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.pos = self.r.seek(pos)?;
        Ok(self.pos)
    }

    fn skip(&mut self, request: libc::int64_t) -> Result<libc::int64_t> {
        let now = self.r.seek(SeekFrom::Current(request))?;
        let skip = now - self.pos;
        self.pos = now;
        Ok(skip as libc::int64_t)
    }
}

pub struct Archive<R: SeekableRead> {
    raw: *mut ffi::Struct_archive,
    eof: bool,
    _proxy: Box<Proxy<R>>,
}

unsafe fn set_error(raw: *mut ffi::Struct_archive, e: Error) {
    let desc = CString::new(e.description()).unwrap();
    ffi::archive_set_error(raw, e.raw_os_error().unwrap_or(libc::EIO), desc.as_ptr());
}

unsafe fn error_string(raw: *mut ffi::Struct_archive) -> String {
    CStr::from_ptr(ffi::archive_error_string(raw)).to_str().unwrap().to_string()
}

unsafe extern "C" fn read_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    buffer: *mut *const libc::c_void)
                                                    -> libc::ssize_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let err;
    match proxy.read() {
        Ok(data) => {
            *buffer = data.as_ptr() as *const libc::c_void;
            return data.len() as libc::ssize_t;
        }
        Err(e) => err = e,
    };
    set_error(raw, err);
    -1
}

unsafe extern "C" fn skip_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    request: libc::int64_t)
                                                    -> libc::int64_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    match proxy.skip(request) {
        Ok(n) => n,
        Err(e) => {
            // collect?
            set_error(raw, e);
            0
        }
    }
}

unsafe extern "C" fn seek_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    offset: libc::int64_t,
                                                    whence: libc::c_int)
                                                    -> libc::int64_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let pos = match whence {
        libc::SEEK_SET => SeekFrom::Start(offset as u64),
        libc::SEEK_CUR => SeekFrom::Current(offset),
        libc::SEEK_END => SeekFrom::End(offset),
        _ => unreachable!(),
    };
    match proxy.seek(pos) {
        Ok(n) => n as libc::int64_t,
        Err(e) => {
            // collect?
            set_error(raw, e);
            -1
        }
    }
}

impl<R: SeekableRead> Archive<R> {
    pub fn new(r: R) -> Self {
        unsafe {
            let raw = ffi::archive_read_new();
            if raw.is_null() {
                panic!("oom");
            }
            if ffi::archive_read_support_format_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support format");
            }
            if ffi::archive_read_support_filter_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support filter");
            }
            if r.bidirectional() {
                if ffi::archive_read_set_seek_callback(raw, Some(seek_callback::<R>)) !=
                   ffi::ARCHIVE_OK {
                    panic!("failed to set seek");
                }
            } else {
                if ffi::archive_read_set_skip_callback(raw, Some(skip_callback::<R>)) !=
                   ffi::ARCHIVE_OK {
                    panic!("failed to set skip");
                }
            }
            let proxy = Box::into_raw(Box::new(Proxy::new(r)));
            if ffi::archive_read_open(raw,
                                      proxy as *mut libc::c_void,
                                      None,
                                      Some(read_callback::<R>),
                                      None) != ffi::ARCHIVE_OK {
                panic!("failed to open");
            }
            Archive {
                raw: raw,
                eof: false,
                _proxy: Box::from_raw(proxy),
            }
        }
    }

    fn next_entry_raw(&mut self) -> Option<Result<Entry>> {
        if self.eof {
            return None;
        }

        let mut entry = ptr::null_mut();
        loop {
            match unsafe { ffi::archive_read_next_header(self.raw, &mut entry) } {
                ffi::ARCHIVE_OK => break,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_next_header: {}",
                          unsafe { error_string(self.raw) });
                    break;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return None;
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_next_header: {}",
                          unsafe { error_string(self.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Some(Err(Error::new(ErrorKind::Other,
                                               unsafe { error_string(self.raw) })));
                }
                _ => unreachable!(),
            }

        }
        Some(Ok(Entry::new(entry)))
    }

    pub fn next_entry<'a>(&'a mut self) -> Option<Result<RefEntry<'a, R>>> {
        self.next_entry_raw().map(|r| r.map(|e| RefEntry::new(e)))
    }

    pub fn find_map<F, T>(mut self, f: F) -> Option<Result<T>>
        where F: Fn(&Entry) -> Option<T>
    {
        loop {
            match self.next_entry_raw() {
                Some(Ok(e)) => {
                    if let Some(x) = f(&e) {
                        return Some(Ok(x));
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }

    pub fn find_open<P>(mut self, p: P) -> Option<Result<Reader<R>>>
        where P: Fn(&Entry) -> bool
    {
        loop {
            match self.next_entry_raw() {
                Some(Ok(e)) => {
                    if p(&e) {
                        break;
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
        Some(Ok(Reader::new(self)))
    }
}

impl<R: SeekableRead> Drop for Archive<R> {
    fn drop(&mut self) {
        unsafe { ffi::archive_read_free(self.raw) };
    }
}

pub struct Reader<R: SeekableRead> {
    a: Archive<R>,
    buf: *const libc::c_void,
    read_pos: usize,
    buf_size: libc::size_t,
    offset: libc::off_t,
    eof: bool,
}

impl<R: SeekableRead> Reader<R> {
    fn new(a: Archive<R>) -> Reader<R> {
        Reader {
            a: a,
            buf: ptr::null(),
            read_pos: 0,
            buf_size: 0,
            offset: 0,
            eof: false,
        }
    }

    fn fill_gap(&mut self, buf: &mut [u8]) -> usize {
        if self.read_pos < self.offset as usize {
            let l = min(buf.len(), (self.offset as usize) - self.read_pos);
            for x in &mut buf[..l] {
                *x = 0;
            }
            self.read_pos += l;
            return l;
        }
        0
    }

    fn read_data_block(&mut self) -> Result<()> {
        if self.eof {
            return Ok(());
        }

        while self.offset as usize + self.buf_size as usize <= self.read_pos {
            match unsafe {
                ffi::archive_read_data_block(self.a.raw,
                                             &mut self.buf,
                                             &mut self.buf_size,
                                             &mut self.offset)
            } {
                ffi::ARCHIVE_OK => continue,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_data_block: {}",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return Ok(());
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_data_block: {}",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Err(Error::new(ErrorKind::Other, unsafe { error_string(self.a.raw) }));
                }
                _ => unreachable!(),
            }
        }
        Ok(())
    }
}

impl<R: SeekableRead> SeekExt for Reader<R> {
    fn bidirectional(&self) -> bool {
        return false;
    }
}

impl<R: SeekableRead> Read for Reader<R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.read_data_block()?;
        let n = self.fill_gap(buf);
        if n > 0 {
            return Ok(n);
        }
        let begin = self.read_pos - self.offset as usize;
        let l = min(buf.len(), self.buf_size - begin);
        unsafe {
            let p = (self.buf as *const u8).offset(begin as isize);
            ptr::copy_nonoverlapping(p, buf.as_mut_ptr(), l);
        }
        self.read_pos += l;
        Ok(l)
    }
}

impl<R: SeekableRead> Seek for Reader<R> {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        match pos {
            SeekFrom::Start(n) => self.read_pos = n as usize,
            SeekFrom::End(n) => unimplemented!(),
            SeekFrom::Current(n) => self.read_pos += n as usize,
        }
        Ok(self.read_pos as u64)
    }
}

pub struct Entry {
    entry: *mut ffi::Struct_archive_entry,
}

impl Entry {
    fn new(entry: *mut ffi::Struct_archive_entry) -> Entry {
        Entry { entry: entry }
    }

    pub fn pathname(&self) -> PathBuf {
        let c_str = unsafe { CStr::from_ptr(ffi::archive_entry_pathname(self.entry)) };
        PathBuf::from(c_str.to_string_lossy().as_ref())
    }

    pub fn size(&self) -> libc::int64_t {
        unsafe { ffi::archive_entry_size(self.entry) }
    }

    pub fn filetype(&self) -> libc::mode_t {
        unsafe { ffi::archive_entry_filetype(self.entry) }
    }
}

pub struct RefEntry<'a, R: SeekableRead + 'a> {
    e: Entry,
    _m: marker::PhantomData<&'a R>,
}

impl<'a, R: SeekableRead> RefEntry<'a, R> {
    fn new(e: Entry) -> RefEntry<'a, R> {
        RefEntry {
            e: e,
            _m: marker::PhantomData,
        }
    }

    pub fn pathname(&self) -> PathBuf {
        self.e.pathname()
    }

    pub fn size(&self) -> libc::int64_t {
        self.e.size()
    }

    pub fn filetype(&self) -> libc::mode_t {
        self.e.filetype()
    }
}
<commit_msg>set locale to convert pathname correctly<commit_after>extern crate libc;
extern crate libarchive3_sys;

use self::libarchive3_sys::ffi;
use std::ffi::{CStr, CString};
use std::marker;
use std::ptr;
use std::io::{Result, Error, SeekFrom, Read, Seek, ErrorKind};
use std::error::Error as STDError;
use fs::{SeekableRead, SeekExt};
use std::cmp::min;
use std::path::PathBuf;
use std::sync::{Once, ONCE_INIT};

// libarchive needs locale to convert pathname.
fn setlocale_once() {
    static ONCE: Once = ONCE_INIT;
    ONCE.call_once(|| unsafe {
        libc::setlocale(libc::LC_ALL, CString::new("").unwrap().as_ptr());
    });
}

struct Proxy<R: SeekableRead> {
    r: R,
    buf: Vec<u8>,
    pos: u64,
}

impl<R: SeekableRead> Proxy<R> {
    fn new(r: R) -> Proxy<R> {
        let mut v = Vec::new();
        v.resize(4096, 0);
        Proxy {
            r: r,
            buf: v,
            pos: 0,
        }
    }

    fn read(&mut self) -> Result<&[u8]> {
        let n = self.r.read(&mut self.buf[..])?;
        self.pos += n as u64;
        Ok(&self.buf[..n])
    }

    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        self.pos = self.r.seek(pos)?;
        Ok(self.pos)
    }

    fn skip(&mut self, request: libc::int64_t) -> Result<libc::int64_t> {
        let now = self.r.seek(SeekFrom::Current(request))?;
        let skip = now - self.pos;
        self.pos = now;
        Ok(skip as libc::int64_t)
    }
}

pub struct Archive<R: SeekableRead> {
    raw: *mut ffi::Struct_archive,
    eof: bool,
    _proxy: Box<Proxy<R>>,
}

unsafe fn set_error(raw: *mut ffi::Struct_archive, e: Error) {
    let desc = CString::new(e.description()).unwrap();
    ffi::archive_set_error(raw, e.raw_os_error().unwrap_or(libc::EIO), desc.as_ptr());
}

unsafe fn error_string(raw: *mut ffi::Struct_archive) -> String {
    CStr::from_ptr(ffi::archive_error_string(raw)).to_str().unwrap().to_string()
}

unsafe extern "C" fn read_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    buffer: *mut *const libc::c_void)
                                                    -> libc::ssize_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let err;
    match proxy.read() {
        Ok(data) => {
            *buffer = data.as_ptr() as *const libc::c_void;
            return data.len() as libc::ssize_t;
        }
        Err(e) => err = e,
    };
    set_error(raw, err);
    -1
}

unsafe extern "C" fn skip_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    request: libc::int64_t)
                                                    -> libc::int64_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    match proxy.skip(request) {
        Ok(n) => n,
        Err(e) => {
            // collect?
            set_error(raw, e);
            0
        }
    }
}

unsafe extern "C" fn seek_callback<R: SeekableRead>(raw: *mut ffi::Struct_archive,
                                                    client_data: *mut libc::c_void,
                                                    offset: libc::int64_t,
                                                    whence: libc::c_int)
                                                    -> libc::int64_t {
    let proxy = (client_data as *mut Proxy<R>).as_mut().unwrap();
    let pos = match whence {
        libc::SEEK_SET => SeekFrom::Start(offset as u64),
        libc::SEEK_CUR => SeekFrom::Current(offset),
        libc::SEEK_END => SeekFrom::End(offset),
        _ => unreachable!(),
    };
    match proxy.seek(pos) {
        Ok(n) => n as libc::int64_t,
        Err(e) => {
            // collect?
            set_error(raw, e);
            -1
        }
    }
}

impl<R: SeekableRead> Archive<R> {
    pub fn new(r: R) -> Self {
        setlocale_once();
        unsafe {
            let raw = ffi::archive_read_new();
            if raw.is_null() {
                panic!("oom");
            }
            if ffi::archive_read_support_format_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support format");
            }
            if ffi::archive_read_support_filter_all(raw) != ffi::ARCHIVE_OK {
                panic!("not support filter");
            }
            if r.bidirectional() {
                if ffi::archive_read_set_seek_callback(raw, Some(seek_callback::<R>)) !=
                   ffi::ARCHIVE_OK {
                    panic!("failed to set seek");
                }
            } else {
                if ffi::archive_read_set_skip_callback(raw, Some(skip_callback::<R>)) !=
                   ffi::ARCHIVE_OK {
                    panic!("failed to set skip");
                }
            }
            let proxy = Box::into_raw(Box::new(Proxy::new(r)));
            if ffi::archive_read_open(raw,
                                      proxy as *mut libc::c_void,
                                      None,
                                      Some(read_callback::<R>),
                                      None) != ffi::ARCHIVE_OK {
                panic!("failed to open");
            }
            Archive {
                raw: raw,
                eof: false,
                _proxy: Box::from_raw(proxy),
            }
        }
    }

    fn next_entry_raw(&mut self) -> Option<Result<Entry>> {
        if self.eof {
            return None;
        }

        let mut entry = ptr::null_mut();
        loop {
            match unsafe { ffi::archive_read_next_header(self.raw, &mut entry) } {
                ffi::ARCHIVE_OK => break,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_next_header: {}",
                          unsafe { error_string(self.raw) });
                    break;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return None;
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_next_header: {}, retry.",
                          unsafe { error_string(self.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Some(Err(Error::new(ErrorKind::Other,
                                               unsafe { error_string(self.raw) })));
                }
                _ => unreachable!(),
            }

        }
        Some(Ok(Entry::new(entry)))
    }

    pub fn next_entry<'a>(&'a mut self) -> Option<Result<RefEntry<'a, R>>> {
        self.next_entry_raw().map(|r| r.map(|e| RefEntry::new(e)))
    }

    pub fn find_map<F, T>(mut self, f: F) -> Option<Result<T>>
        where F: Fn(&Entry) -> Option<T>
    {
        loop {
            match self.next_entry_raw() {
                Some(Ok(e)) => {
                    if let Some(x) = f(&e) {
                        return Some(Ok(x));
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }

    pub fn find_open<P>(mut self, p: P) -> Option<Result<Reader<R>>>
        where P: Fn(&Entry) -> bool
    {
        loop {
            match self.next_entry_raw() {
                Some(Ok(e)) => {
                    if p(&e) {
                        break;
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
        Some(Ok(Reader::new(self)))
    }
}

impl<R: SeekableRead> Drop for Archive<R> {
    fn drop(&mut self) {
        unsafe { ffi::archive_read_free(self.raw) };
    }
}

pub struct Reader<R: SeekableRead> {
    a: Archive<R>,
    buf: *const libc::c_void,
    read_pos: usize,
    buf_size: libc::size_t,
    offset: libc::off_t,
    eof: bool,
}

impl<R: SeekableRead> Reader<R> {
    fn new(a: Archive<R>) -> Reader<R> {
        Reader {
            a: a,
            buf: ptr::null(),
            read_pos: 0,
            buf_size: 0,
            offset: 0,
            eof: false,
        }
    }

    fn fill_gap(&mut self, buf: &mut [u8]) -> usize {
        if self.read_pos < self.offset as usize {
            let l = min(buf.len(), (self.offset as usize) - self.read_pos);
            for x in &mut buf[..l] {
                *x = 0;
            }
            self.read_pos += l;
            return l;
        }
        0
    }

    fn read_data_block(&mut self) -> Result<()> {
        if self.eof {
            return Ok(());
        }

        while self.offset as usize + self.buf_size as usize <= self.read_pos {
            match unsafe {
                ffi::archive_read_data_block(self.a.raw,
                                             &mut self.buf,
                                             &mut self.buf_size,
                                             &mut self.offset)
            } {
                ffi::ARCHIVE_OK => continue,
                ffi::ARCHIVE_WARN => {
                    warn!("archive_read_data_block: {}",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_EOF => {
                    self.eof = true;
                    return Ok(());
                }
                ffi::ARCHIVE_RETRY => {
                    // failed but retryable.
                    warn!("archive_read_data_block: {}, retry",
                          unsafe { error_string(self.a.raw) });
                    continue;
                }
                ffi::ARCHIVE_FATAL => {
                    return Err(Error::new(ErrorKind::Other, unsafe { error_string(self.a.raw) }));
                }
                _ => unreachable!(),
            }
        }
        Ok(())
    }
}

impl<R: SeekableRead> SeekExt for Reader<R> {
    fn bidirectional(&self) -> bool {
        return false;
    }
}

impl<R: SeekableRead> Read for Reader<R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.read_data_block()?;
        let n = self.fill_gap(buf);
        if n > 0 {
            return Ok(n);
        }
        let begin = self.read_pos - self.offset as usize;
        let l = min(buf.len(), self.buf_size - begin);
        unsafe {
            let p = (self.buf as *const u8).offset(begin as isize);
            ptr::copy_nonoverlapping(p, buf.as_mut_ptr(), l);
        }
        self.read_pos += l;
        Ok(l)
    }
}

impl<R: SeekableRead> Seek for Reader<R> {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        match pos {
            SeekFrom::Start(n) => self.read_pos = n as usize,
            SeekFrom::End(n) => unimplemented!(),
            SeekFrom::Current(n) => self.read_pos += n as usize,
        }
        Ok(self.read_pos as u64)
    }
}

pub struct Entry {
    entry: *mut ffi::Struct_archive_entry,
}

impl Entry {
    fn new(entry: *mut ffi::Struct_archive_entry) -> Entry {
        Entry { entry: entry }
    }

    pub fn pathname(&self) -> PathBuf {
        let c_str = unsafe { CStr::from_ptr(ffi::archive_entry_pathname(self.entry)) };
        PathBuf::from(c_str.to_string_lossy().as_ref())
    }

    pub fn size(&self) -> libc::int64_t {
        unsafe { ffi::archive_entry_size(self.entry) }
    }

    pub fn filetype(&self) -> libc::mode_t {
        unsafe { ffi::archive_entry_filetype(self.entry) }
    }
}

pub struct RefEntry<'a, R: SeekableRead + 'a> {
    e: Entry,
    _m: marker::PhantomData<&'a R>,
}

impl<'a, R: SeekableRead> RefEntry<'a, R> {
    fn new(e: Entry) -> RefEntry<'a, R> {
        RefEntry {
            e: e,
            _m: marker::PhantomData,
        }
    }

    pub fn pathname(&self) -> PathBuf {
        self.e.pathname()
    }

    pub fn size(&self) -> libc::int64_t {
        self.e.size()
    }

    pub fn filetype(&self) -> libc::mode_t {
        self.e.filetype()
    }
}
<|endoftext|>


<commit_before>//! `x86` and `x86_64` intrinsics.

pub use self::ia32::*;
pub use self::cpuid::*;
pub use self::xsave::*;

pub use self::sse::*;
pub use self::sse2::*;
pub use self::sse3::*;
pub use self::ssse3::*;
pub use self::sse41::*;
pub use self::sse42::*;
pub use self::avx::*;
pub use self::avx2::*;

pub use self::abm::*;
pub use self::bmi::*;
pub use self::bmi2::*;

#[cfg(not(feature = "intel_sde"))]
pub use self::tbm::*;

/// 128-bit wide signed integer vector type
#[allow(non_camel_case_types)]
pub type __m128i = ::v128::i8x16;
/// 256-bit wide signed integer vector type
#[allow(non_camel_case_types)]
pub type __m256i = ::v256::i8x32;

#[macro_use]
mod macros;

mod ia32;
mod cpuid;
mod xsave;

mod sse;
mod sse2;
mod sse3;
mod ssse3;
mod sse41;
mod sse42;
mod avx;
mod avx2;

mod abm;
mod bmi;
mod bmi2;

#[cfg(not(feature = "intel_sde"))]
mod tbm;

#[allow(non_camel_case_types)]
#[cfg(not(feature = "std"))]
#[repr(u8)]
pub enum c_void {
    #[doc(hidden)] __variant1,
    #[doc(hidden)] __variant2,
}

#[cfg(feature = "std")]
use std::os::raw::c_void;
<commit_msg>[clippy] fix missing doc on pub item<commit_after>//! `x86` and `x86_64` intrinsics.

pub use self::ia32::*;
pub use self::cpuid::*;
pub use self::xsave::*;

pub use self::sse::*;
pub use self::sse2::*;
pub use self::sse3::*;
pub use self::ssse3::*;
pub use self::sse41::*;
pub use self::sse42::*;
pub use self::avx::*;
pub use self::avx2::*;

pub use self::abm::*;
pub use self::bmi::*;
pub use self::bmi2::*;

#[cfg(not(feature = "intel_sde"))]
pub use self::tbm::*;

/// 128-bit wide signed integer vector type
#[allow(non_camel_case_types)]
pub type __m128i = ::v128::i8x16;
/// 256-bit wide signed integer vector type
#[allow(non_camel_case_types)]
pub type __m256i = ::v256::i8x32;

#[macro_use]
mod macros;

mod ia32;
mod cpuid;
mod xsave;

mod sse;
mod sse2;
mod sse3;
mod ssse3;
mod sse41;
mod sse42;
mod avx;
mod avx2;

mod abm;
mod bmi;
mod bmi2;

#[cfg(not(feature = "intel_sde"))]
mod tbm;

/// `C`'s `void` type.
#[cfg(not(feature = "std"))]
#[allow(non_camel_case_types)]
#[repr(u8)]
pub enum c_void {
    #[doc(hidden)] __variant1,
    #[doc(hidden)] __variant2,
}

#[cfg(feature = "std")]
use std::os::raw::c_void;
<|endoftext|>


<commit_before>use std::io;
use std::mem;

use kernel32;
use winapi::{DWORD, HANDLE, WORD};
use winapi::winbase::STD_OUTPUT_HANDLE;
use winapi::wincon::{
    FOREGROUND_BLUE as FG_BLUE,
    FOREGROUND_GREEN as FG_GREEN,
    FOREGROUND_RED as FG_RED,
    FOREGROUND_INTENSITY as FG_INTENSITY,
};

const FG_CYAN: DWORD = FG_BLUE | FG_GREEN;
const FG_MAGENTA: DWORD = FG_BLUE | FG_RED;
const FG_YELLOW: DWORD = FG_GREEN | FG_RED;
const FG_WHITE: DWORD = FG_BLUE | FG_GREEN | FG_RED;

/// A Windows console.
///
/// This represents a very limited set of functionality available to a Windows
/// console. In particular, it can only change text attributes such as color
/// and intensity.
///
/// There is no way to "write" to this console. Simply write to
/// stdout or stderr instead, while interleaving instructions to the console
/// to change text attributes.
///
/// A common pitfall when using a console is to forget to flush writes to
/// stdout before setting new text attributes.
#[derive(Debug)]
pub struct Console {
    handle: HANDLE,
    start_attr: TextAttributes,
    cur_attr: TextAttributes,
}

unsafe impl Send for Console {}

impl Drop for Console {
    fn drop(&mut self) {
        unsafe { kernel32::CloseHandle(self.handle); }
    }
}

impl Console {
    /// Create a new Console to stdout.
    ///
    /// If there was a problem creating the console, then an error is returned.
    pub fn stdout() -> io::Result<Console> {
        let mut info = unsafe { mem::zeroed() };
        let (handle, res) = unsafe {
            let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE);
            (handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
        };
        if res == 0 {
            return Err(io::Error::last_os_error());
        }
        let attr = TextAttributes::from_word(info.wAttributes);
        Ok(Console {
            handle: handle,
            start_attr: attr,
            cur_attr: attr,
        })
    }

    /// Applies the current text attributes.
    fn set(&mut self) -> io::Result<()> {
        let attr = self.cur_attr.to_word();
        let res = unsafe {
            kernel32::SetConsoleTextAttribute(self.handle, attr)
        };
        if res == 0 {
            return Err(io::Error::last_os_error());
        }
        Ok(())
    }

    /// Apply the given intensity and color attributes to the console
    /// foreground.
    ///
    /// If there was a problem setting attributes on the console, then an error
    /// is returned.
    pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
        self.cur_attr.fg_color = color;
        self.cur_attr.fg_intense = intense;
        self.set()
    }

    /// Apply the given intensity and color attributes to the console
    /// background.
    ///
    /// If there was a problem setting attributes on the console, then an error
    /// is returned.
    pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
        self.cur_attr.bg_color = color;
        self.cur_attr.bg_intense = intense;
        self.set()
    }

    /// Reset the console text attributes to their original settings.
    ///
    /// The original settings correspond to the text attributes on the console
    /// when this `Console` value was created.
    ///
    /// If there was a problem setting attributes on the console, then an error
    /// is returned.
    pub fn reset(&mut self) -> io::Result<()> {
        self.cur_attr = self.start_attr;
        self.set()
    }
}

/// A representation of text attributes for the Windows console.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct TextAttributes {
    fg_color: Color,
    fg_intense: Intense,
    bg_color: Color,
    bg_intense: Intense,
}

impl TextAttributes {
    fn to_word(&self) -> WORD {
        let mut w = 0;
        w |= self.fg_color.to_fg();
        w |= self.fg_intense.to_fg();
        w |= self.bg_color.to_bg();
        w |= self.bg_intense.to_bg();
        w as WORD
    }

    fn from_word(word: WORD) -> TextAttributes {
        let attr = word as DWORD;
        TextAttributes {
            fg_color: Color::from_fg(attr),
            fg_intense: Intense::from_fg(attr),
            bg_color: Color::from_bg(attr),
            bg_intense: Intense::from_bg(attr),
        }
    }
}

/// Whether to use intense colors or not.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Intense {
    Yes,
    No,
}

impl Intense {
    fn to_bg(&self) -> DWORD {
        self.to_fg() << 4
    }

    fn from_bg(word: DWORD) -> Intense {
        Intense::from_fg(word >> 4)
    }

    fn to_fg(&self) -> DWORD {
        match *self {
            Intense::No => 0,
            Intense::Yes => FG_INTENSITY,
        }
    }

    fn from_fg(word: DWORD) -> Intense {
        if word & FG_INTENSITY > 0 {
            Intense::Yes
        } else {
            Intense::No
        }
    }
}

/// The set of available colors for use with a Windows console.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Color {
    Black,
    Blue,
    Green,
    Red,
    Cyan,
    Magenta,
    Yellow,
    White,
}

impl Color {
    fn to_bg(&self) -> DWORD {
        self.to_fg() << 4
    }

    fn from_bg(word: DWORD) -> Color {
        Color::from_fg(word >> 4)
    }

    fn to_fg(&self) -> DWORD {
        match *self {
            Color::Black => 0,
            Color::Blue => FG_BLUE,
            Color::Green => FG_GREEN,
            Color::Red => FG_RED,
            Color::Cyan => FG_CYAN,
            Color::Magenta => FG_MAGENTA,
            Color::Yellow => FG_YELLOW,
            Color::White => FG_WHITE,
        }
    }

    fn from_fg(word: DWORD) -> Color {
        match word & 0b111 {
            FG_BLUE => Color::Blue,
            FG_GREEN => Color::Green,
            FG_RED => Color::Red,
            FG_CYAN => Color::Cyan,
            FG_MAGENTA => Color::Magenta,
            FG_YELLOW => Color::Yellow,
            FG_WHITE => Color::White,
            _ => Color::Black,
        }
    }
}
<commit_msg>add docs to wincolor<commit_after>use std::io;
use std::mem;

use kernel32;
use winapi::{DWORD, HANDLE, WORD};
use winapi::winbase::STD_OUTPUT_HANDLE;
use winapi::wincon::{
    FOREGROUND_BLUE as FG_BLUE,
    FOREGROUND_GREEN as FG_GREEN,
    FOREGROUND_RED as FG_RED,
    FOREGROUND_INTENSITY as FG_INTENSITY,
};

const FG_CYAN: DWORD = FG_BLUE | FG_GREEN;
const FG_MAGENTA: DWORD = FG_BLUE | FG_RED;
const FG_YELLOW: DWORD = FG_GREEN | FG_RED;
const FG_WHITE: DWORD = FG_BLUE | FG_GREEN | FG_RED;

/// A Windows console.
///
/// This represents a very limited set of functionality available to a Windows
/// console. In particular, it can only change text attributes such as color
/// and intensity.
///
/// There is no way to "write" to this console. Simply write to
/// stdout or stderr instead, while interleaving instructions to the console
/// to change text attributes.
///
/// A common pitfall when using a console is to forget to flush writes to
/// stdout before setting new text attributes.
#[derive(Debug)]
pub struct Console {
    handle: HANDLE,
    start_attr: TextAttributes,
    cur_attr: TextAttributes,
}

unsafe impl Send for Console {}

impl Drop for Console {
    fn drop(&mut self) {
        unsafe { kernel32::CloseHandle(self.handle); }
    }
}

impl Console {
    /// Create a new Console to stdout.
    ///
    /// If there was a problem creating the console, then an error is returned.
    pub fn stdout() -> io::Result<Console> {
        let mut info = unsafe { mem::zeroed() };
        let (handle, res) = unsafe {
            let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE);
            (handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info))
        };
        if res == 0 {
            return Err(io::Error::last_os_error());
        }
        let attr = TextAttributes::from_word(info.wAttributes);
        Ok(Console {
            handle: handle,
            start_attr: attr,
            cur_attr: attr,
        })
    }

    /// Applies the current text attributes.
    fn set(&mut self) -> io::Result<()> {
        let attr = self.cur_attr.to_word();
        let res = unsafe {
            kernel32::SetConsoleTextAttribute(self.handle, attr)
        };
        if res == 0 {
            return Err(io::Error::last_os_error());
        }
        Ok(())
    }

    /// Apply the given intensity and color attributes to the console
    /// foreground.
    ///
    /// If there was a problem setting attributes on the console, then an error
    /// is returned.
    pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
        self.cur_attr.fg_color = color;
        self.cur_attr.fg_intense = intense;
        self.set()
    }

    /// Apply the given intensity and color attributes to the console
    /// background.
    ///
    /// If there was a problem setting attributes on the console, then an error
    /// is returned.
    pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> {
        self.cur_attr.bg_color = color;
        self.cur_attr.bg_intense = intense;
        self.set()
    }

    /// Reset the console text attributes to their original settings.
    ///
    /// The original settings correspond to the text attributes on the console
    /// when this `Console` value was created.
    ///
    /// If there was a problem setting attributes on the console, then an error
    /// is returned.
    pub fn reset(&mut self) -> io::Result<()> {
        self.cur_attr = self.start_attr;
        self.set()
    }
}

/// A representation of text attributes for the Windows console.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct TextAttributes {
    fg_color: Color,
    fg_intense: Intense,
    bg_color: Color,
    bg_intense: Intense,
}

impl TextAttributes {
    fn to_word(&self) -> WORD {
        let mut w = 0;
        w |= self.fg_color.to_fg();
        w |= self.fg_intense.to_fg();
        w |= self.bg_color.to_bg();
        w |= self.bg_intense.to_bg();
        w as WORD
    }

    fn from_word(word: WORD) -> TextAttributes {
        let attr = word as DWORD;
        TextAttributes {
            fg_color: Color::from_fg(attr),
            fg_intense: Intense::from_fg(attr),
            bg_color: Color::from_bg(attr),
            bg_intense: Intense::from_bg(attr),
        }
    }
}

/// Whether to use intense colors or not.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Intense {
    Yes,
    No,
}

impl Intense {
    fn to_bg(&self) -> DWORD {
        self.to_fg() << 4
    }

    fn from_bg(word: DWORD) -> Intense {
        Intense::from_fg(word >> 4)
    }

    fn to_fg(&self) -> DWORD {
        match *self {
            Intense::No => 0,
            Intense::Yes => FG_INTENSITY,
        }
    }

    fn from_fg(word: DWORD) -> Intense {
        if word & FG_INTENSITY > 0 {
            Intense::Yes
        } else {
            Intense::No
        }
    }
}

/// The set of available colors for use with a Windows console.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Color {
    Black,
    Blue,
    Green,
    Red,
    Cyan,
    Magenta,
    Yellow,
    White,
}

impl Color {
    fn to_bg(&self) -> DWORD {
        self.to_fg() << 4
    }

    fn from_bg(word: DWORD) -> Color {
        Color::from_fg(word >> 4)
    }

    fn to_fg(&self) -> DWORD {
        match *self {
            Color::Black => 0,
            Color::Blue => FG_BLUE,
            Color::Green => FG_GREEN,
            Color::Red => FG_RED,
            Color::Cyan => FG_CYAN,
            Color::Magenta => FG_MAGENTA,
            Color::Yellow => FG_YELLOW,
            Color::White => FG_WHITE,
        }
    }

    fn from_fg(word: DWORD) -> Color {
        match word & 0b111 {
            FG_BLUE => Color::Blue,
            FG_GREEN => Color::Green,
            FG_RED => Color::Red,
            FG_CYAN => Color::Cyan,
            FG_MAGENTA => Color::Magenta,
            FG_YELLOW => Color::Yellow,
            FG_WHITE => Color::White,
            _ => Color::Black,
        }
    }
}
<|endoftext|>


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

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.
#![feature(libc, rustc_private, thread_local)]
#![cfg_attr(not(test), feature(path))]

extern crate compositing;
extern crate devtools;
extern crate devtools_traits;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;
extern crate webdriver_server;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};

use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;

use script::dom::bindings::codegen::RegisterBindings;

use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder};
use net::storage_task::StorageTaskFactory;
use net::resource_task::new_resource_task;
use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask;

use gfx::font_cache_task::FontCacheTask;
use profile::mem;
use profile::time;
use util::opts;
use util::taskpool::TaskPool;

use std::rc::Rc;
use std::sync::mpsc::Sender;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser  {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);

        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();

        // Use this thread pool to load-balance simple tasks, such as
        // image decoding.
        let shared_task_pool = TaskPool::new(8);

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        if let Some(port) = opts.webdriver_port {
            webdriver_server::start_server(port);
        }

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      devtools_chan,
                                                      mem_profiler_chan.clone(),
                                                      shared_task_pool);

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan.clone(),
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}
fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy+Send>,
                        time_profiler_chan: time::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        mem_profiler_chan: mem::ProfilerChan,
                        shared_task_pool: TaskPool) -> ConstellationChan {
    use std::env;

    // Create a Servo instance.
    let resource_task = new_resource_task(opts.user_agent.clone());

    // If we are emitting an output file, then we need to block on
    // image load or we risk emitting an output file missing the
    // image.
    let image_cache_task: ImageCacheTask = if opts.output_file.is_some() {
        ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool,
                                        time_profiler_chan.clone(), LoadPlaceholder::Preload)
    } else {
        ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool,
                                   time_profiler_chan.clone(), LoadPlaceholder::Preload)
    };

    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
    script::script_task::ScriptTask>::start(
        compositor_proxy.clone_compositor_proxy(),
        resource_task,
        image_cache_task,
        font_cache_task,
        time_profiler_chan.clone(),
        mem_profiler_chan.clone(),
        devtools_chan,
        storage_task);

    // Send the URL command to the constellation.
    let cwd = env::current_dir().unwrap();
    let url = match url::Url::parse(&opts.url) {
        Ok(url) => url,
        Err(url::ParseError::RelativeUrlWithoutBase)
        => url::Url::from_file_path(&*cwd.join(&opts.url)).unwrap(),
        Err(_) => panic!("URL parsing failed"),
    };

    {
        let ConstellationChan(ref chan) = constellation_chan;
        chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
    }

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

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.
#![feature(libc, thread_local)]
#![cfg_attr(not(test), feature(path))]

extern crate compositing;
extern crate devtools;
extern crate devtools_traits;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;
extern crate webdriver_server;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};

use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;

use script::dom::bindings::codegen::RegisterBindings;

use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder};
use net::storage_task::StorageTaskFactory;
use net::resource_task::new_resource_task;
use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask;

use gfx::font_cache_task::FontCacheTask;
use profile::mem;
use profile::time;
use util::opts;
use util::taskpool::TaskPool;

use std::rc::Rc;
use std::sync::mpsc::Sender;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser  {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);

        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();

        // Use this thread pool to load-balance simple tasks, such as
        // image decoding.
        let shared_task_pool = TaskPool::new(8);

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        if let Some(port) = opts.webdriver_port {
            webdriver_server::start_server(port);
        }

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      devtools_chan,
                                                      mem_profiler_chan.clone(),
                                                      shared_task_pool);

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan.clone(),
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}
fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy+Send>,
                        time_profiler_chan: time::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        mem_profiler_chan: mem::ProfilerChan,
                        shared_task_pool: TaskPool) -> ConstellationChan {
    use std::env;

    // Create a Servo instance.
    let resource_task = new_resource_task(opts.user_agent.clone());

    // If we are emitting an output file, then we need to block on
    // image load or we risk emitting an output file missing the
    // image.
    let image_cache_task: ImageCacheTask = if opts.output_file.is_some() {
        ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool,
                                        time_profiler_chan.clone(), LoadPlaceholder::Preload)
    } else {
        ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool,
                                   time_profiler_chan.clone(), LoadPlaceholder::Preload)
    };

    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
    script::script_task::ScriptTask>::start(
        compositor_proxy.clone_compositor_proxy(),
        resource_task,
        image_cache_task,
        font_cache_task,
        time_profiler_chan.clone(),
        mem_profiler_chan.clone(),
        devtools_chan,
        storage_task);

    // Send the URL command to the constellation.
    let cwd = env::current_dir().unwrap();
    let url = match url::Url::parse(&opts.url) {
        Ok(url) => url,
        Err(url::ParseError::RelativeUrlWithoutBase)
        => url::Url::from_file_path(&*cwd.join(&opts.url)).unwrap(),
        Err(_) => panic!("URL parsing failed"),
    };

    {
        let ConstellationChan(ref chan) = constellation_chan;
        chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
    }

    constellation_chan
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

struct WorldMap{
    map: HashSet<(i8, i8)>
}

impl WorldMap{

    fn empty() -> WorldMap {
        return WorldMap::new( HashSet::new() );
    }

    fn new(new_map: HashSet<(i8,i8)>) -> WorldMap {
        return WorldMap { map: new_map };
    }

    fn mark_cell_as_alive(&self, cell_coordinates: (i8, i8)) -> WorldMap {
        let mut new_map = self.map.clone();
        new_map.insert(cell_coordinates);
        let new_world = WorldMap::new(new_map);
        return new_world;
    }

    fn is_cell_alive(&self, cell_coordinates: (i8,i8)) -> bool {
        return self.map.contains(&cell_coordinates);
    }

}

#[test]
fn is_cell_alive_should_return_true_for_alive_cell(){
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_as_alive(coords);
    let is_alive = new_world.is_cell_alive(coords);
    assert_eq!(true, is_alive);
}

#[test]
fn is_cell_alive_should_return_false_for_dead_cell(){
    let coords = (0,0);
    let world = WorldMap::empty();
    let is_alive = world.is_cell_alive(coords);
    assert_eq!(false, is_alive);
}
<commit_msg>Neighbours counting - basic empty example added.<commit_after>use std::collections::HashSet;

struct WorldMap{
    map: HashSet<(i8, i8)>
}

impl WorldMap{

    fn empty() -> WorldMap {
        return WorldMap::new( HashSet::new() );
    }

    fn new(new_map: HashSet<(i8,i8)>) -> WorldMap {
        return WorldMap { map: new_map };
    }

    fn mark_cell_as_alive(&self, cell_coordinates: (i8, i8)) -> WorldMap {
        let mut new_map = self.map.clone();
        new_map.insert(cell_coordinates);
        let new_world = WorldMap::new(new_map);
        return new_world;
    }

    fn is_cell_alive(&self, cell_coordinates: (i8,i8)) -> bool {
        return self.map.contains(&cell_coordinates);
    }

    fn count_alive_neighbours(&self, cell_coordinates: (i8, i8)) -> usize {
        let mut neighbour_coordinates = HashSet::new();
        let (x, y) = cell_coordinates;
        neighbour_coordinates.insert((x-1, y-1));
        neighbour_coordinates.insert((x-1, y));
        neighbour_coordinates.insert((x-1, y+1));
        neighbour_coordinates.insert((x, y-1));
        neighbour_coordinates.insert((x, y+1));
        neighbour_coordinates.insert((x+1, y-1));
        neighbour_coordinates.insert((x+1, y));
        neighbour_coordinates.insert((x+1, y+1));
        let neighbours_alive = self.map.intersection(&neighbour_coordinates).collect::<Vec<&(i8,i8)>>();
        return neighbours_alive.len();
    }
}

#[test]
fn the_only_alive_cell_should_have_no_alive_neighbours() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_as_alive(coords);
    let alive_neighbours_count = new_world.count_alive_neighbours(coords);
    assert_eq!(0, alive_neighbours_count);
}

#[test]
fn is_cell_alive_should_return_true_for_alive_cell() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_as_alive(coords);
    let is_alive = new_world.is_cell_alive(coords);
    assert_eq!(true, is_alive);
}

#[test]
fn is_cell_alive_should_return_false_for_dead_cell() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let is_alive = world.is_cell_alive(coords);
    assert_eq!(false, is_alive);
}
<|endoftext|>


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

#![feature(box_syntax)]
#![feature(custom_attribute)]
#![feature(custom_derive)]
#![feature(plugin)]
#![feature(slice_patterns)]
#![feature(step_by)]
#![feature(vec_push_all)]
#![feature(custom_attribute)]
#![plugin(serde_macros, plugins)]
#![plugin(regex_macros)]

#[macro_use]
extern crate log;
extern crate euclid;
extern crate hyper;
extern crate ipc_channel;
extern crate image as piston_image;
extern crate msg;
extern crate regex;
extern crate serde;
extern crate stb_image;
extern crate url;
extern crate util;

use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper::mime::{Attr, Mime};
use hyper::status::StatusCode;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use msg::constellation_msg::{PipelineId};
use regex::Regex;
use serde::{Deserializer, Serializer};
use std::thread;
use url::Url;
use util::mem::HeapSizeOf;

pub mod hosts;
pub mod image_cache_task;
pub mod net_error_list;
pub mod storage_task;

pub static IPV4_REGEX: Regex = regex!(
    r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
pub static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$");

/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
#[derive(Clone, PartialEq, Copy)]
pub enum ResponseType {
    Basic,
    CORS,
    Default,
    Error,
    Opaque
}

/// [Response termination reason](https://fetch.spec.whatwg.org/#concept-response-termination-reason)
#[derive(Clone, Copy)]
pub enum TerminationReason {
    EndUserAbort,
    Fatal,
    Timeout
}

/// The response body can still be pushed to after fetch
/// This provides a way to store unfinished response bodies
#[derive(Clone)]
pub enum ResponseBody {
    Empty, // XXXManishearth is this necessary, or is Done(vec![]) enough?
    Receiving(Vec<u8>),
    Done(Vec<u8>),
}

pub enum ResponseMsg {
    Chunk(Vec<u8>),
    Finished,
    Errored
}

/// A [Response](https://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec
#[derive(Clone)]
pub struct Response {
    pub response_type: ResponseType,
    pub termination_reason: Option<TerminationReason>,
    pub url: Option<Url>,
    /// `None` can be considered a StatusCode of `0`.
    pub status: Option<StatusCode>,
    pub headers: Headers,
    pub body: ResponseBody,
    /// [Internal response](https://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response
    /// is a filtered response
    pub internal_response: Option<Box<Response>>,
}

impl Response {
    pub fn network_error() -> Response {
        Response {
            response_type: ResponseType::Error,
            termination_reason: None,
            url: None,
            status: None,
            headers: Headers::new(),
            body: ResponseBody::Empty,
            internal_response: None
        }
    }

    pub fn is_network_error(&self) -> bool {
        match self.response_type {
            ResponseType::Error => true,
            _ => false
        }
    }
}

/// Image handling.
///
/// It may be surprising that this goes in the network crate as opposed to the graphics crate.
/// However, image handling is generally very integrated with the network stack (especially where
/// caching is involved) and as a result it must live in here.
pub mod image {
    pub mod base;
}

#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct LoadData {
    pub url: Url,
    pub method: Method,
    #[ignore_heap_size_of = "Defined in hyper"]
    /// Headers that will apply to the initial request only
    pub headers: Headers,
    #[ignore_heap_size_of = "Defined in hyper"]
    /// Headers that will apply to the initial request and any redirects
    pub preserved_headers: Headers,
    pub data: Option<Vec<u8>>,
    pub cors: Option<ResourceCORSData>,
    pub pipeline_id: Option<PipelineId>,
}

impl LoadData {
    pub fn new(url: Url, id: Option<PipelineId>) -> LoadData {
        LoadData {
            url: url,
            method: Method::Get,
            headers: Headers::new(),
            preserved_headers: Headers::new(),
            data: None,
            cors: None,
            pipeline_id: id,
        }
    }
}

/// Interface for observing the final response for an asynchronous fetch operation.
pub trait AsyncFetchListener {
    fn response_available(&self, response: Response);
}

/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
pub trait AsyncResponseListener {
    /// The response headers for a request have been received.
    fn headers_available(&mut self, metadata: Metadata);
    /// A portion of the response body has been received. This data is unavailable after
    /// this method returned, and must be stored accordingly.
    fn data_available(&mut self, payload: Vec<u8>);
    /// The response is complete. If the provided status is an Err value, there is no guarantee
    /// that the response body was completely read.
    fn response_complete(&mut self, status: Result<(), String>);
}

/// Data for passing between threads/processes to indicate a particular action to
/// take on a provided network listener.
#[derive(Deserialize, Serialize)]
pub enum ResponseAction {
    /// Invoke headers_available
    HeadersAvailable(Metadata),
    /// Invoke data_available
    DataAvailable(Vec<u8>),
    /// Invoke response_complete
    ResponseComplete(Result<(), String>)
}

impl ResponseAction {
    /// Execute the default action on a provided listener.
    pub fn process(self, listener: &mut AsyncResponseListener) {
        match self {
            ResponseAction::HeadersAvailable(m) => listener.headers_available(m),
            ResponseAction::DataAvailable(d) => listener.data_available(d),
            ResponseAction::ResponseComplete(r) => listener.response_complete(r),
        }
    }
}

/// A target for async networking events. Commonly used to dispatch a runnable event to another
/// thread storing the wrapped closure for later execution.
#[derive(Deserialize, Serialize)]
pub struct AsyncResponseTarget {
    pub sender: IpcSender<ResponseAction>,
}

impl AsyncResponseTarget {
    pub fn invoke_with_listener(&self, action: ResponseAction) {
        self.sender.send(action).unwrap()
    }
}

/// A wrapper for a network load that can either be channel or event-based.
#[derive(Deserialize, Serialize)]
pub enum LoadConsumer {
    Channel(IpcSender<LoadResponse>),
    Listener(AsyncResponseTarget),
}

/// Handle to a resource task
pub type ResourceTask = IpcSender<ControlMsg>;

#[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum IncludeSubdomains {
    Included,
    NotIncluded
}

#[derive(Deserialize, Serialize)]
pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(LoadData, LoadConsumer),
    /// Store a set of cookies for a given originating URL
    SetCookiesForUrl(Url, String, CookieSource),
    /// Retrieve the stored cookies for a given URL
    GetCookiesForUrl(Url, IpcSender<Option<String>>, CookieSource),
    Exit
}

/// Initialized but unsent request. Encapsulates everything necessary to instruct
/// the resource task to make a new request. The `load` method *must* be called before
/// destruction or the task will panic.
pub struct PendingAsyncLoad {
    resource_task: ResourceTask,
    url: Url,
    pipeline: Option<PipelineId>,
    guard: PendingLoadGuard,
}

struct PendingLoadGuard {
    loaded: bool,
}

impl PendingLoadGuard {
    fn neuter(&mut self) {
        self.loaded = true;
    }
}

impl Drop for PendingLoadGuard {
    fn drop(&mut self) {
        if !thread::panicking() {
            assert!(self.loaded)
        }
    }
}

impl PendingAsyncLoad {
    pub fn new(resource_task: ResourceTask, url: Url, pipeline: Option<PipelineId>)
               -> PendingAsyncLoad {
        PendingAsyncLoad {
            resource_task: resource_task,
            url: url,
            pipeline: pipeline,
            guard: PendingLoadGuard { loaded: false, },
        }
    }

    /// Initiate the network request associated with this pending load.
    pub fn load(mut self) -> IpcReceiver<LoadResponse> {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let (sender, receiver) = ipc::channel().unwrap();
        let consumer = LoadConsumer::Channel(sender);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
        receiver
    }

    /// Initiate the network request associated with this pending load, using the provided target.
    pub fn load_async(mut self, listener: AsyncResponseTarget) {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let consumer = LoadConsumer::Listener(listener);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
    }
}

/// Message sent in response to `Load`.  Contains metadata, and a port
/// for receiving the data.
///
/// Even if loading fails immediately, we send one of these and the
/// progress_port will provide the error.
#[derive(Serialize, Deserialize)]
pub struct LoadResponse {
    /// Metadata, such as from HTTP headers.
    pub metadata: Metadata,
    /// Port for reading data.
    pub progress_port: IpcReceiver<ProgressMsg>,
}

#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct ResourceCORSData {
    /// CORS Preflight flag
    pub preflight: bool,
    /// Origin of CORS Request
    pub origin: Url,
}

/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct Metadata {
    /// Final URL after redirects.
    pub final_url: Url,

    /// MIME type / subtype.
    pub content_type: Option<(ContentType)>,

    /// Character set.
    pub charset: Option<String>,

    #[ignore_heap_size_of = "Defined in hyper"]
    /// Headers
    pub headers: Option<Headers>,

    /// HTTP Status
    pub status: Option<RawStatus>,
}

impl Metadata {
    /// Metadata with defaults for everything optional.
    pub fn default(url: Url) -> Self {
        Metadata {
            final_url:    url,
            content_type: None,
            charset:      None,
            headers: None,
            // https://fetch.spec.whatwg.org/#concept-response-status-message
            status: Some(RawStatus(200, "OK".into())),
        }
    }

    /// Extract the parts of a Mime that we care about.
    pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
        match content_type {
            None => (),
            Some(mime) => {
                self.content_type = Some(ContentType(mime.clone()));
                let &Mime(_, _, ref parameters) = mime;
                for &(ref k, ref v) in parameters {
                    if &Attr::Charset == k {
                        self.charset = Some(v.to_string());
                    }
                }
            }
        }
    }
}

/// The creator of a given cookie
#[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum CookieSource {
    /// An HTTP API
    HTTP,
    /// A non-HTTP API
    NonHTTP,
}

/// Messages sent in response to a `Load` message
#[derive(PartialEq, Debug, Deserialize, Serialize)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(Vec<u8>),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), String>)
}

/// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url, pipeline_id: Option<PipelineId>)
        -> Result<(Metadata, Vec<u8>), String> {
    let (start_chan, start_port) = ipc::channel().unwrap();
    resource_task.send(ControlMsg::Load(LoadData::new(url, pipeline_id),
                       LoadConsumer::Channel(start_chan))).unwrap();
    let response = start_port.recv().unwrap();

    let mut buf = vec!();
    loop {
        match response.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => buf.push_all(&data),
            ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)),
            ProgressMsg::Done(Err(e)) => return Err(e)
        }
    }
}

/// Load a URL asynchronously and iterate over chunks of bytes from the response.
pub fn load_bytes_iter(pending: PendingAsyncLoad) -> (Metadata, ProgressMsgPortIterator) {
    let input_port = pending.load();
    let response = input_port.recv().unwrap();
    let iter = ProgressMsgPortIterator {
        progress_port: response.progress_port
    };
    (response.metadata, iter)
}

/// Iterator that reads chunks of bytes from a ProgressMsg port
pub struct ProgressMsgPortIterator {
    progress_port: IpcReceiver<ProgressMsg>,
}

impl Iterator for ProgressMsgPortIterator {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Vec<u8>> {
        match self.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => Some(data),
            ProgressMsg::Done(Ok(()))  => None,
            ProgressMsg::Done(Err(e))  => {
                error!("error receiving bytes: {}", e);
                None
            }
        }
    }
}
<commit_msg>Auto merge of #8401 - eefriedman:net-dead-sync-load, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(box_syntax)]
#![feature(custom_attribute)]
#![feature(custom_derive)]
#![feature(plugin)]
#![feature(slice_patterns)]
#![feature(step_by)]
#![feature(vec_push_all)]
#![feature(custom_attribute)]
#![plugin(serde_macros, plugins)]
#![plugin(regex_macros)]

#[macro_use]
extern crate log;
extern crate euclid;
extern crate hyper;
extern crate ipc_channel;
extern crate image as piston_image;
extern crate msg;
extern crate regex;
extern crate serde;
extern crate stb_image;
extern crate url;
extern crate util;

use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper::mime::{Attr, Mime};
use hyper::status::StatusCode;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use msg::constellation_msg::{PipelineId};
use regex::Regex;
use serde::{Deserializer, Serializer};
use std::thread;
use url::Url;
use util::mem::HeapSizeOf;

pub mod hosts;
pub mod image_cache_task;
pub mod net_error_list;
pub mod storage_task;

pub static IPV4_REGEX: Regex = regex!(
    r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
pub static IPV6_REGEX: Regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$");

/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
#[derive(Clone, PartialEq, Copy)]
pub enum ResponseType {
    Basic,
    CORS,
    Default,
    Error,
    Opaque
}

/// [Response termination reason](https://fetch.spec.whatwg.org/#concept-response-termination-reason)
#[derive(Clone, Copy)]
pub enum TerminationReason {
    EndUserAbort,
    Fatal,
    Timeout
}

/// The response body can still be pushed to after fetch
/// This provides a way to store unfinished response bodies
#[derive(Clone)]
pub enum ResponseBody {
    Empty, // XXXManishearth is this necessary, or is Done(vec![]) enough?
    Receiving(Vec<u8>),
    Done(Vec<u8>),
}

pub enum ResponseMsg {
    Chunk(Vec<u8>),
    Finished,
    Errored
}

/// A [Response](https://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec
#[derive(Clone)]
pub struct Response {
    pub response_type: ResponseType,
    pub termination_reason: Option<TerminationReason>,
    pub url: Option<Url>,
    /// `None` can be considered a StatusCode of `0`.
    pub status: Option<StatusCode>,
    pub headers: Headers,
    pub body: ResponseBody,
    /// [Internal response](https://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response
    /// is a filtered response
    pub internal_response: Option<Box<Response>>,
}

impl Response {
    pub fn network_error() -> Response {
        Response {
            response_type: ResponseType::Error,
            termination_reason: None,
            url: None,
            status: None,
            headers: Headers::new(),
            body: ResponseBody::Empty,
            internal_response: None
        }
    }

    pub fn is_network_error(&self) -> bool {
        match self.response_type {
            ResponseType::Error => true,
            _ => false
        }
    }
}

/// Image handling.
///
/// It may be surprising that this goes in the network crate as opposed to the graphics crate.
/// However, image handling is generally very integrated with the network stack (especially where
/// caching is involved) and as a result it must live in here.
pub mod image {
    pub mod base;
}

#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct LoadData {
    pub url: Url,
    pub method: Method,
    #[ignore_heap_size_of = "Defined in hyper"]
    /// Headers that will apply to the initial request only
    pub headers: Headers,
    #[ignore_heap_size_of = "Defined in hyper"]
    /// Headers that will apply to the initial request and any redirects
    pub preserved_headers: Headers,
    pub data: Option<Vec<u8>>,
    pub cors: Option<ResourceCORSData>,
    pub pipeline_id: Option<PipelineId>,
}

impl LoadData {
    pub fn new(url: Url, id: Option<PipelineId>) -> LoadData {
        LoadData {
            url: url,
            method: Method::Get,
            headers: Headers::new(),
            preserved_headers: Headers::new(),
            data: None,
            cors: None,
            pipeline_id: id,
        }
    }
}

/// Interface for observing the final response for an asynchronous fetch operation.
pub trait AsyncFetchListener {
    fn response_available(&self, response: Response);
}

/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
pub trait AsyncResponseListener {
    /// The response headers for a request have been received.
    fn headers_available(&mut self, metadata: Metadata);
    /// A portion of the response body has been received. This data is unavailable after
    /// this method returned, and must be stored accordingly.
    fn data_available(&mut self, payload: Vec<u8>);
    /// The response is complete. If the provided status is an Err value, there is no guarantee
    /// that the response body was completely read.
    fn response_complete(&mut self, status: Result<(), String>);
}

/// Data for passing between threads/processes to indicate a particular action to
/// take on a provided network listener.
#[derive(Deserialize, Serialize)]
pub enum ResponseAction {
    /// Invoke headers_available
    HeadersAvailable(Metadata),
    /// Invoke data_available
    DataAvailable(Vec<u8>),
    /// Invoke response_complete
    ResponseComplete(Result<(), String>)
}

impl ResponseAction {
    /// Execute the default action on a provided listener.
    pub fn process(self, listener: &mut AsyncResponseListener) {
        match self {
            ResponseAction::HeadersAvailable(m) => listener.headers_available(m),
            ResponseAction::DataAvailable(d) => listener.data_available(d),
            ResponseAction::ResponseComplete(r) => listener.response_complete(r),
        }
    }
}

/// A target for async networking events. Commonly used to dispatch a runnable event to another
/// thread storing the wrapped closure for later execution.
#[derive(Deserialize, Serialize)]
pub struct AsyncResponseTarget {
    pub sender: IpcSender<ResponseAction>,
}

impl AsyncResponseTarget {
    pub fn invoke_with_listener(&self, action: ResponseAction) {
        self.sender.send(action).unwrap()
    }
}

/// A wrapper for a network load that can either be channel or event-based.
#[derive(Deserialize, Serialize)]
pub enum LoadConsumer {
    Channel(IpcSender<LoadResponse>),
    Listener(AsyncResponseTarget),
}

/// Handle to a resource task
pub type ResourceTask = IpcSender<ControlMsg>;

#[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum IncludeSubdomains {
    Included,
    NotIncluded
}

#[derive(Deserialize, Serialize)]
pub enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(LoadData, LoadConsumer),
    /// Store a set of cookies for a given originating URL
    SetCookiesForUrl(Url, String, CookieSource),
    /// Retrieve the stored cookies for a given URL
    GetCookiesForUrl(Url, IpcSender<Option<String>>, CookieSource),
    Exit
}

/// Initialized but unsent request. Encapsulates everything necessary to instruct
/// the resource task to make a new request. The `load` method *must* be called before
/// destruction or the task will panic.
pub struct PendingAsyncLoad {
    resource_task: ResourceTask,
    url: Url,
    pipeline: Option<PipelineId>,
    guard: PendingLoadGuard,
}

struct PendingLoadGuard {
    loaded: bool,
}

impl PendingLoadGuard {
    fn neuter(&mut self) {
        self.loaded = true;
    }
}

impl Drop for PendingLoadGuard {
    fn drop(&mut self) {
        if !thread::panicking() {
            assert!(self.loaded)
        }
    }
}

impl PendingAsyncLoad {
    pub fn new(resource_task: ResourceTask, url: Url, pipeline: Option<PipelineId>)
               -> PendingAsyncLoad {
        PendingAsyncLoad {
            resource_task: resource_task,
            url: url,
            pipeline: pipeline,
            guard: PendingLoadGuard { loaded: false, },
        }
    }

    /// Initiate the network request associated with this pending load, using the provided target.
    pub fn load_async(mut self, listener: AsyncResponseTarget) {
        self.guard.neuter();
        let load_data = LoadData::new(self.url, self.pipeline);
        let consumer = LoadConsumer::Listener(listener);
        self.resource_task.send(ControlMsg::Load(load_data, consumer)).unwrap();
    }
}

/// Message sent in response to `Load`.  Contains metadata, and a port
/// for receiving the data.
///
/// Even if loading fails immediately, we send one of these and the
/// progress_port will provide the error.
#[derive(Serialize, Deserialize)]
pub struct LoadResponse {
    /// Metadata, such as from HTTP headers.
    pub metadata: Metadata,
    /// Port for reading data.
    pub progress_port: IpcReceiver<ProgressMsg>,
}

#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct ResourceCORSData {
    /// CORS Preflight flag
    pub preflight: bool,
    /// Origin of CORS Request
    pub origin: Url,
}

/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
pub struct Metadata {
    /// Final URL after redirects.
    pub final_url: Url,

    /// MIME type / subtype.
    pub content_type: Option<(ContentType)>,

    /// Character set.
    pub charset: Option<String>,

    #[ignore_heap_size_of = "Defined in hyper"]
    /// Headers
    pub headers: Option<Headers>,

    /// HTTP Status
    pub status: Option<RawStatus>,
}

impl Metadata {
    /// Metadata with defaults for everything optional.
    pub fn default(url: Url) -> Self {
        Metadata {
            final_url:    url,
            content_type: None,
            charset:      None,
            headers: None,
            // https://fetch.spec.whatwg.org/#concept-response-status-message
            status: Some(RawStatus(200, "OK".into())),
        }
    }

    /// Extract the parts of a Mime that we care about.
    pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
        match content_type {
            None => (),
            Some(mime) => {
                self.content_type = Some(ContentType(mime.clone()));
                let &Mime(_, _, ref parameters) = mime;
                for &(ref k, ref v) in parameters {
                    if &Attr::Charset == k {
                        self.charset = Some(v.to_string());
                    }
                }
            }
        }
    }
}

/// The creator of a given cookie
#[derive(PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum CookieSource {
    /// An HTTP API
    HTTP,
    /// A non-HTTP API
    NonHTTP,
}

/// Messages sent in response to a `Load` message
#[derive(PartialEq, Debug, Deserialize, Serialize)]
pub enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(Vec<u8>),
    /// Indicates loading is complete, either successfully or not
    Done(Result<(), String>)
}

/// Convenience function for synchronously loading a whole resource.
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url, pipeline_id: Option<PipelineId>)
        -> Result<(Metadata, Vec<u8>), String> {
    let (start_chan, start_port) = ipc::channel().unwrap();
    resource_task.send(ControlMsg::Load(LoadData::new(url, pipeline_id),
                       LoadConsumer::Channel(start_chan))).unwrap();
    let response = start_port.recv().unwrap();

    let mut buf = vec!();
    loop {
        match response.progress_port.recv().unwrap() {
            ProgressMsg::Payload(data) => buf.push_all(&data),
            ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)),
            ProgressMsg::Done(Err(e)) => return Err(e)
        }
    }
}
<|endoftext|>