<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/. */

//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::QuirksMode;
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{ServoStyleSheetInner, StyleSheetInfo, nsIDocument};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
use media_queries::{Device, MediaList};
use properties::ComputedValues;
use selector_parser::SnapshotMap;
use servo_arc::Arc;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
use stylist::Stylist;

/// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet);

impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        unsafe { MediaListKey::from_raw(mem::transmute(self.0)) }
    }
}

impl GeckoStyleSheet {
    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer.
    #[inline]
    pub unsafe fn new(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        bindings::Gecko_StyleSheet_AddRef(s);
        Self::from_addrefed(s)
    }

    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that
    /// already holds a strong reference.
    #[inline]
    pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        GeckoStyleSheet(s)
    }

    /// Get the raw `ServoStyleSheet` that we're wrapping.
    pub fn raw(&self) -> &ServoStyleSheet {
        unsafe { &*self.0 }
    }

    fn inner(&self) -> &ServoStyleSheetInner {
        unsafe {
            &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner)
        }
    }

    /// Gets the StylesheetContents for this stylesheet.
    pub fn contents(&self) -> &StylesheetContents {
        debug_assert!(!self.inner().mContents.mRawPtr.is_null());
        unsafe {
            let contents =
                (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
            &*contents
        }
    }
}

impl Drop for GeckoStyleSheet {
    fn drop(&mut self) {
        unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
    }
}

impl Clone for GeckoStyleSheet {
    fn clone(&self) -> Self {
        unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
        GeckoStyleSheet(self.0)
    }
}

impl StylesheetInDocument for GeckoStyleSheet {
    fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
        self.contents().origin
    }

    fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
        self.contents().quirks_mode
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        use gecko_bindings::structs::ServoMediaList;
        use std::mem;

        unsafe {
            let servo_media_list = self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
            if servo_media_list.is_null() {
                return None;
            }
            let raw_list = &*(*servo_media_list).mRawList.mRawPtr;
            let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
            Some(list.read_with(guard))
        }
    }

    // All the stylesheets Servo knows about are enabled, because that state is
    // handled externally by Gecko.
    fn enabled(&self) -> bool {
        true
    }

    #[inline]
    fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
        self.contents().rules(guard)
    }
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
pub struct PerDocumentStyleDataImpl {
    /// Rule processor.
    pub stylist: Stylist,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
/// and unexpected races while trying to mutate it.
pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);

impl PerDocumentStyleData {
    /// Create a dummy `PerDocumentStyleData`.
    pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
        let device = Device::new(pres_context);

        // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
        // right now not always honored, see bug 1405543...
        //
        // Should we just force XBL Stylists to be NoQuirks?
        let quirks_mode =
            unsafe { (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode };

        PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
            stylist: Stylist::new(device, quirks_mode.into()),
        }))
    }

    /// Get an immutable reference to this style data.
    pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
        self.0.borrow()
    }

    /// Get an mutable reference to this style data.
    pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
        self.0.borrow_mut()
    }
}

impl PerDocumentStyleDataImpl {
    /// Recreate the style data if the stylesheets have changed.
    pub fn flush_stylesheets<E>(
        &mut self,
        guard: &SharedRwLockReadGuard,
        document_element: Option<E>,
        snapshots: Option<&SnapshotMap>,
    ) -> bool
    where
        E: TElement,
    {
        self.stylist
            .flush(&StylesheetGuards::same(guard), document_element, snapshots)
    }

    /// Returns whether private browsing is enabled.
    fn is_private_browsing_enabled(&self) -> bool {
        let doc = self.stylist
            .device()
            .pres_context()
            .mDocument
            .raw::<nsIDocument>();
        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
    }

    /// Returns whether the document is being used as an image.
    fn is_being_used_as_an_image(&self) -> bool {
        let doc = self.stylist
            .device()
            .pres_context()
            .mDocument
            .raw::<nsIDocument>();

        unsafe { (*doc).mIsBeingUsedAsImage() }
    }

    /// Get the default computed values for this document.
    pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
        self.stylist.device().default_computed_values_arc()
    }

    /// Returns whether visited links are enabled.
    fn visited_links_enabled(&self) -> bool {
        unsafe { structs::StaticPrefs_sVarCache_layout_css_visited_links_enabled }
    }

    /// Returns whether visited styles are enabled.
    pub fn visited_styles_enabled(&self) -> bool {
        if !self.visited_links_enabled() {
            return false;
        }

        if self.is_private_browsing_enabled() {
            return false;
        }

        if self.is_being_used_as_an_image() {
            return false;
        }

        true
    }

    /// Measure heap usage.
    pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
        self.stylist.add_size_of(ops, sizes);
    }
}

unsafe impl HasFFI for PerDocumentStyleData {
    type FFIType = RawServoStyleSet;
}
unsafe impl HasSimpleFFI for PerDocumentStyleData {}
unsafe impl HasBoxFFI for PerDocumentStyleData {}
<commit_msg>style: Unify MediaList and ServoMediaList.<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/. */

//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::QuirksMode;
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{ServoStyleSheetInner, StyleSheetInfo, nsIDocument};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
use media_queries::{Device, MediaList};
use properties::ComputedValues;
use selector_parser::SnapshotMap;
use servo_arc::Arc;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
use stylist::Stylist;

/// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet);

impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        unsafe { MediaListKey::from_raw(mem::transmute(self.0)) }
    }
}

impl GeckoStyleSheet {
    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer.
    #[inline]
    pub unsafe fn new(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        bindings::Gecko_StyleSheet_AddRef(s);
        Self::from_addrefed(s)
    }

    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that
    /// already holds a strong reference.
    #[inline]
    pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        GeckoStyleSheet(s)
    }

    /// Get the raw `ServoStyleSheet` that we're wrapping.
    pub fn raw(&self) -> &ServoStyleSheet {
        unsafe { &*self.0 }
    }

    fn inner(&self) -> &ServoStyleSheetInner {
        unsafe {
            &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner)
        }
    }

    /// Gets the StylesheetContents for this stylesheet.
    pub fn contents(&self) -> &StylesheetContents {
        debug_assert!(!self.inner().mContents.mRawPtr.is_null());
        unsafe {
            let contents =
                (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
            &*contents
        }
    }
}

impl Drop for GeckoStyleSheet {
    fn drop(&mut self) {
        unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
    }
}

impl Clone for GeckoStyleSheet {
    fn clone(&self) -> Self {
        unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
        GeckoStyleSheet(self.0)
    }
}

impl StylesheetInDocument for GeckoStyleSheet {
    fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
        self.contents().origin
    }

    fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
        self.contents().quirks_mode
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        use gecko_bindings::structs::mozilla::dom::MediaList as DomMediaList;
        use std::mem;

        unsafe {
            let dom_media_list = self.raw()._base.mMedia.mRawPtr as *const DomMediaList;
            if dom_media_list.is_null() {
                return None;
            }
            let raw_list = &*(*dom_media_list).mRawList.mRawPtr;
            let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
            Some(list.read_with(guard))
        }
    }

    // All the stylesheets Servo knows about are enabled, because that state is
    // handled externally by Gecko.
    fn enabled(&self) -> bool {
        true
    }

    #[inline]
    fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
        self.contents().rules(guard)
    }
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
pub struct PerDocumentStyleDataImpl {
    /// Rule processor.
    pub stylist: Stylist,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
/// and unexpected races while trying to mutate it.
pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);

impl PerDocumentStyleData {
    /// Create a dummy `PerDocumentStyleData`.
    pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
        let device = Device::new(pres_context);

        // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
        // right now not always honored, see bug 1405543...
        //
        // Should we just force XBL Stylists to be NoQuirks?
        let quirks_mode =
            unsafe { (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode };

        PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
            stylist: Stylist::new(device, quirks_mode.into()),
        }))
    }

    /// Get an immutable reference to this style data.
    pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
        self.0.borrow()
    }

    /// Get an mutable reference to this style data.
    pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
        self.0.borrow_mut()
    }
}

impl PerDocumentStyleDataImpl {
    /// Recreate the style data if the stylesheets have changed.
    pub fn flush_stylesheets<E>(
        &mut self,
        guard: &SharedRwLockReadGuard,
        document_element: Option<E>,
        snapshots: Option<&SnapshotMap>,
    ) -> bool
    where
        E: TElement,
    {
        self.stylist
            .flush(&StylesheetGuards::same(guard), document_element, snapshots)
    }

    /// Returns whether private browsing is enabled.
    fn is_private_browsing_enabled(&self) -> bool {
        let doc = self.stylist
            .device()
            .pres_context()
            .mDocument
            .raw::<nsIDocument>();
        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
    }

    /// Returns whether the document is being used as an image.
    fn is_being_used_as_an_image(&self) -> bool {
        let doc = self.stylist
            .device()
            .pres_context()
            .mDocument
            .raw::<nsIDocument>();

        unsafe { (*doc).mIsBeingUsedAsImage() }
    }

    /// Get the default computed values for this document.
    pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
        self.stylist.device().default_computed_values_arc()
    }

    /// Returns whether visited links are enabled.
    fn visited_links_enabled(&self) -> bool {
        unsafe { structs::StaticPrefs_sVarCache_layout_css_visited_links_enabled }
    }

    /// Returns whether visited styles are enabled.
    pub fn visited_styles_enabled(&self) -> bool {
        if !self.visited_links_enabled() {
            return false;
        }

        if self.is_private_browsing_enabled() {
            return false;
        }

        if self.is_being_used_as_an_image() {
            return false;
        }

        true
    }

    /// Measure heap usage.
    pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
        self.stylist.add_size_of(ops, sizes);
    }
}

unsafe impl HasFFI for PerDocumentStyleData {
    type FFIType = RawServoStyleSet;
}
unsafe impl HasSimpleFFI for PerDocumentStyleData {}
unsafe impl HasBoxFFI for PerDocumentStyleData {}
<|endoftext|>


<commit_before>//! A simple example of hooking up stdin/stdout to a TCP stream.
//!
//! This example will connect to a server specified in the argument list and
//! then forward all data read on stdin to the server, printing out all data
//! received on stdout.
//!
//! Note that this is not currently optimized for performance, especially around
//! buffer management. Rather it's intended to show an example of working with a
//! client.

extern crate futures;
extern crate tokio_core;

use std::env;
use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::thread;

use futures::{Sink, Future, Stream};
use futures::sync::mpsc;
use tokio_core::reactor::Core;
use tokio_core::io::{Io, EasyBuf, Codec};
use tokio_core::net::TcpStream;

fn main() {
    // Parse what address we're going to connect to
    let addr = env::args().nth(1).unwrap_or_else(|| {
        panic!("this program requires at least one argument")
    });
    let addr = addr.parse::<SocketAddr>().unwrap();

    // Create the event loop and initiate the connection to the remote server
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let tcp = TcpStream::connect(&addr, &handle);

    // Right now Tokio doesn't support a handle to stdin running on the event
    // loop, so we farm out that work to a separate thread. This thread will
    // read data from stdin and then send it to the event loop over a standard
    // futures channel.
    let (stdin_tx, stdin_rx) = mpsc::channel(0);
    thread::spawn(|| read_stdin(stdin_tx));
    let stdin_rx = stdin_rx.map_err(|_| panic!()); // errors not possible on rx

    // After the TCP connection has been established, we set up our client to
    // start forwarding data.
    //
    // First we use the `Io::framed` method with a simple implementation of a
    // `Codec` (listed below) that just ships bytes around. We then split that
    // in two to work with the stream and sink separately.
    //
    // Half of the work we're going to do is to take all data we receive on
    // stdin (`stdin_rx`) and send that along the TCP stream (`sink`). The
    // second half is to take all the data we receive (`stream`) and then write
    // that to stdout. Currently we just write to stdout in a synchronous
    // fashion.
    //
    // Finally we set the client to terminate once either half of this work
    // finishes. If we don't have any more data to read or we won't receive any
    // more work from the remote then we can exit.
    let mut stdout = io::stdout();
    let client = tcp.and_then(|(sink, stream)| {
        let (sink, stream) = stream.framed(Bytes).split();
        let send_stdin = stdin_rx.forward(sink);
        let write_stdout = stream.for_each(move |buf| {
            stdout.write_all(buf.as_slice())
        });

        send_stdin.map(|_| ())
                  .select(write_stdout.map(|_| ()))
                  .then(|_| Ok(()))
    });

    // And now that we've got our client, we execute it in the event loop!
    core.run(client).unwrap();
}

/// A simple `Codec` implementation that just ships bytes around.
///
/// This type is used for "framing" a TCP stream of bytes but it's really just a
/// convenient method for us to work with streams/sinks for now. This'll just
/// take any data read and interpret it as a "frame" and conversely just shove
/// data into the output location without looking at it.
struct Bytes;

impl Codec for Bytes {
    type In = EasyBuf;
    type Out = Vec<u8>;

    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<EasyBuf>> {
        if buf.len() > 0 {
            let len = buf.len();
            Ok(Some(buf.drain_to(len)))
        } else {
            Ok(None)
        }
    }

    fn encode(&mut self, data: Vec<u8>, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(data);
        Ok(())
    }
}

// Our helper method which will read data from stdin and send it along the
// sender provided.
fn read_stdin(mut rx: mpsc::Sender<Vec<u8>>) {
    let mut stdin = io::stdin();
    loop {
        let mut buf = vec![0; 1024];
        let n = match stdin.read(&mut buf) {
            Err(_) |
            Ok(0) => break,
            Ok(n) => n,
        };
        buf.truncate(n);
        rx = rx.send(buf).wait().unwrap();
    }
}
<commit_msg>Fix connect example<commit_after>//! A simple example of hooking up stdin/stdout to a TCP stream.
//!
//! This example will connect to a server specified in the argument list and
//! then forward all data read on stdin to the server, printing out all data
//! received on stdout.
//!
//! Note that this is not currently optimized for performance, especially around
//! buffer management. Rather it's intended to show an example of working with a
//! client.

extern crate futures;
extern crate tokio_core;

use std::env;
use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::thread;

use futures::{Sink, Future, Stream};
use futures::sync::mpsc;
use tokio_core::reactor::Core;
use tokio_core::io::{Io, EasyBuf, Codec};
use tokio_core::net::TcpStream;

fn main() {
    // Parse what address we're going to connect to
    let addr = env::args().nth(1).unwrap_or_else(|| {
        panic!("this program requires at least one argument")
    });
    let addr = addr.parse::<SocketAddr>().unwrap();

    // Create the event loop and initiate the connection to the remote server
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let tcp = TcpStream::connect(&addr, &handle);

    // Right now Tokio doesn't support a handle to stdin running on the event
    // loop, so we farm out that work to a separate thread. This thread will
    // read data from stdin and then send it to the event loop over a standard
    // futures channel.
    let (stdin_tx, stdin_rx) = mpsc::channel(0);
    thread::spawn(|| read_stdin(stdin_tx));
    let stdin_rx = stdin_rx.map_err(|_| panic!()); // errors not possible on rx

    // After the TCP connection has been established, we set up our client to
    // start forwarding data.
    //
    // First we use the `Io::framed` method with a simple implementation of a
    // `Codec` (listed below) that just ships bytes around. We then split that
    // in two to work with the stream and sink separately.
    //
    // Half of the work we're going to do is to take all data we receive on
    // stdin (`stdin_rx`) and send that along the TCP stream (`sink`). The
    // second half is to take all the data we receive (`stream`) and then write
    // that to stdout. Currently we just write to stdout in a synchronous
    // fashion.
    //
    // Finally we set the client to terminate once either half of this work
    // finishes. If we don't have any more data to read or we won't receive any
    // more work from the remote then we can exit.
    let mut stdout = io::stdout();
    let client = tcp.and_then(|stream| {
        let (sink, stream) = stream.framed(Bytes).split();
        let send_stdin = stdin_rx.forward(sink);
        let write_stdout = stream.for_each(move |buf| {
            stdout.write_all(buf.as_slice())
        });

        send_stdin.map(|_| ())
                  .select(write_stdout.map(|_| ()))
                  .then(|_| Ok(()))
    });

    // And now that we've got our client, we execute it in the event loop!
    core.run(client).unwrap();
}

/// A simple `Codec` implementation that just ships bytes around.
///
/// This type is used for "framing" a TCP stream of bytes but it's really just a
/// convenient method for us to work with streams/sinks for now. This'll just
/// take any data read and interpret it as a "frame" and conversely just shove
/// data into the output location without looking at it.
struct Bytes;

impl Codec for Bytes {
    type In = EasyBuf;
    type Out = Vec<u8>;

    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<EasyBuf>> {
        if buf.len() > 0 {
            let len = buf.len();
            Ok(Some(buf.drain_to(len)))
        } else {
            Ok(None)
        }
    }

    fn encode(&mut self, data: Vec<u8>, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(data);
        Ok(())
    }
}

// Our helper method which will read data from stdin and send it along the
// sender provided.
fn read_stdin(mut rx: mpsc::Sender<Vec<u8>>) {
    let mut stdin = io::stdin();
    loop {
        let mut buf = vec![0; 1024];
        let n = match stdin.read(&mut buf) {
            Err(_) |
            Ok(0) => break,
            Ok(n) => n,
        };
        buf.truncate(n);
        rx = rx.send(buf).wait().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate core;
extern crate simple_serialize;

use std::default::Default;

use simple_serialize::{SimpleSerialize, SimpleSerializeVec};

fn main()
{
    println!("Encoding/decoding throughput for {{ uint, (uint, (uint, uint)), Vec<Vec<uint>, and Option<uint> }}.");
    println!("Caveat: compiler optimizations from whole program analysis; actual performance should be worse.");

    test_simpleser(1024, |i| i);
    test_simpleser(1024, |i| (i, (i+1, i-1)));
    test_simpleser(128, |_| vec![vec![0u, 1u], vec![1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]]);
    test_simpleser(1024, |i| if i % 2 == 0 { Some(i) } else { None });
}

// bounces some elements back and forth between columnar stacks, encoding/decoding ...
fn test_simpleser<T: SimpleSerialize<R>, R: SimpleSerializeVec<T>>(number: uint, element: |uint|:'static -> T)
{
    let start = time::precise_time_ns();

    let mut stack1: R = Default::default();
    let mut stack2: R = Default::default();

    let mut buffers = Vec::new();

    for index in range(0, number) { stack1.push(element(index)); }
    stack1.encode(&mut buffers);

    let mut bytes = 0u;     // number of bytes per iteration
    let mut total = 0u;     // total bytes processed

    for buffer in buffers.iter() { bytes += buffer.len(); }

    while time::precise_time_ns() - start < 1000000000
    {
        // decode, move, encode
        stack1.decode(&mut buffers);
        while let Some(record) = stack1.pop() { stack2.push(record); }
        stack2.encode(&mut buffers);

        // decode, move, encode
        stack2.decode(&mut buffers);
        while let Some(record) = stack2.pop() { stack1.push(record); }
        stack1.encode(&mut buffers);

        total += 2 * bytes;
    }

    println!("Encoding/decoding at {}GB/s", total as f64 / (time::precise_time_ns() - start) as f64)
}
<commit_msg>Also measure throughput in terms of serialized values / sec<commit_after>extern crate time;
extern crate core;
extern crate simple_serialize;

use std::default::Default;

use simple_serialize::{SimpleSerialize, SimpleSerializeVec};

fn main()
{
    println!("Encoding/decoding throughput for {{ uint, (uint, (uint, uint)), Vec<Vec<uint>, and Option<uint> }}.");
    println!("Caveat: compiler optimizations from whole program analysis; actual performance should be worse.");

    test_simpleser(1024, |i| i);
    test_simpleser(1024, |i| (i, (i+1, i-1)));
    test_simpleser(128, |_| vec![vec![0u, 1u], vec![1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]]);
    test_simpleser(1024, |i| if i % 2 == 0 { Some(i) } else { None });
}

// bounces some elements back and forth between columnar stacks, encoding/decoding ...
fn test_simpleser<T: SimpleSerialize<R>, R: SimpleSerializeVec<T>>(number: uint, element: |uint|:'static -> T)
{
    let start = time::precise_time_ns();

    let mut stack1: R = Default::default();
    let mut stack2: R = Default::default();

    let mut buffers = Vec::new();

    for index in range(0, number) { stack1.push(element(index)); }
    stack1.encode(&mut buffers);

    let mut bytes = 0u;     // number of bytes per iteration
    let mut total = 0u;     // total bytes processed

    for buffer in buffers.iter() { bytes += buffer.len(); }

    let mut count: uint = 0;
    while time::precise_time_ns() - start < 1000000000
    {
        // decode, move, encode
        stack1.decode(&mut buffers);
        while let Some(record) = stack1.pop() { stack2.push(record); }
        stack2.encode(&mut buffers);

        // decode, move, encode
        stack2.decode(&mut buffers);
        while let Some(record) = stack2.pop() { stack1.push(record); }
        stack1.encode(&mut buffers);

        total += 2 * bytes;
        count=count+1;
    }

    println!("Encoding/decoding at {}GB/s, {} values", total as f64 / (time::precise_time_ns() - start) as f64, 1000.0*1000.0*1000.0*
        count as f64 / (time::precise_time_ns() - start) as f64)
}
<|endoftext|>


<commit_before>use assembler::label_parsers::label_usage;
use assembler::register_parsers::register;
use assembler::Token;
use nom::digit;
use nom::types::CompleteStr;

/// Parser for all numbers, which have to be prefaced with `#` in our assembly language:
/// #100
named!(integer_operand<CompleteStr, Token>,
    ws!(
        do_parse!(
            tag!("#") >>
            sign: opt!(tag!("-")) >>
            reg_num: digit >>
            (
                Token::IntegerOperand{value: reg_num.parse::<i32>().unwrap()}
            )
        )
    )
);

named!(float_operand<CompleteStr, Token>,
    ws!(
        do_parse!(
            tag!("#") >>
            sign: opt!(tag!("-")) >>
            reg_num: digit >>
            tag!(".") >>
            post_num: digit >>
            (
                {

                    Token::FloatOperand{value: (reg_num.to_string() + "." + &post_num).parse::<f64>().unwrap()}
                }
            )
        )
    )
);

named!(irstring<CompleteStr, Token>,
    do_parse!(
        tag!("'") >>
        content: take_until!("'") >>
        tag!("'") >>
        (
            Token::IrString{ name: content.to_string() }
        )
    )
);

named!(pub operand<CompleteStr, Token>,
    alt!(
        integer_operand |
        float_operand |
        label_usage |
        register |
        irstring
    )
);

mod tests {
    #![allow(unused_imports)]

    use assembler::Token;
    use nom::types::CompleteStr;
    use super::{float_operand, integer_operand, irstring};

    #[test]
    fn test_parse_integer_operand() {
        let result = integer_operand(CompleteStr("#10"));
        assert_eq!(result.is_ok(), true);
        let (rest, value) = result.unwrap();
        assert_eq!(rest, CompleteStr(""));
        assert_eq!(value, Token::IntegerOperand { value: 10 });
        let result = integer_operand(CompleteStr("10"));
        assert_eq!(result.is_ok(), false);
    }

    #[test]
    fn test_parse_string_operand() {
        let result = irstring(CompleteStr("'This is a test'"));
        assert_eq!(result.is_ok(), true);
    }

    #[test]
    fn test_parse_float_operand() {
        let test = vec!["#100.3", "#-100.3", "#1.0", "#0.0"];
        for i in &test {
            assert_eq!(float_operand(CompleteStr(i)).is_ok(), true);
        }
    }
}
<commit_msg>Fixed some issues with operand parsers and ints<commit_after>use assembler::label_parsers::label_usage;
use assembler::register_parsers::register;
use assembler::Token;
use nom::digit;
use nom::types::CompleteStr;

/// Parser for all numbers, which have to be prefaced with `#` in our assembly language:
/// #100
named!(integer_operand<CompleteStr, Token>,
    ws!(
        do_parse!(
            tag!("#") >>
            sign: opt!(tag!("-")) >>
            reg_num: digit >>
            (
                {
                    let mut tmp = String::from("");
                    if sign.is_some() {
                        tmp.push_str("-");
                    }
                    tmp.push_str(&reg_num.to_string());
                    Token::IntegerOperand{value: reg_num.parse::<i32>().unwrap()}
                }
            )
        )
    )
);

named!(float_operand<CompleteStr, Token>,
    ws!(
        do_parse!(
            tag!("#") >>
            sign: opt!(tag!("-")) >>
            left_nums: digit >>
            tag!(".") >>
            right_nums: digit >>
            (
                {
                    let mut tmp = String::from("");
                    if sign.is_some() {
                        tmp.push_str("-");
                    }
                    tmp.push_str(&left_nums.to_string());
                    tmp.push_str(".");
                    tmp.push_str(&right_nums.to_string());
                    Token::FloatOperand{value: tmp.parse::<f64>().unwrap()}
                }
            )
        )
    )
);

named!(irstring<CompleteStr, Token>,
    do_parse!(
        tag!("'") >>
        content: take_until!("'") >>
        tag!("'") >>
        (
            Token::IrString{ name: content.to_string() }
        )
    )
);

named!(pub operand<CompleteStr, Token>,
    alt!(
        integer_operand |
        float_operand |
        label_usage |
        register |
        irstring
    )
);

mod tests {
    #![allow(unused_imports)]

    use assembler::Token;
    use nom::types::CompleteStr;
    use super::{float_operand, integer_operand, irstring};

    #[test]
    fn test_parse_integer_operand() {
        let result = integer_operand(CompleteStr("#10"));
        assert_eq!(result.is_ok(), true);
        let (rest, value) = result.unwrap();
        assert_eq!(rest, CompleteStr(""));
        assert_eq!(value, Token::IntegerOperand { value: 10 });
        let result = integer_operand(CompleteStr("10"));
        assert_eq!(result.is_ok(), false);
    }

    #[test]
    fn test_parse_string_operand() {
        let result = irstring(CompleteStr("'This is a test'"));
        assert_eq!(result.is_ok(), true);
    }

    #[test]
    fn test_parse_float_operand() {
        let test = vec!["#100.3", "#-100.3", "#1.0", "#0.0"];
        for i in &test {
            assert_eq!(float_operand(CompleteStr(i)).is_ok(), true);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Add VoiLutOption::First<commit_after><|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use evcxr;

use evcxr::{Error, EvalContext, EvalContextOutputs};
use std::collections::HashMap;
use std::io;
use std::sync::mpsc;

macro_rules! eval {
    ($ctxt:expr, $($t:tt)*) => {$ctxt.eval(stringify!($($t)*)).unwrap().content_by_mime_type}
}

fn new_context_and_outputs() -> (EvalContext, EvalContextOutputs) {
    if false {
        evcxr::runtime_hook();

        let mut command = std::process::Command::new(&std::env::current_exe().unwrap());
        command
            .arg("--test-threads")
            .arg("1")
            .arg("--nocapture")
            .arg("--quiet");
        EvalContext::with_subprocess_command(command).unwrap()
    } else {
        let testing_runtime_path = std::env::current_exe()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("testing_runtime");
        EvalContext::with_subprocess_command(std::process::Command::new(&testing_runtime_path))
            .unwrap()
    }
}

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

fn new_context() -> EvalContext {
    let (context, outputs) = new_context_and_outputs();
    send_output(outputs.stderr, io::stderr());
    context
}

fn variable_names_and_types(ctx: &EvalContext) -> Vec<(&str, &str)> {
    let mut var_names = ctx.variables_and_types().collect::<Vec<_>>();
    var_names.sort();
    var_names
}

#[test]
fn single_statement() {
    let mut e = new_context();
    eval!(e, assert_eq!(40i32 + 2, 42));
}

#[test]
fn save_and_restore_variables() {
    let mut e = new_context();

    eval!(e, let mut a = 34; let b = 8;);
    eval!(e, a = a + b;);
    eval!(e, assert_eq!(a, 42););
    assert_eq!(eval!(e, a), text_plain("42"));
    // Try to change a mutable variable and check that the error we get is what we expect.
    match e.eval("b = 2;") {
        Err(Error::CompilationErrors(errors)) => {
            if errors.len() != 1 {
                println!("{:#?}", errors);
            }
            assert_eq!(errors.len(), 1);
            assert_eq!(errors[0].code(), Some("E0384"));
        }
        _ => unreachable!(),
    }
}

#[test]
fn printing() {
    let (mut e, outputs) = new_context_and_outputs();

    eval!(e,
        println!("This is stdout");
        eprintln!("This is stderr");
        println!("Another stdout line");
        eprintln!("Another stderr line");
    );
    assert_eq!(outputs.stdout.recv(), Ok("This is stdout".to_owned()));
    assert_eq!(outputs.stderr.recv(), Ok("This is stderr".to_owned()));
    assert_eq!(outputs.stdout.recv(), Ok("Another stdout line".to_owned()));
    assert_eq!(outputs.stderr.recv(), Ok("Another stderr line".to_owned()));
}

#[test]
fn rc_refcell_etc() {
    let mut e = new_context();
    eval!(e,
        use std::cell::RefCell; use std::rc::Rc;
        let r: Rc<RefCell<String>> = Rc::new(RefCell::new(String::new()));
    );
    eval!(e, let r2: Rc<RefCell<String>> = Rc::clone(&r););
    eval!(e, r.borrow_mut().push_str("f"););
    eval!(e, let s = "oo";);
    eval!(e, r.borrow_mut().push_str(s););
    eval!(e, assert!(*r.borrow() == "foo"););
}

#[test]
fn define_then_call_function() {
    let mut e = new_context();
    eval!(
        e,
        pub fn bar() -> i32 {
            42
        }
    );
    eval!(
        e,
        pub fn foo() -> i32 {
            bar()
        }
    );
    eval!(e, assert_eq!(foo(), 42););
    let mut defined_names = e.defined_item_names().collect::<Vec<_>>();
    defined_names.sort();
    assert_eq!(defined_names, vec!["bar", "foo"]);
}

#[test]
fn function_panics_with_variable_preserving() {
    // Don't allow stderr to be printed here. We don't really want to see the
    // panic stack trace when running tests.
    let (mut e, _) = new_context_and_outputs();
    e.preserve_vars_on_panic = true;
    eval!(e, let a = vec![1, 2, 3];);
    eval!(e, let b = 42;);
    eval!(e, panic!("Intentional panic {}", b););
    // The variable a isn't referenced by the code that panics, while the variable b implements
    // Copy, so neither should be lost.
    assert_eq!(
        eval!(e, format!("{:?}, {}", a, b)),
        text_plain("\"[1, 2, 3], 42\"")
    );
}

#[test]
fn function_panics_without_variable_preserving() {
    // Don't allow stderr to be printed here. We don't really want to see the
    // panic stack trace when running tests.
    let (mut e, _) = new_context_and_outputs();
    e.preserve_vars_on_panic = false;
    eval!(e, let a = vec![1, 2, 3];);
    eval!(e, let b = 42;);
    eval!(e, panic!("Intentional panic {}", b););
    assert_eq!(variable_names_and_types(&e), vec![]);
}

// Also tests multiple item definitions in the one compilation unit.
#[test]
fn tls_implementing_drop() {
    let mut e = new_context();
    eval!(e, pub struct Foo {}
    impl Drop for Foo {
        fn drop(&mut self) {
            println!("Dropping Foo");
        }
    }
    pub fn init_foo() {
        thread_local! {
            pub static FOO: Foo = Foo {};
        }
        FOO.with(|f| ())
    });
    eval!(e, init_foo(););
}

fn text_plain(content: &str) -> HashMap<String, String> {
    let mut map = HashMap::new();
    map.insert("text/plain".to_owned(), content.to_owned());
    map
}

#[test]
fn moved_value() {
    let mut e = new_context();
    eval!(e, let a = Some("foo".to_owned()););
    assert_eq!(
        variable_names_and_types(&e),
        vec![("a", "std::option::Option<std::string::String>")]
    );
    assert_eq!(eval!(e, a.unwrap()), text_plain("\"foo\""));
    assert_eq!(variable_names_and_types(&e), vec![]);
}

#[test]
fn struct_type_inference() {
    let mut e = new_context();
    eval!(
        e,
        #[derive(Debug)]
        pub struct Point {
            pub x: i32,
            pub y: i32,
        }
    );
    eval!(e, let p1 = Point {x: 3, y: 8};);
    // While we're here, also test that printing an expression doesn't move the (non-copy)
    // value. Hey, these tests take time to run, we've got to economise :)
    eval!(e, p1);
    // Destructure our point.
    eval!(e, let Point {x, y: y2} = p1;);
    eval!(e, assert_eq!(x, 3););
    eval!(e, assert_eq!(y2, 8););
    let mut defined_names = e.defined_item_names().collect::<Vec<_>>();
    defined_names.sort();
    assert_eq!(defined_names, vec!["Point"]);
}

#[test]
fn non_concrete_types() {
    let mut e = new_context();
    eval!(e, let a = (42, 3.14););
    assert_eq!(
        e.variables_and_types().collect::<Vec<_>>(),
        vec![("a", "(i32, f32)")]
    );
}

#[test]
fn statement_and_expression() {
    let mut e = new_context();
    assert_eq!(
        eval!(e, let a = "foo".to_owned() + "bar"; a),
        text_plain("\"foobar\"")
    );
}

#[test]
fn continue_execution_after_bad_use_statement() {
    let mut e = new_context();
    // First make sure we get the error we expect.
    match e.eval("use foobar;") {
        Err(Error::CompilationErrors(errors)) => {
            assert_eq!(errors.len(), 1);
            assert_eq!(errors[0].code(), Some("E0432"));
        }
        x => panic!("Unexpected result: {:?}", x),
    }
    // Now make sure we can still execute code.
    assert_eq!(eval!(e, "f".to_string() + "oo"), text_plain("\"foo\""));
}

#[test]
fn error_from_macro_expansion() {
    let mut e = new_context();
    // The the following line we're missing & before format!. The compiler reports the error as
    // coming from "<format macros>" with expansion information leading to the user code. Make sure
    // we ignore the span from non-user code and use the expansion info correctly.
    match e.eval("let mut s = String::new(); s.push_str(format!(\"\"));") {
        Err(Error::CompilationErrors(errors)) => {
            assert_eq!(errors.len(), 1);
            assert_eq!(errors[0].code(), Some("E0308")); // mismatched types
            let mut lines = std::collections::HashSet::new();
            for spanned_message in errors[0].spanned_messages() {
                for line in &spanned_message.lines {
                    lines.insert(line.as_str());
                }
            }
            // There's only one line on which we should be reporting errors...
            assert_eq!(
                lines.into_iter().collect::<Vec<_>>(),
                vec!["s.push_str(format!(\"\"));"]
            );
        }
        x => panic!("Unexpected result: {:?}", x),
    }
}

#[test]
fn multiple_identical_use_statements() {
    let mut e = new_context();
    eval!(e, use std::collections::HashMap;);
    eval!(e, use std::collections::HashMap;);
}

#[test]
fn redefine_type_with_existing_var() {
    let mut e = new_context();
    eval!(e,
        struct Foo {x: i32}
        let f1 = Foo {x: 42};
        let f2 = Foo {x: 42};
    );
    assert_eq!(
        variable_names_and_types(&e),
        vec![("f1", "Foo"), ("f2", "Foo")]
    );
    eval!(e,
        struct Foo { x: i32, y: i32 }
        let f3 = Foo {x: 42, y: 43};
    );
    // `f1` and `f2` should have been dropped because the type Foo was
    // redefined.
    assert_eq!(variable_names_and_types(&e), vec![("f3", "Foo")]);
    // Make sure that we actually evaluated the above by checking that f3 is
    // accessible.
    eval!(e,
        assert_eq!(f3.x, 42);
    );
}

#[test]
fn abort_and_restart() {
    let mut e = new_context();
    eval!(
        e,
        pub fn foo() -> i32 {
            42
        }
        // Define a variable in order to check that we don't think it still
        // exists after a restart.
        let a = 42i32;
    );
    let result = e.eval(stringify!(std::process::abort();));
    if let Err(Error::ChildProcessTerminated(message)) = result {
        assert_eq!(message, "Child process terminated with status: signal: 6");
    } else {
        panic!("Unexpected result: {:?}", result);
    }
    eval!(e, assert_eq!(foo(), 42));
    e.clear().unwrap();
    eval!(e, assert_eq!(40 + 2, 42););
}

#[test]
fn variable_assignment_compile_fail_then_use_statement() {
    let mut e = new_context();
    assert!(e.eval(stringify!(let v = foo();)).is_err());
    eval!(e, use std::collections::HashMap;);
    assert_eq!(eval!(e, 42), text_plain("42"));
}

#[test]
fn unnamable_type_closure() {
    let mut e = new_context();
    let result = e.eval(stringify!(let v = || {42};));
    if let Err(Error::Message(message)) = result {
        if !(message.starts_with("Sorry, the type")
            && message.contains("cannot currently be persisted"))
        {
            panic!("Unexpected error: {:?}", message);
        }
    } else {
        panic!("Unexpected result: {:?}", result);
    }
}

#[test]
fn unnamable_type_impl_trait() {
    let mut e = new_context();
    let result = e.eval(stringify!(
        pub trait Bar {}
        impl Bar for i32 {}
        pub fn foo() -> impl Bar {42}
        let v = foo();
    ));
    if let Err(Error::Message(message)) = result {
        if !(message.starts_with("Sorry, the type")
            && message.contains("cannot currently be persisted"))
        {
            panic!("Unexpected error: {:?}", message);
        }
    } else {
        panic!("Unexpected result: {:?}", result);
    }
}
<commit_msg>Fix a test that was failing on Windows.<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use evcxr;

use evcxr::{Error, EvalContext, EvalContextOutputs};
use std::collections::HashMap;
use std::io;
use std::sync::mpsc;

macro_rules! eval {
    ($ctxt:expr, $($t:tt)*) => {$ctxt.eval(stringify!($($t)*)).unwrap().content_by_mime_type}
}

fn new_context_and_outputs() -> (EvalContext, EvalContextOutputs) {
    if false {
        evcxr::runtime_hook();

        let mut command = std::process::Command::new(&std::env::current_exe().unwrap());
        command
            .arg("--test-threads")
            .arg("1")
            .arg("--nocapture")
            .arg("--quiet");
        EvalContext::with_subprocess_command(command).unwrap()
    } else {
        let testing_runtime_path = std::env::current_exe()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("testing_runtime");
        EvalContext::with_subprocess_command(std::process::Command::new(&testing_runtime_path))
            .unwrap()
    }
}

fn send_output<T: io::Write + Send + 'static>(channel: mpsc::Receiver<String>, mut output: T) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            if writeln!(output, "{}", line).is_err() {
                break;
            }
        }
    });
}

fn new_context() -> EvalContext {
    let (context, outputs) = new_context_and_outputs();
    send_output(outputs.stderr, io::stderr());
    context
}

fn variable_names_and_types(ctx: &EvalContext) -> Vec<(&str, &str)> {
    let mut var_names = ctx.variables_and_types().collect::<Vec<_>>();
    var_names.sort();
    var_names
}

#[test]
fn single_statement() {
    let mut e = new_context();
    eval!(e, assert_eq!(40i32 + 2, 42));
}

#[test]
fn save_and_restore_variables() {
    let mut e = new_context();

    eval!(e, let mut a = 34; let b = 8;);
    eval!(e, a = a + b;);
    eval!(e, assert_eq!(a, 42););
    assert_eq!(eval!(e, a), text_plain("42"));
    // Try to change a mutable variable and check that the error we get is what we expect.
    match e.eval("b = 2;") {
        Err(Error::CompilationErrors(errors)) => {
            if errors.len() != 1 {
                println!("{:#?}", errors);
            }
            assert_eq!(errors.len(), 1);
            assert_eq!(errors[0].code(), Some("E0384"));
        }
        _ => unreachable!(),
    }
}

#[test]
fn printing() {
    let (mut e, outputs) = new_context_and_outputs();

    eval!(e,
        println!("This is stdout");
        eprintln!("This is stderr");
        println!("Another stdout line");
        eprintln!("Another stderr line");
    );
    assert_eq!(outputs.stdout.recv(), Ok("This is stdout".to_owned()));
    assert_eq!(outputs.stderr.recv(), Ok("This is stderr".to_owned()));
    assert_eq!(outputs.stdout.recv(), Ok("Another stdout line".to_owned()));
    assert_eq!(outputs.stderr.recv(), Ok("Another stderr line".to_owned()));
}

#[test]
fn rc_refcell_etc() {
    let mut e = new_context();
    eval!(e,
        use std::cell::RefCell; use std::rc::Rc;
        let r: Rc<RefCell<String>> = Rc::new(RefCell::new(String::new()));
    );
    eval!(e, let r2: Rc<RefCell<String>> = Rc::clone(&r););
    eval!(e, r.borrow_mut().push_str("f"););
    eval!(e, let s = "oo";);
    eval!(e, r.borrow_mut().push_str(s););
    eval!(e, assert!(*r.borrow() == "foo"););
}

#[test]
fn define_then_call_function() {
    let mut e = new_context();
    eval!(
        e,
        pub fn bar() -> i32 {
            42
        }
    );
    eval!(
        e,
        pub fn foo() -> i32 {
            bar()
        }
    );
    eval!(e, assert_eq!(foo(), 42););
    let mut defined_names = e.defined_item_names().collect::<Vec<_>>();
    defined_names.sort();
    assert_eq!(defined_names, vec!["bar", "foo"]);
}

#[test]
fn function_panics_with_variable_preserving() {
    // Don't allow stderr to be printed here. We don't really want to see the
    // panic stack trace when running tests.
    let (mut e, _) = new_context_and_outputs();
    e.preserve_vars_on_panic = true;
    eval!(e, let a = vec![1, 2, 3];);
    eval!(e, let b = 42;);
    eval!(e, panic!("Intentional panic {}", b););
    // The variable a isn't referenced by the code that panics, while the variable b implements
    // Copy, so neither should be lost.
    assert_eq!(
        eval!(e, format!("{:?}, {}", a, b)),
        text_plain("\"[1, 2, 3], 42\"")
    );
}

#[test]
fn function_panics_without_variable_preserving() {
    // Don't allow stderr to be printed here. We don't really want to see the
    // panic stack trace when running tests.
    let (mut e, _) = new_context_and_outputs();
    e.preserve_vars_on_panic = false;
    eval!(e, let a = vec![1, 2, 3];);
    eval!(e, let b = 42;);
    eval!(e, panic!("Intentional panic {}", b););
    assert_eq!(variable_names_and_types(&e), vec![]);
}

// Also tests multiple item definitions in the one compilation unit.
#[test]
fn tls_implementing_drop() {
    let mut e = new_context();
    eval!(e, pub struct Foo {}
    impl Drop for Foo {
        fn drop(&mut self) {
            println!("Dropping Foo");
        }
    }
    pub fn init_foo() {
        thread_local! {
            pub static FOO: Foo = Foo {};
        }
        FOO.with(|f| ())
    });
    eval!(e, init_foo(););
}

fn text_plain(content: &str) -> HashMap<String, String> {
    let mut map = HashMap::new();
    map.insert("text/plain".to_owned(), content.to_owned());
    map
}

#[test]
fn moved_value() {
    let mut e = new_context();
    eval!(e, let a = Some("foo".to_owned()););
    assert_eq!(
        variable_names_and_types(&e),
        vec![("a", "std::option::Option<std::string::String>")]
    );
    assert_eq!(eval!(e, a.unwrap()), text_plain("\"foo\""));
    assert_eq!(variable_names_and_types(&e), vec![]);
}

#[test]
fn struct_type_inference() {
    let mut e = new_context();
    eval!(
        e,
        #[derive(Debug)]
        pub struct Point {
            pub x: i32,
            pub y: i32,
        }
    );
    eval!(e, let p1 = Point {x: 3, y: 8};);
    // While we're here, also test that printing an expression doesn't move the (non-copy)
    // value. Hey, these tests take time to run, we've got to economise :)
    eval!(e, p1);
    // Destructure our point.
    eval!(e, let Point {x, y: y2} = p1;);
    eval!(e, assert_eq!(x, 3););
    eval!(e, assert_eq!(y2, 8););
    let mut defined_names = e.defined_item_names().collect::<Vec<_>>();
    defined_names.sort();
    assert_eq!(defined_names, vec!["Point"]);
}

#[test]
fn non_concrete_types() {
    let mut e = new_context();
    eval!(e, let a = (42, 3.14););
    assert_eq!(
        e.variables_and_types().collect::<Vec<_>>(),
        vec![("a", "(i32, f32)")]
    );
}

#[test]
fn statement_and_expression() {
    let mut e = new_context();
    assert_eq!(
        eval!(e, let a = "foo".to_owned() + "bar"; a),
        text_plain("\"foobar\"")
    );
}

#[test]
fn continue_execution_after_bad_use_statement() {
    let mut e = new_context();
    // First make sure we get the error we expect.
    match e.eval("use foobar;") {
        Err(Error::CompilationErrors(errors)) => {
            assert_eq!(errors.len(), 1);
            assert_eq!(errors[0].code(), Some("E0432"));
        }
        x => panic!("Unexpected result: {:?}", x),
    }
    // Now make sure we can still execute code.
    assert_eq!(eval!(e, "f".to_string() + "oo"), text_plain("\"foo\""));
}

#[test]
fn error_from_macro_expansion() {
    let mut e = new_context();
    // The the following line we're missing & before format!. The compiler reports the error as
    // coming from "<format macros>" with expansion information leading to the user code. Make sure
    // we ignore the span from non-user code and use the expansion info correctly.
    match e.eval("let mut s = String::new(); s.push_str(format!(\"\"));") {
        Err(Error::CompilationErrors(errors)) => {
            assert_eq!(errors.len(), 1);
            assert_eq!(errors[0].code(), Some("E0308")); // mismatched types
            let mut lines = std::collections::HashSet::new();
            for spanned_message in errors[0].spanned_messages() {
                for line in &spanned_message.lines {
                    lines.insert(line.as_str());
                }
            }
            // There's only one line on which we should be reporting errors...
            assert_eq!(
                lines.into_iter().collect::<Vec<_>>(),
                vec!["s.push_str(format!(\"\"));"]
            );
        }
        x => panic!("Unexpected result: {:?}", x),
    }
}

#[test]
fn multiple_identical_use_statements() {
    let mut e = new_context();
    eval!(e, use std::collections::HashMap;);
    eval!(e, use std::collections::HashMap;);
}

#[test]
fn redefine_type_with_existing_var() {
    let mut e = new_context();
    eval!(e,
        struct Foo {x: i32}
        let f1 = Foo {x: 42};
        let f2 = Foo {x: 42};
    );
    assert_eq!(
        variable_names_and_types(&e),
        vec![("f1", "Foo"), ("f2", "Foo")]
    );
    eval!(e,
        struct Foo { x: i32, y: i32 }
        let f3 = Foo {x: 42, y: 43};
    );
    // `f1` and `f2` should have been dropped because the type Foo was
    // redefined.
    assert_eq!(variable_names_and_types(&e), vec![("f3", "Foo")]);
    // Make sure that we actually evaluated the above by checking that f3 is
    // accessible.
    eval!(e,
        assert_eq!(f3.x, 42);
    );
}

#[test]
fn abort_and_restart() {
    let mut e = new_context();
    eval!(
        e,
        pub fn foo() -> i32 {
            42
        }
        // Define a variable in order to check that we don't think it still
        // exists after a restart.
        let a = 42i32;
    );
    let result = e.eval(stringify!(std::process::abort();));
    if let Err(Error::ChildProcessTerminated(message)) = result {
        #[cfg(not(windows))]
        {
            assert_eq!(message, "Child process terminated with status: signal: 6");
        }
        #[cfg(windows)]
        {
            assert_eq!(
                message,
                "Child process terminated with status: exit code: 0xc0000409"
            );
        }
    } else {
        panic!("Unexpected result: {:?}", result);
    }
    eval!(e, assert_eq!(foo(), 42));
    e.clear().unwrap();
    eval!(e, assert_eq!(40 + 2, 42););
}

#[test]
fn variable_assignment_compile_fail_then_use_statement() {
    let mut e = new_context();
    assert!(e.eval(stringify!(let v = foo();)).is_err());
    eval!(e, use std::collections::HashMap;);
    assert_eq!(eval!(e, 42), text_plain("42"));
}

#[test]
fn unnamable_type_closure() {
    let mut e = new_context();
    let result = e.eval(stringify!(let v = || {42};));
    if let Err(Error::Message(message)) = result {
        if !(message.starts_with("Sorry, the type")
            && message.contains("cannot currently be persisted"))
        {
            panic!("Unexpected error: {:?}", message);
        }
    } else {
        panic!("Unexpected result: {:?}", result);
    }
}

#[test]
fn unnamable_type_impl_trait() {
    let mut e = new_context();
    let result = e.eval(stringify!(
        pub trait Bar {}
        impl Bar for i32 {}
        pub fn foo() -> impl Bar {42}
        let v = foo();
    ));
    if let Err(Error::Message(message)) = result {
        if !(message.starts_with("Sorry, the type")
            && message.contains("cannot currently be persisted"))
        {
            panic!("Unexpected error: {:?}", message);
        }
    } else {
        panic!("Unexpected result: {:?}", result);
    }
}
<|endoftext|>


<commit_before>use hal::window::Extent2D;
use hal::{self, format as f, image, CompositeAlpha};

use crate::{native, Backend, PhysicalDevice, QueueFamily, GlContainer};
use hal::format::Format;

use std::{
    ffi::{CString, OsStr},
    mem,
    os::{raw::c_void, windows::ffi::OsStrExt},
    ptr,
};
use winapi::shared::minwindef::*;
use winapi::shared::windef::*;
use winapi::um::libloaderapi::*;
use winapi::um::wingdi::*;
use winapi::um::winuser::*;

pub mod wgl_sys {
    include!(concat!(env!("OUT_DIR"), "/wgl_sys.rs"));
}

pub mod wgl_ext_sys {
    include!(concat!(env!("OUT_DIR"), "/wgl_ext_sys.rs"));
}

#[link(name = "opengl32")]
extern "C" {}

#[cfg(feature = "winit")]
use winit;

pub(crate) struct Entry {
    hwnd: HWND,
    pub(crate) hdc: HDC,
    pub(crate) wgl: wgl_ext_sys::Wgl,
    lib: HMODULE,
}

unsafe impl Sync for Entry {}

impl Entry {
    pub fn new() -> Self {
        unsafe {
            let mut class: WNDCLASSEXW = mem::zeroed();
            let instance = GetModuleHandleW(ptr::null());
            let class_name = OsStr::new("gfx-rs wgl")
                .encode_wide()
                .chain(Some(0).into_iter())
                .collect::<Vec<_>>();

            class.cbSize = mem::size_of::<WNDCLASSEXW>() as UINT;
            class.lpszClassName = class_name.as_ptr();
            class.lpfnWndProc = Some(DefWindowProcW);

            RegisterClassExW(&class);

            let hwnd = CreateWindowExW(
                0,
                class_name.as_ptr(),
                std::ptr::null(),
                0,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                instance,
                std::ptr::null_mut(),
            );

            let hdc = GetDC(hwnd);

            let desc = PIXELFORMATDESCRIPTOR {
                nSize: std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16,
                nVersion: 1,
                dwFlags: PFD_SUPPORT_OPENGL,
                iPixelType: PFD_TYPE_RGBA,
                cColorBits: 8,
                cRedBits: 0,
                cRedShift: 0,
                cGreenBits: 0,
                cGreenShift: 0,
                cBlueBits: 0,
                cBlueShift: 0,
                cAlphaBits: 8,
                cAlphaShift: 0,
                cAccumBits: 0,
                cAccumRedBits: 0,
                cAccumGreenBits: 0,
                cAccumBlueBits: 0,
                cAccumAlphaBits: 0,
                cDepthBits: 0,
                cStencilBits: 0,
                cAuxBuffers: 0,
                iLayerType: PFD_MAIN_PLANE,
                bReserved: 0,
                dwLayerMask: 0,
                dwVisibleMask: 0,
                dwDamageMask: 0,
            };

            let format_id = ChoosePixelFormat(hdc, &desc);
            SetPixelFormat(hdc, format_id, &desc);
            let hglrc = wglCreateContext(hdc);

            println!("{:?}", (hwnd, hdc, format_id, hglrc));

            wglMakeCurrent(hdc, hglrc);

            let name = OsStr::new("opengl32.dll")
                .encode_wide()
                .chain(Some(0).into_iter())
                .collect::<Vec<_>>();

            let lib = LoadLibraryW(name.as_ptr());

            let wgl = wgl_ext_sys::Wgl::load_with(|sym| {
                let sym = CString::new(sym.as_bytes()).unwrap();
                let addr = wgl_sys::GetProcAddress(sym.as_ptr()) as *const ();
                if !addr.is_null() {
                    addr as *const _
                } else {
                    GetProcAddress(lib, sym.as_ptr()) as *const _
                }
            });

            Entry {
                hwnd,
                hdc: hdc as _,
                wgl,
                lib,
            }
        }
    }
}

impl Drop for Entry {
    fn drop(&mut self) {
        unsafe {
            DestroyWindow(self.hwnd);
        }
    }
}

lazy_static! {
    // Entry function pointers
    pub(crate) static ref WGL_ENTRY: Entry = Entry::new();
}

pub struct Instance {
    pub(crate) ctxt: DeviceContext,
}

impl Instance {
    pub fn create(_name: &str, version: u32) -> Self {
        unsafe {
            let glrc = WGL_ENTRY.wgl.CreateContextAttribsARB(
                WGL_ENTRY.hdc as *const _,
                ptr::null(),
                ptr::null(),
            ) as HGLRC;

            wglMakeCurrent(WGL_ENTRY.hdc as *mut _, glrc);

            Instance {
                ctxt: DeviceContext {
                    ctxt: Context { glrc },
                    hdc: WGL_ENTRY.hdc,
                },
            }
        }
    }

    #[cfg(windows)]
    pub fn create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface {
        Surface {
            hwnd: hwnd as *mut _,
        }
    }

    #[cfg(feature = "winit")]
    pub fn create_surface(&self, window: &winit::Window) -> Surface {
        use winit::os::windows::WindowExt;

        let hwnd = window.get_hwnd();
        self.create_surface_from_hwnd(hwnd as *mut _)
    }
}

impl hal::Instance for Instance {
    type Backend = Backend;

    fn enumerate_adapters(&self) -> Vec<hal::Adapter<Backend>> {
        let gl_container = GlContainer::from_fn_proc(|s| unsafe {
            let sym = CString::new(s.as_bytes()).unwrap();
            let addr = wgl_sys::GetProcAddress(sym.as_ptr()) as *const ();
            if !addr.is_null() {
                addr as *const _
            } else {
                GetProcAddress(WGL_ENTRY.lib, sym.as_ptr()) as *const _
            }
        });
        let adapter = PhysicalDevice::new_adapter(self.ctxt, gl_container);
        vec![adapter]
    }
}

#[derive(Debug)]
pub struct Surface {
    pub(crate) hwnd: HWND,
}

// TODO: high -msiglreith
unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl Surface {
    fn get_extent(&self) -> hal::window::Extent2D {
        let mut rect: RECT = unsafe { mem::uninitialized() };
        unsafe {
            GetClientRect(self.hwnd, &mut rect);
        }
        hal::window::Extent2D {
            width: (rect.right - rect.left) as _,
            height: (rect.bottom - rect.top) as _,
        }
    }
}

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> hal::image::Kind {
        unimplemented!()
    }

    fn compatibility(
        &self,
        physical_device: &PhysicalDevice,
    ) -> (
        hal::SurfaceCapabilities,
        Option<Vec<Format>>,
        Vec<hal::PresentMode>,
    ) {
        let extent = self.get_extent();

        let caps = hal::SurfaceCapabilities {
            image_count: 2..3,
            current_extent: Some(extent),
            extents: extent..hal::window::Extent2D {
                width: extent.width + 1,
                height: extent.height + 1,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT | image::Usage::TRANSFER_SRC,
            composite_alpha: CompositeAlpha::OPAQUE, //TODO
        };
        let present_modes = vec![
            hal::PresentMode::Fifo, //TODO
        ];

        (
            caps,
            Some(vec![f::Format::Rgba8Srgb, f::Format::Bgra8Srgb]),
            present_modes,
        )
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        true
    }
}

#[derive(Debug)]
pub struct Swapchain {
    pub(crate) fbos: Vec<native::FrameBuffer>,
    pub(crate) context: PresentContext,
    pub(crate) extent: Extent2D,
}
impl Swapchain {
    pub(crate) fn make_current(&self) {
        self.context.make_current();
    }

    pub(crate) fn swap_buffers(&self) {
        self.context.swap_buffers();
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
        _semaphore: Option<&native::Semaphore>,
        _fence: Option<&native::Fence>,
    ) -> Result<(hal::SwapImageIndex, Option<hal::window::Suboptimal>), hal::AcquireError> {
        Ok((0, None)) // TODO
    }
}

/// Basic abstraction for wgl context handles.
#[derive(Debug, Copy, Clone)]
struct Context {
    glrc: HGLRC,
}

impl Context {
    unsafe fn make_current(&self, hdc: HDC) {
        wglMakeCurrent(hdc, self.glrc);
    }
}

/// Owned context for devices and instances.
#[derive(Debug, Copy, Clone)]
pub(crate) struct DeviceContext {
    /// Owned wgl context.
    ctxt: Context,

    /// Device context owned by the corresponding instance.
    ///
    /// This refers to either a pbuffer or dummy window. Therefore not used for actual presentation.
    hdc: HDC,
}

// TODO
unsafe impl Send for DeviceContext {}
unsafe impl Sync for DeviceContext {}

impl DeviceContext {
    pub(crate) fn make_current(&self) {
        unsafe {
            self.ctxt.make_current(self.hdc);
        }
    }
}

/// Owned context for swapchains which soley is required for presentation.
#[derive(Debug)]
pub(crate) struct PresentContext {
    /// Owned wgl context.
    ctxt: Context,

    /// Device context of the corresponding presentation surface.
    hdc: HDC,
}

// TODO
unsafe impl Send for PresentContext {}
unsafe impl Sync for PresentContext {}

impl PresentContext {
    pub(crate) fn new(surface: &Surface, device_ctxt: &DeviceContext) -> Self {
        // TODO: configuration options
        unsafe {
            let hdc = GetDC(surface.hwnd);

            let desc = PIXELFORMATDESCRIPTOR {
                nSize: std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16,
                nVersion: 1,
                dwFlags: PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
                iPixelType: PFD_TYPE_RGBA,
                cColorBits: 32,
                cRedBits: 0,
                cRedShift: 0,
                cGreenBits: 0,
                cGreenShift: 0,
                cBlueBits: 0,
                cBlueShift: 0,
                cAlphaBits: 8,
                cAlphaShift: 0,
                cAccumBits: 0,
                cAccumRedBits: 0,
                cAccumGreenBits: 0,
                cAccumBlueBits: 0,
                cAccumAlphaBits: 0,
                cDepthBits: 0,
                cStencilBits: 0,
                cAuxBuffers: 0,
                iLayerType: PFD_MAIN_PLANE,
                bReserved: 0,
                dwLayerMask: 0,
                dwVisibleMask: 0,
                dwDamageMask: 0,
            };

            let format_id = ChoosePixelFormat(hdc, &desc);
            SetPixelFormat(hdc, format_id, &desc);

            let glrc = WGL_ENTRY.wgl.CreateContextAttribsARB(
                hdc as *const _,
                device_ctxt.ctxt.glrc as _,
                ptr::null(),
            ) as HGLRC;

            wglMakeCurrent(hdc, glrc);

            PresentContext {
                ctxt: Context { glrc },
                hdc,
            }
        }
    }

    pub(crate) fn make_current(&self) {
        unsafe {
            self.ctxt.make_current(self.hdc);
        }
    }

    fn swap_buffers(&self) {
        unsafe {
            SwapBuffers(self.hdc);
        }
    }
}
<commit_msg>wgl: Add missing Send implementation<commit_after>use hal::window::Extent2D;
use hal::{self, format as f, image, CompositeAlpha};

use crate::{native, Backend, PhysicalDevice, QueueFamily, GlContainer};
use hal::format::Format;

use std::{
    ffi::{CString, OsStr},
    mem,
    os::{raw::c_void, windows::ffi::OsStrExt},
    ptr,
};
use winapi::shared::minwindef::*;
use winapi::shared::windef::*;
use winapi::um::libloaderapi::*;
use winapi::um::wingdi::*;
use winapi::um::winuser::*;

pub mod wgl_sys {
    include!(concat!(env!("OUT_DIR"), "/wgl_sys.rs"));
}

pub mod wgl_ext_sys {
    include!(concat!(env!("OUT_DIR"), "/wgl_ext_sys.rs"));
}

#[link(name = "opengl32")]
extern "C" {}

#[cfg(feature = "winit")]
use winit;

pub(crate) struct Entry {
    hwnd: HWND,
    pub(crate) hdc: HDC,
    pub(crate) wgl: wgl_ext_sys::Wgl,
    lib: HMODULE,
}

unsafe impl Send for Entry {}
unsafe impl Sync for Entry {}

impl Entry {
    pub fn new() -> Self {
        unsafe {
            let mut class: WNDCLASSEXW = mem::zeroed();
            let instance = GetModuleHandleW(ptr::null());
            let class_name = OsStr::new("gfx-rs wgl")
                .encode_wide()
                .chain(Some(0).into_iter())
                .collect::<Vec<_>>();

            class.cbSize = mem::size_of::<WNDCLASSEXW>() as UINT;
            class.lpszClassName = class_name.as_ptr();
            class.lpfnWndProc = Some(DefWindowProcW);

            RegisterClassExW(&class);

            let hwnd = CreateWindowExW(
                0,
                class_name.as_ptr(),
                std::ptr::null(),
                0,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                instance,
                std::ptr::null_mut(),
            );

            let hdc = GetDC(hwnd);

            let desc = PIXELFORMATDESCRIPTOR {
                nSize: std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16,
                nVersion: 1,
                dwFlags: PFD_SUPPORT_OPENGL,
                iPixelType: PFD_TYPE_RGBA,
                cColorBits: 8,
                cRedBits: 0,
                cRedShift: 0,
                cGreenBits: 0,
                cGreenShift: 0,
                cBlueBits: 0,
                cBlueShift: 0,
                cAlphaBits: 8,
                cAlphaShift: 0,
                cAccumBits: 0,
                cAccumRedBits: 0,
                cAccumGreenBits: 0,
                cAccumBlueBits: 0,
                cAccumAlphaBits: 0,
                cDepthBits: 0,
                cStencilBits: 0,
                cAuxBuffers: 0,
                iLayerType: PFD_MAIN_PLANE,
                bReserved: 0,
                dwLayerMask: 0,
                dwVisibleMask: 0,
                dwDamageMask: 0,
            };

            let format_id = ChoosePixelFormat(hdc, &desc);
            SetPixelFormat(hdc, format_id, &desc);
            let hglrc = wglCreateContext(hdc);

            println!("{:?}", (hwnd, hdc, format_id, hglrc));

            wglMakeCurrent(hdc, hglrc);

            let name = OsStr::new("opengl32.dll")
                .encode_wide()
                .chain(Some(0).into_iter())
                .collect::<Vec<_>>();

            let lib = LoadLibraryW(name.as_ptr());

            let wgl = wgl_ext_sys::Wgl::load_with(|sym| {
                let sym = CString::new(sym.as_bytes()).unwrap();
                let addr = wgl_sys::GetProcAddress(sym.as_ptr()) as *const ();
                if !addr.is_null() {
                    addr as *const _
                } else {
                    GetProcAddress(lib, sym.as_ptr()) as *const _
                }
            });

            Entry {
                hwnd,
                hdc: hdc as _,
                wgl,
                lib,
            }
        }
    }
}

impl Drop for Entry {
    fn drop(&mut self) {
        unsafe {
            DestroyWindow(self.hwnd);
        }
    }
}

lazy_static! {
    // Entry function pointers
    pub(crate) static ref WGL_ENTRY: Entry = Entry::new();
}

pub struct Instance {
    pub(crate) ctxt: DeviceContext,
}

impl Instance {
    pub fn create(_name: &str, version: u32) -> Self {
        unsafe {
            let glrc = WGL_ENTRY.wgl.CreateContextAttribsARB(
                WGL_ENTRY.hdc as *const _,
                ptr::null(),
                ptr::null(),
            ) as HGLRC;

            wglMakeCurrent(WGL_ENTRY.hdc as *mut _, glrc);

            Instance {
                ctxt: DeviceContext {
                    ctxt: Context { glrc },
                    hdc: WGL_ENTRY.hdc,
                },
            }
        }
    }

    #[cfg(windows)]
    pub fn create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface {
        Surface {
            hwnd: hwnd as *mut _,
        }
    }

    #[cfg(feature = "winit")]
    pub fn create_surface(&self, window: &winit::Window) -> Surface {
        use winit::os::windows::WindowExt;

        let hwnd = window.get_hwnd();
        self.create_surface_from_hwnd(hwnd as *mut _)
    }
}

impl hal::Instance for Instance {
    type Backend = Backend;

    fn enumerate_adapters(&self) -> Vec<hal::Adapter<Backend>> {
        let gl_container = GlContainer::from_fn_proc(|s| unsafe {
            let sym = CString::new(s.as_bytes()).unwrap();
            let addr = wgl_sys::GetProcAddress(sym.as_ptr()) as *const ();
            if !addr.is_null() {
                addr as *const _
            } else {
                GetProcAddress(WGL_ENTRY.lib, sym.as_ptr()) as *const _
            }
        });
        let adapter = PhysicalDevice::new_adapter(self.ctxt, gl_container);
        vec![adapter]
    }
}

#[derive(Debug)]
pub struct Surface {
    pub(crate) hwnd: HWND,
}

// TODO: high -msiglreith
unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl Surface {
    fn get_extent(&self) -> hal::window::Extent2D {
        let mut rect: RECT = unsafe { mem::uninitialized() };
        unsafe {
            GetClientRect(self.hwnd, &mut rect);
        }
        hal::window::Extent2D {
            width: (rect.right - rect.left) as _,
            height: (rect.bottom - rect.top) as _,
        }
    }
}

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> hal::image::Kind {
        unimplemented!()
    }

    fn compatibility(
        &self,
        physical_device: &PhysicalDevice,
    ) -> (
        hal::SurfaceCapabilities,
        Option<Vec<Format>>,
        Vec<hal::PresentMode>,
    ) {
        let extent = self.get_extent();

        let caps = hal::SurfaceCapabilities {
            image_count: 2..3,
            current_extent: Some(extent),
            extents: extent..hal::window::Extent2D {
                width: extent.width + 1,
                height: extent.height + 1,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT | image::Usage::TRANSFER_SRC,
            composite_alpha: CompositeAlpha::OPAQUE, //TODO
        };
        let present_modes = vec![
            hal::PresentMode::Fifo, //TODO
        ];

        (
            caps,
            Some(vec![f::Format::Rgba8Srgb, f::Format::Bgra8Srgb]),
            present_modes,
        )
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        true
    }
}

#[derive(Debug)]
pub struct Swapchain {
    pub(crate) fbos: Vec<native::FrameBuffer>,
    pub(crate) context: PresentContext,
    pub(crate) extent: Extent2D,
}
impl Swapchain {
    pub(crate) fn make_current(&self) {
        self.context.make_current();
    }

    pub(crate) fn swap_buffers(&self) {
        self.context.swap_buffers();
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
        _semaphore: Option<&native::Semaphore>,
        _fence: Option<&native::Fence>,
    ) -> Result<(hal::SwapImageIndex, Option<hal::window::Suboptimal>), hal::AcquireError> {
        Ok((0, None)) // TODO
    }
}

/// Basic abstraction for wgl context handles.
#[derive(Debug, Copy, Clone)]
struct Context {
    glrc: HGLRC,
}

impl Context {
    unsafe fn make_current(&self, hdc: HDC) {
        wglMakeCurrent(hdc, self.glrc);
    }
}

/// Owned context for devices and instances.
#[derive(Debug, Copy, Clone)]
pub(crate) struct DeviceContext {
    /// Owned wgl context.
    ctxt: Context,

    /// Device context owned by the corresponding instance.
    ///
    /// This refers to either a pbuffer or dummy window. Therefore not used for actual presentation.
    hdc: HDC,
}

// TODO
unsafe impl Send for DeviceContext {}
unsafe impl Sync for DeviceContext {}

impl DeviceContext {
    pub(crate) fn make_current(&self) {
        unsafe {
            self.ctxt.make_current(self.hdc);
        }
    }
}

/// Owned context for swapchains which soley is required for presentation.
#[derive(Debug)]
pub(crate) struct PresentContext {
    /// Owned wgl context.
    ctxt: Context,

    /// Device context of the corresponding presentation surface.
    hdc: HDC,
}

// TODO
unsafe impl Send for PresentContext {}
unsafe impl Sync for PresentContext {}

impl PresentContext {
    pub(crate) fn new(surface: &Surface, device_ctxt: &DeviceContext) -> Self {
        // TODO: configuration options
        unsafe {
            let hdc = GetDC(surface.hwnd);

            let desc = PIXELFORMATDESCRIPTOR {
                nSize: std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16,
                nVersion: 1,
                dwFlags: PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
                iPixelType: PFD_TYPE_RGBA,
                cColorBits: 32,
                cRedBits: 0,
                cRedShift: 0,
                cGreenBits: 0,
                cGreenShift: 0,
                cBlueBits: 0,
                cBlueShift: 0,
                cAlphaBits: 8,
                cAlphaShift: 0,
                cAccumBits: 0,
                cAccumRedBits: 0,
                cAccumGreenBits: 0,
                cAccumBlueBits: 0,
                cAccumAlphaBits: 0,
                cDepthBits: 0,
                cStencilBits: 0,
                cAuxBuffers: 0,
                iLayerType: PFD_MAIN_PLANE,
                bReserved: 0,
                dwLayerMask: 0,
                dwVisibleMask: 0,
                dwDamageMask: 0,
            };

            let format_id = ChoosePixelFormat(hdc, &desc);
            SetPixelFormat(hdc, format_id, &desc);

            let glrc = WGL_ENTRY.wgl.CreateContextAttribsARB(
                hdc as *const _,
                device_ctxt.ctxt.glrc as _,
                ptr::null(),
            ) as HGLRC;

            wglMakeCurrent(hdc, glrc);

            PresentContext {
                ctxt: Context { glrc },
                hdc,
            }
        }
    }

    pub(crate) fn make_current(&self) {
        unsafe {
            self.ctxt.make_current(self.hdc);
        }
    }

    fn swap_buffers(&self) {
        unsafe {
            SwapBuffers(self.hdc);
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Error, ErrorKind, Read, Write};
use super::{Rebox, HeapAllocator, IoWriterWrapper};
use brotli::{DecompressorWriterCustomIo, CustomWrite};
use alloc_no_stdlib::{Allocator, SliceWrapper};
use brotli::enc::BrotliEncoderParams;
#[cfg(feature="validation")]
use sha2::{Sha256, Digest};
#[cfg(feature="validation")]
type Checksum = Sha256;

struct Tee<OutputA:Write, OutputB:Write>(OutputA, OutputB);
impl <OutputA:Write, OutputB:Write> Write for Tee<OutputA, OutputB> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        match self.0.write(data) {
            Err(err) => return Err(err),
            Ok(size) => match self.1.write_all(&data[..size]) {
                Ok(_) => Ok(size),
                Err(err) => Err(err),
            }
        }
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        match self.0.flush() {
            Err(err) => return Err(err),
            Ok(_) => {
                loop {
                    match self.1.flush() {
                        Err(e) => match e.kind() {
                            ErrorKind::Interrupted => continue,
                            _ => return Err(e),
                        },
                        Ok(e) => return Ok(e),
                    }
                }
            },
        }
    }
}

struct DecompressAndValidate<'a, OutputType:Write+'a>(
    DecompressorWriterCustomIo<io::Error,
                               IoWriterWrapper<'a, OutputType>,
                               Rebox<u8>, // buffer type
                               HeapAllocator,
                               HeapAllocator,
                               HeapAllocator>
);

impl<'a, OutputType:Write> Write for DecompressAndValidate<'a, OutputType> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.write(data)
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.0.flush()
    }
}

#[cfg(not(feature="validation"))]
fn make_sha_writer() -> io::Sink {
    io::sink()
}
#[cfg(not(feature="validation"))]
fn make_sha_reader<InputType:Read>(r:&mut InputType) -> &mut InputType {
    r
}

#[cfg(not(feature="validation"))]
fn sha_ok<InputType:Read>(_writer: &mut io::Sink, _reader: &mut InputType) -> bool {
    false
}

#[cfg(feature="validation")]
struct ShaReader<'a, InputType:Read> {
    reader:&'a mut InputType,
    checksum:Checksum,
}
#[cfg(feature="validation")]
impl<'a, InputType:Read> Read for ShaReader<'a, InputType> {
    fn read(&mut self, data: &mut [u8]) -> Result<usize, io::Error> {
        match self.reader.read(data) {
            Err(e) => Err(e),
            Ok(size) => {
                self.checksum.input(&data[..size]);
                Ok(size)
            },
        }
    }
}
#[cfg(feature="validation")]
fn make_sha_reader<InputType:Read>(r:&mut InputType) -> ShaReader<InputType> {
    ShaReader{
        reader:r,
        checksum:Checksum::default(),
    }
}

#[cfg(feature="validation")]
fn sha_ok<InputType:Read>(writer: &mut ShaWriter, reader: &mut ShaReader<InputType>) -> bool {
    core::mem::replace(&mut writer.0,
                       Checksum::default()).result() == core::mem::replace(&mut reader.checksum,
                                                                           Checksum::default()).result()
}
#[cfg(feature="validation")]
#[derive(Default)]
struct ShaWriter(Checksum);
#[cfg(feature="validation")]
impl Write for ShaWriter {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.input(data);
        Ok(data.len())
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}
#[cfg(feature="validation")]
fn make_sha_writer() -> ShaWriter {
    ShaWriter::default()
}
#[cfg(feature="validation")]
const VALIDATION_FAILED: &'static str = "Validation failed";
#[cfg(not(feature="validation"))]
const VALIDATION_FAILED: &'static str = "Validation module not enabled: build with cargo build --features=validation";

pub fn compress_validate<InputType:Read, OutputType: Write>(r: &mut InputType,
                                                            w: &mut OutputType,
                                                            buffer_size: usize,
                                                            params: &BrotliEncoderParams,
                                                            custom_dictionary:Rebox<u8>,
                                                            num_threads: usize) -> Result<(), io::Error> {
    let mut m8 = HeapAllocator::default();
    let buffer = <HeapAllocator as Allocator<u8>>::alloc_cell(&mut m8, buffer_size);
    // FIXME: could reuse the dictionary to seed the compressor, but that violates the abstraction right now
    // also dictionaries are not very popular since they are mostly an internal concept, given their deprecation in
    // the standard brotli spec
    let mut dict = Vec::<u8>::new();

    dict.extend_from_slice(custom_dictionary.slice());
    let mut sha_writer = make_sha_writer();
    let mut sha_reader = make_sha_reader(r);
    let ret;
    {
        let validate_writer = DecompressAndValidate(DecompressorWriterCustomIo::new_with_custom_dictionary(
            IoWriterWrapper(&mut sha_writer),
            buffer,
            m8,
            HeapAllocator::default(),
            HeapAllocator::default(),
            custom_dictionary,
            Error::new(ErrorKind::InvalidData,
                       "Invalid Data")));
        let mut overarching_writer = Tee(validate_writer, w);
        ret = super::compress(&mut sha_reader, &mut overarching_writer, buffer_size, params, &dict[..], num_threads);
    }
    match ret {
        Ok(_ret) => {
            if sha_ok(&mut sha_writer, &mut sha_reader) {
                return Ok(());
            } else {
                return Err(Error::new(ErrorKind::InvalidData, VALIDATION_FAILED));
            }
        },
        Err(e) => Err(e),
    }
}
<commit_msg>specify lifetimes and import core<commit_after>#[cfg(feature="validation")]
use core;
use std::io::{self, Error, ErrorKind, Read, Write};
use super::{Rebox, HeapAllocator, IoWriterWrapper};
use brotli::{DecompressorWriterCustomIo, CustomWrite};
use alloc_no_stdlib::{Allocator, SliceWrapper};
use brotli::enc::BrotliEncoderParams;
#[cfg(feature="validation")]
use sha2::{Sha256, Digest};
#[cfg(feature="validation")]
type Checksum = Sha256;

struct Tee<OutputA:Write, OutputB:Write>(OutputA, OutputB);
impl <OutputA:Write, OutputB:Write> Write for Tee<OutputA, OutputB> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        match self.0.write(data) {
            Err(err) => return Err(err),
            Ok(size) => match self.1.write_all(&data[..size]) {
                Ok(_) => Ok(size),
                Err(err) => Err(err),
            }
        }
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        match self.0.flush() {
            Err(err) => return Err(err),
            Ok(_) => {
                loop {
                    match self.1.flush() {
                        Err(e) => match e.kind() {
                            ErrorKind::Interrupted => continue,
                            _ => return Err(e),
                        },
                        Ok(e) => return Ok(e),
                    }
                }
            },
        }
    }
}

struct DecompressAndValidate<'a, OutputType:Write+'a>(
    DecompressorWriterCustomIo<io::Error,
                               IoWriterWrapper<'a, OutputType>,
                               Rebox<u8>, // buffer type
                               HeapAllocator,
                               HeapAllocator,
                               HeapAllocator>
);

impl<'a, OutputType:Write> Write for DecompressAndValidate<'a, OutputType> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.write(data)
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.0.flush()
    }
}

#[cfg(not(feature="validation"))]
fn make_sha_writer() -> io::Sink {
    io::sink()
}
#[cfg(not(feature="validation"))]
fn make_sha_reader<InputType:Read>(r:&mut InputType) -> &mut InputType {
    r
}

#[cfg(not(feature="validation"))]
fn sha_ok<InputType:Read>(_writer: &mut io::Sink, _reader: &mut InputType) -> bool {
    false
}

#[cfg(feature="validation")]
struct ShaReader<'a, InputType:Read+'a> {
    reader:&'a mut InputType,
    checksum:Checksum,
}
#[cfg(feature="validation")]
impl<'a, InputType:Read+'a> Read for ShaReader<'a, InputType> {
    fn read(&mut self, data: &mut [u8]) -> Result<usize, io::Error> {
        match self.reader.read(data) {
            Err(e) => Err(e),
            Ok(size) => {
                self.checksum.input(&data[..size]);
                Ok(size)
            },
        }
    }
}
#[cfg(feature="validation")]
fn make_sha_reader<InputType:Read>(r:&mut InputType) -> ShaReader<InputType> {
    ShaReader{
        reader:r,
        checksum:Checksum::default(),
    }
}

#[cfg(feature="validation")]
fn sha_ok<InputType:Read>(writer: &mut ShaWriter, reader: &mut ShaReader<InputType>) -> bool {
    core::mem::replace(&mut writer.0,
                       Checksum::default()).result() == core::mem::replace(&mut reader.checksum,
                                                                           Checksum::default()).result()
}
#[cfg(feature="validation")]
#[derive(Default)]
struct ShaWriter(Checksum);
#[cfg(feature="validation")]
impl Write for ShaWriter {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.input(data);
        Ok(data.len())
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}
#[cfg(feature="validation")]
fn make_sha_writer() -> ShaWriter {
    ShaWriter::default()
}
#[cfg(feature="validation")]
const VALIDATION_FAILED: &'static str = "Validation failed";
#[cfg(not(feature="validation"))]
const VALIDATION_FAILED: &'static str = "Validation module not enabled: build with cargo build --features=validation";

pub fn compress_validate<InputType:Read, OutputType: Write>(r: &mut InputType,
                                                            w: &mut OutputType,
                                                            buffer_size: usize,
                                                            params: &BrotliEncoderParams,
                                                            custom_dictionary:Rebox<u8>,
                                                            num_threads: usize) -> Result<(), io::Error> {
    let mut m8 = HeapAllocator::default();
    let buffer = <HeapAllocator as Allocator<u8>>::alloc_cell(&mut m8, buffer_size);
    // FIXME: could reuse the dictionary to seed the compressor, but that violates the abstraction right now
    // also dictionaries are not very popular since they are mostly an internal concept, given their deprecation in
    // the standard brotli spec
    let mut dict = Vec::<u8>::new();

    dict.extend_from_slice(custom_dictionary.slice());
    let mut sha_writer = make_sha_writer();
    let mut sha_reader = make_sha_reader(r);
    let ret;
    {
        let validate_writer = DecompressAndValidate(DecompressorWriterCustomIo::new_with_custom_dictionary(
            IoWriterWrapper(&mut sha_writer),
            buffer,
            m8,
            HeapAllocator::default(),
            HeapAllocator::default(),
            custom_dictionary,
            Error::new(ErrorKind::InvalidData,
                       "Invalid Data")));
        let mut overarching_writer = Tee(validate_writer, w);
        ret = super::compress(&mut sha_reader, &mut overarching_writer, buffer_size, params, &dict[..], num_threads);
    }
    match ret {
        Ok(_ret) => {
            if sha_ok(&mut sha_writer, &mut sha_reader) {
                return Ok(());
            } else {
                return Err(Error::new(ErrorKind::InvalidData, VALIDATION_FAILED));
            }
        },
        Err(e) => Err(e),
    }
}
<|endoftext|>