<commit_before>#![doc(test(attr(deny(warnings))))]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(feature = "futures-v0_3"), allow(dead_code, unused_imports))]

//! A crate for integrating signal handling with the Tokio runtime.
//!
//! This provides the [`Signals`][Signals] struct which acts as a
//! [`Stream`] of signals.
//!
//! Note that the `futures-v0_3` feature of this crate must be
//! enabled for `Signals` to implement the `Stream` trait.
//!
//! # Example
//!
//! ```rust
//! # #[cfg(feature = "futures-v0_3")]
//! # mod test {
//! use std::io::Error;
//!
//! use signal_hook::consts::signal::*;
//! use signal_hook_tokio::Signals;
//!
//! use futures::stream::StreamExt;
//!
//! async fn handle_signals(signals: Signals) {
//!     let mut signals = signals.fuse();
//!     while let Some(signal) = signals.next().await {
//!         match signal {
//!             SIGHUP => {
//!                 // Reload configuration
//!                 // Reopen the log file
//!             }
//!             SIGTERM | SIGINT | SIGQUIT => {
//!                 // Shutdown the system;
//!             },
//!             _ => unreachable!(),
//!         }
//!     }
//! }
//!
//! #[tokio::main]
//! # pub
//! async fn main() -> Result<(), Error> {
//!     let signals = Signals::new(&[
//!         SIGHUP,
//!         SIGTERM,
//!         SIGINT,
//!         SIGQUIT,
//!     ])?;
//!     let handle = signals.handle();
//!
//!     let signals_task = tokio::spawn(handle_signals(signals));
//!
//!     // Execute your main program logic
//!
//!     // Terminate the signal stream.
//!     handle.close();
//!     signals_task.await?;
//!
//!     Ok(())
//! }
//! }
//! # fn main() -> Result<(), std::io::Error> {
//! #    #[cfg(feature = "futures-v0_3")]
//! #    test::main()?;
//! #    Ok(())
//! # }
//! ```

use std::borrow::Borrow;
use std::io::Error;
use std::pin::Pin;
use std::task::{Context, Poll};

use libc::c_int;

use tokio::io::{AsyncRead, ReadBuf};
use tokio::net::UnixStream;

pub use signal_hook::iterator::backend::Handle;
use signal_hook::iterator::backend::{OwningSignalIterator, PollResult, SignalDelivery};
use signal_hook::iterator::exfiltrator::{Exfiltrator, SignalOnly};

#[cfg(feature = "futures-v0_3")]
use futures_core_0_3::Stream;

/// An asynchronous [`Stream`] of arriving signals.
///
/// The stream doesn't return the signals in the order they were recieved by
/// the process and may merge signals received multiple times.
pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(OwningSignalIterator<UnixStream, E>);

impl<E: Exfiltrator> SignalsInfo<E> {
    /// Create a `SignalsInfo` instance.
    ///
    /// This registers all the signals listed. The same restrictions (panics, errors) apply
    /// as with [`Handle::add_signal`].
    pub fn new<I, S>(signals: I) -> Result<Self, Error>
    where
        I: IntoIterator<Item = S>,
        S: Borrow<c_int>,
        E: Default,
    {
        Self::with_exfiltrator(signals, E::default())
    }

    /// A constructor with explicit exfiltrator.
    pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error>
    where
        I: IntoIterator<Item = S>,
        S: Borrow<c_int>,
    {
        let (read, write) = UnixStream::pair()?;
        let inner = SignalDelivery::with_pipe(read, write, exfiltrator, signals)?;
        Ok(Self(OwningSignalIterator::new(inner)))
    }

    /// Get a shareable [`Handle`] for this `Signals` instance.
    ///
    /// This can be used to add further signals or close the [`Signals`] instance
    /// which terminates the whole signal stream.
    pub fn handle(&self) -> Handle {
        self.0.handle()
    }
}

/// Simplified version of the signals stream.
///
/// This one simply returns the signal numbers, while [`SignalsInfo`] can provide additional
/// information.
pub type Signals = SignalsInfo<SignalOnly>;

impl Signals {
    fn has_signals(read: &mut UnixStream, ctx: &mut Context<'_>) -> Result<bool, Error> {
        let mut buf = [0u8];
        let mut read_buf = ReadBuf::new(&mut buf);
        match Pin::new(read).poll_read(ctx, &mut read_buf) {
            Poll::Pending => Ok(false),
            Poll::Ready(Ok(())) => Ok(true),
            Poll::Ready(Err(error)) => Err(error),
        }
    }
}

#[cfg_attr(docsrs, doc(cfg(feature = "futures-v0_3")))]
#[cfg(feature = "futures-v0_3")]
impl Stream for Signals {
    type Item = c_int;

    fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match self.0.poll_signal(&mut |read| Self::has_signals(read, ctx)) {
            PollResult::Signal(sig) => Poll::Ready(Some(sig)),
            PollResult::Closed => Poll::Ready(None),
            PollResult::Pending => Poll::Pending,
            PollResult::Err(error) => panic!("Unexpected error: {}", error),
        }
    }
}
<commit_msg>Fix example code<commit_after>#![doc(test(attr(deny(warnings))))]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(feature = "futures-v0_3"), allow(dead_code, unused_imports))]

//! A crate for integrating signal handling with the Tokio runtime.
//!
//! This provides the [`Signals`][Signals] struct which acts as a
//! [`Stream`] of signals.
//!
//! Note that the `futures-v0_3` feature of this crate must be
//! enabled for `Signals` to implement the `Stream` trait.
//!
//! # Example
//!
//! ```rust
//! # #[cfg(feature = "futures-v0_3")]
//! # mod test {
//! use std::io::Error;
//!
//! use signal_hook::consts::signal::*;
//! use signal_hook_tokio::Signals;
//!
//! use futures::stream::StreamExt;
//!
//! async fn handle_signals(signals: Signals) {
//!     let mut signals = signals.fuse();
//!     while let Some(signal) = signals.next().await {
//!         match signal {
//!             SIGHUP => {
//!                 // Reload configuration
//!                 // Reopen the log file
//!             }
//!             SIGTERM | SIGINT | SIGQUIT => {
//!                 // Shutdown the system;
//!             },
//!             _ => unreachable!(),
//!         }
//!     }
//! }
//!
//! #[tokio::main]
//! # pub
//! async fn main() -> Result<(), Error> {
//!     let signals = Signals::new(&[
//!         SIGHUP,
//!         SIGTERM,
//!         SIGINT,
//!         SIGQUIT,
//!     ])?;
//!     let handle = signals.handle();
//!
//!     let signals_task = tokio::spawn(handle_signals(signals));
//!
//!     // Execute your main program logic
//!
//!     // Terminate the signal stream.
//!     handle.close();
//!     signals_task.await?;
//!
//!     Ok(())
//! }
//! # }
//! # fn main() -> Result<(), std::io::Error> {
//! #    #[cfg(feature = "futures-v0_3")]
//! #    test::main()?;
//! #    Ok(())
//! # }
//! ```

use std::borrow::Borrow;
use std::io::Error;
use std::pin::Pin;
use std::task::{Context, Poll};

use libc::c_int;

use tokio::io::{AsyncRead, ReadBuf};
use tokio::net::UnixStream;

pub use signal_hook::iterator::backend::Handle;
use signal_hook::iterator::backend::{OwningSignalIterator, PollResult, SignalDelivery};
use signal_hook::iterator::exfiltrator::{Exfiltrator, SignalOnly};

#[cfg(feature = "futures-v0_3")]
use futures_core_0_3::Stream;

/// An asynchronous [`Stream`] of arriving signals.
///
/// The stream doesn't return the signals in the order they were recieved by
/// the process and may merge signals received multiple times.
pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(OwningSignalIterator<UnixStream, E>);

impl<E: Exfiltrator> SignalsInfo<E> {
    /// Create a `SignalsInfo` instance.
    ///
    /// This registers all the signals listed. The same restrictions (panics, errors) apply
    /// as with [`Handle::add_signal`].
    pub fn new<I, S>(signals: I) -> Result<Self, Error>
    where
        I: IntoIterator<Item = S>,
        S: Borrow<c_int>,
        E: Default,
    {
        Self::with_exfiltrator(signals, E::default())
    }

    /// A constructor with explicit exfiltrator.
    pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error>
    where
        I: IntoIterator<Item = S>,
        S: Borrow<c_int>,
    {
        let (read, write) = UnixStream::pair()?;
        let inner = SignalDelivery::with_pipe(read, write, exfiltrator, signals)?;
        Ok(Self(OwningSignalIterator::new(inner)))
    }

    /// Get a shareable [`Handle`] for this `Signals` instance.
    ///
    /// This can be used to add further signals or close the [`Signals`] instance
    /// which terminates the whole signal stream.
    pub fn handle(&self) -> Handle {
        self.0.handle()
    }
}

/// Simplified version of the signals stream.
///
/// This one simply returns the signal numbers, while [`SignalsInfo`] can provide additional
/// information.
pub type Signals = SignalsInfo<SignalOnly>;

impl Signals {
    fn has_signals(read: &mut UnixStream, ctx: &mut Context<'_>) -> Result<bool, Error> {
        let mut buf = [0u8];
        let mut read_buf = ReadBuf::new(&mut buf);
        match Pin::new(read).poll_read(ctx, &mut read_buf) {
            Poll::Pending => Ok(false),
            Poll::Ready(Ok(())) => Ok(true),
            Poll::Ready(Err(error)) => Err(error),
        }
    }
}

#[cfg_attr(docsrs, doc(cfg(feature = "futures-v0_3")))]
#[cfg(feature = "futures-v0_3")]
impl Stream for Signals {
    type Item = c_int;

    fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match self.0.poll_signal(&mut |read| Self::has_signals(read, ctx)) {
            PollResult::Signal(sig) => Poll::Ready(Some(sig)),
            PollResult::Closed => Poll::Ready(None),
            PollResult::Pending => Poll::Pending,
            PollResult::Err(error) => panic!("Unexpected error: {}", error),
        }
    }
}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::{NSUInteger, NSString};
use objc::runtime::{BOOL, NO, YES};
use sys::{MTLCreateSystemDefaultDevice, MTLCopyAllDevices, MTLDevice};
use std::borrow::Cow;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::ffi::CStr;
use {Size};

pub trait ReadOnlyDevice {
    fn is_depth24_stencil8_pixel_format_supported(&self) -> bool;
    fn is_headless(&self) -> bool;
    fn is_low_power(&self) -> bool;
    fn max_threads_per_group(&self) -> Size;
    fn get_name(&self) -> Cow<str>;
    fn supports_texture_sample_count(&self, sample_count: usize) -> bool;
}

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil {
            Ok(Device(device))
        } else {
            Err(DeviceError::ConstructionFailed)
        }
    }

    #[allow(unused_mut, unused_variables)]
    pub fn enumerate_all_system_devices() -> Vec<Result<Self, DeviceError>> {
        let all_devices = unsafe { MTLCopyAllDevices() };
        let mut devices_vec = vec![];

        devices_vec
    }

    pub unsafe fn into_raw(self) -> id {
        self.0
    }

    pub unsafe fn from_raw_unchecked(device_ptr: id) -> Self {
        Device(device_ptr)
    }

    pub fn from_raw(device_ptr: id) -> Result<Self, DeviceError> {
        #[link(name = "Foundation", kind = "framework")]
        extern {
            fn NSProtocolFromString(namestr: id) -> id;
        }

        let conforms_to_protocol: BOOL = unsafe {
            let mtl_device_protocol_str = NSString::alloc(nil).init_str("MTLDevice");
            let mtl_device_protocol = NSProtocolFromString(mtl_device_protocol_str);
            msg_send![device_ptr, conformsToProtocol:mtl_device_protocol]
        };

        if device_ptr == nil {
            Err(DeviceError::ConstructedFromNil)
        } else if conforms_to_protocol == NO {
            Err(DeviceError::ConstructedFromWrongPointerType)
        } else {
            Ok(Device(device_ptr))
        }
    }
}

impl ReadOnlyDevice for Device {
    fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    fn get_name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }
}

/// Internal utility function to get a Device's id without consuming it.
/// Not exported publicly from this crate.
#[doc(hidden)]
pub unsafe fn _device_get_raw(device: &Device) -> id {
    device.0
}

// TODO(George): Should this have a lifetime associated with it?
pub struct DeviceRef(id);

impl ReadOnlyDevice for DeviceRef {
    fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    fn get_name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }
}

/// Internal utility function to create a DeviceRef.
/// Not exported publicly from this crate.
#[doc(hidden)]
pub unsafe fn _make_device_ref(device: id) -> DeviceRef {
    DeviceRef(device)
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed,
    ConstructedFromNil,
    ConstructedFromWrongPointerType,
    OtherRuntimeError
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed",
            DeviceError::ConstructedFromNil => "DeviceError::ConstructedFromNil",
            DeviceError::ConstructedFromWrongPointerType => "DeviceError::ConstructedFromWrongPointerType",
            DeviceError::OtherRuntimeError => "DeviceError::OtherRuntimeError"
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed =>
                "Could not create a default device. Please ensure that you are using at least OSX 10.11 or iOS 8.0",
            DeviceError::ConstructedFromNil => "Attempted to create a device from a nil pointer",
            DeviceError::ConstructedFromWrongPointerType =>
                "Attempted to create a device from a pointer which does not implement MTLDevice",
            DeviceError::OtherRuntimeError => "An error occured in the Objective-C runtime"
        }
    }
}
<commit_msg>Add DeviceRef::is_reference_to(&self, &Device) fn<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::{NSUInteger, NSString};
use objc::runtime::{BOOL, NO, YES};
use sys::{MTLCreateSystemDefaultDevice, MTLCopyAllDevices, MTLDevice};
use std::borrow::Cow;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::ffi::CStr;
use {Size};

pub trait ReadOnlyDevice {
    fn is_depth24_stencil8_pixel_format_supported(&self) -> bool;
    fn is_headless(&self) -> bool;
    fn is_low_power(&self) -> bool;
    fn max_threads_per_group(&self) -> Size;
    fn get_name(&self) -> Cow<str>;
    fn supports_texture_sample_count(&self, sample_count: usize) -> bool;
}

pub struct Device(id);

impl Device {
    pub fn system_default_device() -> Result<Self, DeviceError> {
        let device = unsafe { MTLCreateSystemDefaultDevice() };
        if device != nil {
            Ok(Device(device))
        } else {
            Err(DeviceError::ConstructionFailed)
        }
    }

    #[allow(unused_mut, unused_variables)]
    pub fn enumerate_all_system_devices() -> Vec<Result<Self, DeviceError>> {
        let all_devices = unsafe { MTLCopyAllDevices() };
        let mut devices_vec = vec![];

        devices_vec
    }

    pub unsafe fn into_raw(self) -> id {
        self.0
    }

    pub unsafe fn from_raw_unchecked(device_ptr: id) -> Self {
        Device(device_ptr)
    }

    pub fn from_raw(device_ptr: id) -> Result<Self, DeviceError> {
        #[link(name = "Foundation", kind = "framework")]
        extern {
            fn NSProtocolFromString(namestr: id) -> id;
        }

        let conforms_to_protocol: BOOL = unsafe {
            let mtl_device_protocol_str = NSString::alloc(nil).init_str("MTLDevice");
            let mtl_device_protocol = NSProtocolFromString(mtl_device_protocol_str);
            msg_send![device_ptr, conformsToProtocol:mtl_device_protocol]
        };

        if device_ptr == nil {
            Err(DeviceError::ConstructedFromNil)
        } else if conforms_to_protocol == NO {
            Err(DeviceError::ConstructedFromWrongPointerType)
        } else {
            Ok(Device(device_ptr))
        }
    }
}

impl ReadOnlyDevice for Device {
    fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    fn get_name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }
}

/// Internal utility function to get a Device's id without consuming it.
/// Not exported publicly from this crate.
#[doc(hidden)]
pub unsafe fn _device_get_raw(device: &Device) -> id {
    device.0
}

// TODO(George): Should this have a lifetime associated with it?
pub struct DeviceRef(id);

impl DeviceRef {
    // TODO(George): Is this correct?
    pub fn is_reference_to(&self, device: &Device) -> bool {
        self.0 == device.0
    }
}

impl ReadOnlyDevice for DeviceRef {
    fn is_depth24_stencil8_pixel_format_supported(&self) -> bool {
        unsafe { self.0.depth24Stencil8PixelFormatSupported() == YES }
    }

    fn is_headless(&self) -> bool {
        unsafe { self.0.headless() == YES }
    }

    fn is_low_power(&self) -> bool {
        unsafe { self.0.lowPower() == YES }
    }

    fn max_threads_per_group(&self) -> Size {
        unsafe { self.0.maxThreadsPerGroup().into() }
    }

    fn get_name(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.name().UTF8String()).to_string_lossy() }
    }

    fn supports_texture_sample_count(&self, sample_count: usize) -> bool {
        unsafe { self.0.supportsTextureSampleCount(sample_count as NSUInteger) == YES }
    }
}

/// Internal utility function to create a DeviceRef.
/// Not exported publicly from this crate.
#[doc(hidden)]
pub unsafe fn _make_device_ref(device: id) -> DeviceRef {
    DeviceRef(device)
}

#[derive(Clone, Debug)]
pub enum DeviceError {
    ConstructionFailed,
    ConstructedFromNil,
    ConstructedFromWrongPointerType,
    OtherRuntimeError
}

impl Display for DeviceError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let descr = match *self {
            DeviceError::ConstructionFailed => "DeviceError::ConstructionFailed",
            DeviceError::ConstructedFromNil => "DeviceError::ConstructedFromNil",
            DeviceError::ConstructedFromWrongPointerType => "DeviceError::ConstructedFromWrongPointerType",
            DeviceError::OtherRuntimeError => "DeviceError::OtherRuntimeError"
        };
        write!(f, "{}", descr)
    }
}

impl Error for DeviceError {
    fn description(&self) -> &str {
        match *self {
            DeviceError::ConstructionFailed =>
                "Could not create a default device. Please ensure that you are using at least OSX 10.11 or iOS 8.0",
            DeviceError::ConstructedFromNil => "Attempted to create a device from a nil pointer",
            DeviceError::ConstructedFromWrongPointerType =>
                "Attempted to create a device from a pointer which does not implement MTLDevice",
            DeviceError::OtherRuntimeError => "An error occured in the Objective-C runtime"
        }
    }
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::ffi::CString;
use std::fs::File;
use std::os::raw::{c_char, c_int};

use rustc::middle::cstore::EncodedMetadata;
use rustc::mir::mono::{Linkage as RLinkage, Visibility};
use rustc::session::config::{DebugInfo, OutputType};
use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::CrateInfo;

use cranelift_faerie::*;

use crate::prelude::*;

pub fn codegen_crate(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
) -> Box<dyn Any> {
    tcx.sess.abort_if_errors();

    let mut log = if cfg!(debug_assertions) {
        Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
    } else {
        None
    };

    if std::env::var("SHOULD_RUN").is_ok()
        && tcx.sess.crate_types.get().contains(&CrateType::Executable)
    {
        #[cfg(not(target_arch = "wasm32"))]
        let _: ! = run_jit(tcx, &mut log);

        #[cfg(target_arch = "wasm32")]
        panic!("jit not supported on wasm");
    }

    run_aot(tcx, metadata, need_metadata_module, &mut log)
}

#[cfg(not(target_arch = "wasm32"))]
fn run_jit(tcx: TyCtxt<'_>, log: &mut Option<File>) -> ! {
    use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    let imported_symbols = load_imported_symbols_for_jit(tcx);

    let mut jit_builder = SimpleJITBuilder::with_isa(
        crate::build_isa(tcx.sess, false),
        cranelift_module::default_libcall_names(),
    );
    jit_builder.symbols(imported_symbols);
    let mut jit_module: Module<SimpleJITBackend> = Module::new(jit_builder);
    assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

    let sig = Signature {
        params: vec![
            AbiParam::new(jit_module.target_config().pointer_type()),
            AbiParam::new(jit_module.target_config().pointer_type()),
        ],
        returns: vec![AbiParam::new(
            jit_module.target_config().pointer_type(), /*isize*/
        )],
        call_conv: CallConv::SystemV,
    };
    let main_func_id = jit_module
        .declare_function("main", Linkage::Import, &sig)
        .unwrap();

    codegen_cgus(tcx, &mut jit_module, &mut None, log);
    crate::allocator::codegen(tcx.sess, &mut jit_module);
    jit_module.finalize_definitions();

    tcx.sess.abort_if_errors();

    let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);

    println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
        unsafe { ::std::mem::transmute(finalized_main) };

    let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new());
    let args = args
        .split(" ")
        .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()))
        .map(|arg| CString::new(arg).unwrap())
        .collect::<Vec<_>>();
    let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
    // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end

    let ret = f(args.len() as c_int, argv.as_ptr());

    jit_module.finish();
    std::process::exit(ret);
}

fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
    use rustc::middle::dependency_format::Linkage;

    let mut dylib_paths = Vec::new();

    let crate_info = CrateInfo::new(tcx);
    let formats = tcx.sess.dependency_formats.borrow();
    let data = formats.get(&CrateType::Executable).unwrap();
    for &(cnum, _) in &crate_info.used_crates_dynamic {
        let src = &crate_info.used_crate_source[&cnum];
        match data[cnum.as_usize() - 1] {
            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
            Linkage::Static => {
                let name = tcx.crate_name(cnum);
                let mut err = tcx
                    .sess
                    .struct_err(&format!("Can't load static lib {}", name.as_str()));
                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
                err.emit();
            }
            Linkage::Dynamic => {
                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
            }
        }
    }

    let mut imported_symbols = Vec::new();
    for path in dylib_paths {
        use object::Object;
        let lib = libloading::Library::new(&path).unwrap();
        let obj = std::fs::read(path).unwrap();
        let obj = object::File::parse(&obj).unwrap();
        imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| {
            let name = symbol.name().unwrap().to_string();
            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
                return None;
            }
            let symbol: libloading::Symbol<*const u8> =
                unsafe { lib.get(name.as_bytes()) }.unwrap();
            Some((name, *symbol))
        }));
        std::mem::forget(lib)
    }

    tcx.sess.abort_if_errors();

    imported_symbols
}

fn run_aot(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
    log: &mut Option<File>,
) -> Box<CodegenResults> {
    let new_module = |name: String| {
        let module: Module<FaerieBackend> = Module::new(
            FaerieBuilder::new(
                crate::build_isa(tcx.sess, true),
                name + ".o",
                FaerieTrapCollection::Disabled,
                cranelift_module::default_libcall_names(),
            )
            .unwrap(),
        );
        assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
        module
    };

    let emit_module = |name: &str,
                       kind: ModuleKind,
                       mut module: Module<FaerieBackend>,
                       debug: Option<DebugContext>| {
        module.finalize_definitions();
        let mut artifact = module.finish().artifact;

        if let Some(mut debug) = debug {
            debug.emit(&mut artifact);
        }

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Object, Some(name));
        let obj = artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();
        CompiledModule {
            name: name.to_string(),
            kind,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        }
    };

    let mut faerie_module = new_module("some_file".to_string());

    let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None
        // macOS debuginfo doesn't work yet (see #303)
        && !tcx.sess.target.target.options.is_like_osx
    {
        let debug = DebugContext::new(
            tcx,
            faerie_module.target_config().pointer_type().bytes() as u8,
        );
        Some(debug)
    } else {
        None
    };

    codegen_cgus(tcx, &mut faerie_module, &mut debug, log);

    tcx.sess.abort_if_errors();

    let mut allocator_module = new_module("allocator_shim.o".to_string());
    let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module);

    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));

    let metadata_module = if need_metadata_module {
        use rustc::mir::mono::CodegenUnitNameBuilder;

        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
        let metadata_cgu_name = cgu_name_builder
            .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
            .as_str()
            .to_string();

        let mut metadata_artifact = faerie::Artifact::new(
            crate::build_isa(tcx.sess, true).triple().clone(),
            metadata_cgu_name.clone(),
        );
        crate::metadata::write_metadata(tcx, &mut metadata_artifact);

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));

        let obj = metadata_artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();

        Some(CompiledModule {
            name: metadata_cgu_name,
            kind: ModuleKind::Metadata,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        })
    } else {
        None
    };

    Box::new(CodegenResults {
        crate_name: tcx.crate_name(LOCAL_CRATE),
        modules: vec![emit_module(
            "dummy_name",
            ModuleKind::Regular,
            faerie_module,
            debug,
        )],
        allocator_module: if created_alloc_shim {
            Some(emit_module(
                "allocator_shim",
                ModuleKind::Allocator,
                allocator_module,
                None,
            ))
        } else {
            None
        },
        metadata_module,
        crate_hash: tcx.crate_hash(LOCAL_CRATE),
        metadata,
        windows_subsystem: None, // Windows is not yet supported
        linker_info: LinkerInfo::new(tcx),
        crate_info: CrateInfo::new(tcx),
    })
}

fn codegen_cgus<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug: &mut Option<DebugContext<'tcx>>,
    log: &mut Option<File>,
) {
    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus
        .iter()
        .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
        .flatten()
        .collect::<FxHashMap<_, (_, _)>>();

    codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);

    crate::main_shim::maybe_create_entry_wrapper(tcx, module);
}

fn codegen_mono_items<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug_context: Option<&mut DebugContext<'tcx>>,
    log: &mut Option<File>,
    mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
) {
    let mut cx = CodegenCx::new(tcx, module, debug_context);
    time("codegen mono items", move || {
        for (mono_item, (linkage, visibility)) in mono_items {
            crate::unimpl::try_unimpl(tcx, log, || {
                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                trans_mono_item(&mut cx, mono_item, linkage);
            });
        }

        cx.finalize();
    });
}

fn trans_mono_item<'clif, 'tcx, B: Backend + 'static>(
    cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
    mono_item: MonoItem<'tcx>,
    linkage: Linkage,
) {
    let tcx = cx.tcx;
    match mono_item {
        MonoItem::Fn(inst) => {
            let _inst_guard =
                PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name.as_str()));
            debug_assert!(!inst.substs.needs_infer());
            let _mir_guard = PrintOnPanic(|| {
                match inst.def {
                    InstanceDef::Item(_)
                    | InstanceDef::DropGlue(_, _)
                    | InstanceDef::Virtual(_, _) => {
                        let mut mir = ::std::io::Cursor::new(Vec::new());
                        crate::rustc_mir::util::write_mir_pretty(
                            tcx,
                            Some(inst.def_id()),
                            &mut mir,
                        )
                        .unwrap();
                        String::from_utf8(mir.into_inner()).unwrap()
                    }
                    _ => {
                        // FIXME fix write_mir_pretty for these instances
                        format!("{:#?}", tcx.instance_mir(inst.def))
                    }
                }
            });

            crate::base::trans_fn(cx, inst, linkage);
        }
        MonoItem::Static(def_id) => {
            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
        }
        MonoItem::GlobalAsm(node_id) => tcx
            .sess
            .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)),
    }
}

fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
    println!("[{}] start", name);
    let before = std::time::Instant::now();
    let res = f();
    let after = std::time::Instant::now();
    println!("[{}] end time: {:?}", name, after - before);
    res
}
<commit_msg>Cleanup<commit_after>use std::any::Any;
use std::ffi::CString;
use std::fs::File;
use std::os::raw::{c_char, c_int};

use rustc::middle::cstore::EncodedMetadata;
use rustc::mir::mono::{Linkage as RLinkage, Visibility};
use rustc::session::config::{DebugInfo, OutputType};
use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::CrateInfo;

use cranelift_faerie::*;

use crate::prelude::*;

pub fn codegen_crate(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
) -> Box<dyn Any> {
    tcx.sess.abort_if_errors();

    let mut log = if cfg!(debug_assertions) {
        Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
    } else {
        None
    };

    if std::env::var("SHOULD_RUN").is_ok()
        && tcx.sess.crate_types.get().contains(&CrateType::Executable)
    {
        #[cfg(not(target_arch = "wasm32"))]
        let _: ! = run_jit(tcx, &mut log);

        #[cfg(target_arch = "wasm32")]
        panic!("jit not supported on wasm");
    }

    run_aot(tcx, metadata, need_metadata_module, &mut log)
}

#[cfg(not(target_arch = "wasm32"))]
fn run_jit(tcx: TyCtxt<'_>, log: &mut Option<File>) -> ! {
    use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    let imported_symbols = load_imported_symbols_for_jit(tcx);

    let mut jit_builder = SimpleJITBuilder::with_isa(
        crate::build_isa(tcx.sess, false),
        cranelift_module::default_libcall_names(),
    );
    jit_builder.symbols(imported_symbols);
    let mut jit_module: Module<SimpleJITBackend> = Module::new(jit_builder);
    assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

    let sig = Signature {
        params: vec![
            AbiParam::new(jit_module.target_config().pointer_type()),
            AbiParam::new(jit_module.target_config().pointer_type()),
        ],
        returns: vec![AbiParam::new(
            jit_module.target_config().pointer_type(), /*isize*/
        )],
        call_conv: CallConv::SystemV,
    };
    let main_func_id = jit_module
        .declare_function("main", Linkage::Import, &sig)
        .unwrap();

    codegen_cgus(tcx, &mut jit_module, &mut None, log);
    crate::allocator::codegen(tcx.sess, &mut jit_module);
    jit_module.finalize_definitions();

    tcx.sess.abort_if_errors();

    let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);

    println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
        unsafe { ::std::mem::transmute(finalized_main) };

    let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new());
    let args = args
        .split(" ")
        .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()))
        .map(|arg| CString::new(arg).unwrap())
        .collect::<Vec<_>>();
    let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
    // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end

    let ret = f(args.len() as c_int, argv.as_ptr());

    jit_module.finish();
    std::process::exit(ret);
}

fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
    use rustc::middle::dependency_format::Linkage;

    let mut dylib_paths = Vec::new();

    let crate_info = CrateInfo::new(tcx);
    let formats = tcx.sess.dependency_formats.borrow();
    let data = formats.get(&CrateType::Executable).unwrap();
    for &(cnum, _) in &crate_info.used_crates_dynamic {
        let src = &crate_info.used_crate_source[&cnum];
        match data[cnum.as_usize() - 1] {
            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
            Linkage::Static => {
                let name = tcx.crate_name(cnum);
                let mut err = tcx
                    .sess
                    .struct_err(&format!("Can't load static lib {}", name.as_str()));
                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
                err.emit();
            }
            Linkage::Dynamic => {
                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
            }
        }
    }

    let mut imported_symbols = Vec::new();
    for path in dylib_paths {
        use object::Object;
        let lib = libloading::Library::new(&path).unwrap();
        let obj = std::fs::read(path).unwrap();
        let obj = object::File::parse(&obj).unwrap();
        imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| {
            let name = symbol.name().unwrap().to_string();
            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
                return None;
            }
            let symbol: libloading::Symbol<*const u8> =
                unsafe { lib.get(name.as_bytes()) }.unwrap();
            Some((name, *symbol))
        }));
        std::mem::forget(lib)
    }

    tcx.sess.abort_if_errors();

    imported_symbols
}

fn run_aot(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
    log: &mut Option<File>,
) -> Box<CodegenResults> {
    let new_module = |name: String| {
        let module: Module<FaerieBackend> = Module::new(
            FaerieBuilder::new(
                crate::build_isa(tcx.sess, true),
                name + ".o",
                FaerieTrapCollection::Disabled,
                cranelift_module::default_libcall_names(),
            )
            .unwrap(),
        );
        assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
        module
    };

    let emit_module = |kind: ModuleKind,
                       mut module: Module<FaerieBackend>,
                       debug: Option<DebugContext>| {
        module.finalize_definitions();
        let mut artifact = module.finish().artifact;

        if let Some(mut debug) = debug {
            debug.emit(&mut artifact);
        }

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Object, Some(&artifact.name));
        let obj = artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();
        CompiledModule {
            name: artifact.name,
            kind,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        }
    };

    let mut faerie_module = new_module("some_file".to_string());

    let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None
        // macOS debuginfo doesn't work yet (see #303)
        && !tcx.sess.target.target.options.is_like_osx
    {
        let debug = DebugContext::new(
            tcx,
            faerie_module.target_config().pointer_type().bytes() as u8,
        );
        Some(debug)
    } else {
        None
    };

    codegen_cgus(tcx, &mut faerie_module, &mut debug, log);

    tcx.sess.abort_if_errors();

    let mut allocator_module = new_module("allocator_shim".to_string());
    let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module);

    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));

    let metadata_module = if need_metadata_module {
        use rustc::mir::mono::CodegenUnitNameBuilder;

        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
        let metadata_cgu_name = cgu_name_builder
            .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
            .as_str()
            .to_string();

        let mut metadata_artifact = faerie::Artifact::new(
            crate::build_isa(tcx.sess, true).triple().clone(),
            metadata_cgu_name.clone(),
        );
        crate::metadata::write_metadata(tcx, &mut metadata_artifact);

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));

        let obj = metadata_artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();

        Some(CompiledModule {
            name: metadata_cgu_name,
            kind: ModuleKind::Metadata,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        })
    } else {
        None
    };

    Box::new(CodegenResults {
        crate_name: tcx.crate_name(LOCAL_CRATE),
        modules: vec![emit_module(
            ModuleKind::Regular,
            faerie_module,
            debug,
        )],
        allocator_module: if created_alloc_shim {
            Some(emit_module(
                ModuleKind::Allocator,
                allocator_module,
                None,
            ))
        } else {
            None
        },
        metadata_module,
        crate_hash: tcx.crate_hash(LOCAL_CRATE),
        metadata,
        windows_subsystem: None, // Windows is not yet supported
        linker_info: LinkerInfo::new(tcx),
        crate_info: CrateInfo::new(tcx),
    })
}

fn codegen_cgus<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug: &mut Option<DebugContext<'tcx>>,
    log: &mut Option<File>,
) {
    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus
        .iter()
        .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
        .flatten()
        .collect::<FxHashMap<_, (_, _)>>();

    codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);

    crate::main_shim::maybe_create_entry_wrapper(tcx, module);
}

fn codegen_mono_items<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug_context: Option<&mut DebugContext<'tcx>>,
    log: &mut Option<File>,
    mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
) {
    let mut cx = CodegenCx::new(tcx, module, debug_context);
    time("codegen mono items", move || {
        for (mono_item, (linkage, visibility)) in mono_items {
            crate::unimpl::try_unimpl(tcx, log, || {
                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                trans_mono_item(&mut cx, mono_item, linkage);
            });
        }

        cx.finalize();
    });
}

fn trans_mono_item<'clif, 'tcx, B: Backend + 'static>(
    cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
    mono_item: MonoItem<'tcx>,
    linkage: Linkage,
) {
    let tcx = cx.tcx;
    match mono_item {
        MonoItem::Fn(inst) => {
            let _inst_guard =
                PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name.as_str()));
            debug_assert!(!inst.substs.needs_infer());
            let _mir_guard = PrintOnPanic(|| {
                match inst.def {
                    InstanceDef::Item(_)
                    | InstanceDef::DropGlue(_, _)
                    | InstanceDef::Virtual(_, _) => {
                        let mut mir = ::std::io::Cursor::new(Vec::new());
                        crate::rustc_mir::util::write_mir_pretty(
                            tcx,
                            Some(inst.def_id()),
                            &mut mir,
                        )
                        .unwrap();
                        String::from_utf8(mir.into_inner()).unwrap()
                    }
                    _ => {
                        // FIXME fix write_mir_pretty for these instances
                        format!("{:#?}", tcx.instance_mir(inst.def))
                    }
                }
            });

            crate::base::trans_fn(cx, inst, linkage);
        }
        MonoItem::Static(def_id) => {
            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
        }
        MonoItem::GlobalAsm(node_id) => tcx
            .sess
            .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)),
    }
}

fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
    println!("[{}] start", name);
    let before = std::time::Instant::now();
    let res = f();
    let after = std::time::Instant::now();
    println!("[{}] end time: {:?}", name, after - before);
    res
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::rc::Rc;

use vecmath;
use sprite;

use piston::event;
use sprite::Sprite;
use opengl_graphics::Texture;
use uuid::Uuid;

pub struct Player {
    loc: vecmath::Vector2<f64>,
    vel: vecmath::Vector2<f64>,
    sprite: Uuid,
}

impl Player {
    pub fn new(scene: &mut sprite::Scene<Texture>) -> Player {
        // load sprite
        let path = Path::new("./assets/playerShip1_red.png");
        let tex  = Rc::new(
            match Texture::from_path(&path) {
                Ok(tex) => tex,
                Err(_)  => { panic!("couldn't load texture from path"); },
            }
            );
        let sprite = Sprite::from_texture(tex.clone());

        // add sprite to scene
        let id = scene.add_child(sprite);

        Player{loc: [0.0, 0.0], vel: [0.0, 0.0], sprite: id}
    }
}

pub trait MobileUnit {
    fn update(&mut self, time_delta: f64);

    fn set_vel_x(&mut self, velX: f64);
    fn set_vel_y(&mut self, velY: f64);
}

impl MobileUnit for Player {
    fn update(&mut self, time_delta: f64) {
        self.loc = vecmath::vec2_add(self.loc.clone(),
            vecmath::vec2_scale(self.vel.clone(), time_delta));
    }
    fn set_vel_x(&mut self, vel_x: f64) {
        self.vel[0] = vel_x;
    }
    fn set_vel_y(&mut self, vel_y: f64) {
        self.vel[1] = vel_y;
    }
}

pub trait Drawable {
    fn draw(&self, scene: &mut sprite::Scene<Texture>, render_args: event::RenderArgs);
}

impl Drawable for Player {
    fn draw(&self, scene: &mut sprite::Scene<Texture>, render_args: event::RenderArgs) {
        let mut sprite = scene.child_mut(self.sprite)
            .expect("couldn't retrieve sprite asset");

        let rect = sprite.bounding_box();
        sprite.set_position(render_args.width as f64/2.0 + self.loc[0], render_args.height as f64 - self.loc[1] - rect[3]);
    }

}
<commit_msg>Reorganise entity module<commit_after>use std::path::Path;
use std::rc::Rc;

use vecmath;
use sprite;

use piston::event;
use sprite::Sprite;
use opengl_graphics::Texture;
use uuid::Uuid;

pub trait Drawable {
    fn draw(&self, scene: &mut sprite::Scene<Texture>, render_args: event::RenderArgs);
}

pub trait MobileUnit {
    fn update(&mut self, time_delta: f64);

    fn set_vel_x(&mut self, velX: f64);
    fn set_vel_y(&mut self, velY: f64);
}

pub struct Player {
    loc: vecmath::Vector2<f64>,
    vel: vecmath::Vector2<f64>,
    sprite: Uuid,
}

impl Player {
    pub fn new(scene: &mut sprite::Scene<Texture>) -> Player {
        // load sprite
        let path = Path::new("./assets/playerShip1_red.png");
        let tex  = Rc::new(
            match Texture::from_path(&path) {
                Ok(tex) => tex,
                Err(_)  => { panic!("couldn't load texture from path"); },
            }
            );
        let sprite = Sprite::from_texture(tex.clone());

        // add sprite to scene
        let id = scene.add_child(sprite);

        Player{loc: [0.0, 0.0], vel: [0.0, 0.0], sprite: id}
    }
}

impl MobileUnit for Player {
    fn update(&mut self, time_delta: f64) {
        self.loc = vecmath::vec2_add(self.loc.clone(),
            vecmath::vec2_scale(self.vel.clone(), time_delta));
    }
    fn set_vel_x(&mut self, vel_x: f64) {
        self.vel[0] = vel_x;
    }
    fn set_vel_y(&mut self, vel_y: f64) {
        self.vel[1] = vel_y;
    }
}

impl Drawable for Player {
    fn draw(&self, scene: &mut sprite::Scene<Texture>, render_args: event::RenderArgs) {
        let mut sprite = scene.child_mut(self.sprite)
            .expect("couldn't retrieve sprite asset");

        let rect = sprite.bounding_box();
        sprite.set_position(render_args.width as f64/2.0 + self.loc[0],
                            render_args.height as f64 - self.loc[1] - rect[3]);
    }

}
<|endoftext|>


<commit_before>use ndarray::Array1;
use geometry::Space;

/// An interface for dealing with functions that may be evaluated.
pub trait Function<I: ?Sized, O> {
    /// Evaluates the function and returns its output.
    fn evaluate(&self, input: &I) -> O;
}

impl<I: ?Sized, O, T> Function<I, O> for Box<T>
    where T: Function<I, O>
{
    fn evaluate(&self, input: &I) -> O {
        (**self).evaluate(input)
    }
}

/// An interface for dealing with adaptive functions.
pub trait Parameterised<I: ?Sized, E> {
    fn update(&mut self, input: &I, error: E);
}

impl<I: ?Sized, E, T> Parameterised<I, E> for Box<T>
    where T: Parameterised<I, E>
{
    fn update(&mut self, input: &I, error: E) {
        (**self).update(input, error)
    }
}

/// An interface for linearly parameterised functions.
pub trait Linear<S: Space> {
    fn phi(&self, input: &S::Repr) -> Array1<f64>;
}

/// An interface for value functions.
pub trait VFunction<S: Space>:
    Function<S::Repr, f64> + Parameterised<S::Repr, f64>
{
    fn evaluate_phi(&self, _: &Array1<f64>) -> f64 {
        unimplemented!()
    }

    fn update_phi(&mut self, _: &Array1<f64>, _: f64) {
        unimplemented!()
    }
}

impl<S: Space, T> VFunction<S> for Box<T>
    where T: VFunction<S>
{
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        (**self).evaluate_phi(phi)
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        (**self).update_phi(phi, error);
    }
}

/// An interface for action-value functions.
pub trait QFunction<S: Space>:
    Function<S::Repr, Vec<f64>> + Parameterised<S::Repr, Vec<f64>>
{
    fn evaluate_action(&self, input: &S::Repr, action: usize) -> f64;
    fn update_action(&mut self, input: &S::Repr, action: usize, error: f64);

    fn evaluate_phi(&self, _: &Array1<f64>) -> Vec<f64> {
        unimplemented!();
    }

    fn evaluate_action_phi(&self, _: &Array1<f64>, _: usize) -> f64 {
        unimplemented!();
    }

    fn update_phi(&mut self, _: &Array1<f64>, _: Vec<f64>) {
        unimplemented!();
    }

    fn update_action_phi(&mut self, _: &Array1<f64>, _: usize, _: f64) {
        unimplemented!();
    }

    // NOTE: Eventually we may want to distinguish between the feature vector
    //       for each action. I can't see this being needed anytime soon so
    //       for now we will just have a single entry point for computing phi.
    // fn phi(&self, input: &S::Repr) -> Array2<f64> {
        // unimplemented!()
    // }

    // fn phi_action(&self, input: &S::Repr, _: usize) -> Array1<f64>{
        // unimplemented!()
    // }

    // fn evaluate_phi(&self, phi: &Array2<f64>) -> f64 {
        // unimplemented!();
    // }

    // fn evaluate_action_phi(&self, phi: &Array1<f64>, action: usize) -> f64 {
        // unimplemented!();
    // }

    // fn update_phi(&mut self, phi: &Array2<f64>, error: f64) -> f64 {
        // unimplemented!();
    // }

    // fn update_action_phi(&mut self, phi: &Array1<f64>, action: usize, error: f64) -> f64 {
        // unimplemented!();
    // }
}

impl<S: Space, T> QFunction<S> for Box<T>
    where T: QFunction<S>
{
    fn evaluate_action(&self, input: &S::Repr, action: usize) -> f64 {
        (**self).evaluate_action(input, action)
    }

    fn update_action(&mut self, input: &S::Repr, action: usize, error: f64) {
        (**self).update_action(input, action, error);
    }

    fn evaluate_phi(&self, phi: &Array1<f64>) -> Vec<f64> {
        (**self).evaluate_phi(phi)
    }

    fn evaluate_action_phi(&self, phi: &Array1<f64>, action: usize) -> f64 {
        (**self).evaluate_action_phi(phi, action)
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: Vec<f64>) {
        (**self).update_phi(phi, error);
    }

    fn update_action_phi(&mut self, phi: &Array1<f64>, action: usize, error: f64) {
        (**self).update_action_phi(phi, action, error)
    }
}

mod fgroup;
pub use self::fgroup::VFunctionGroup;

mod table;
mod uniform_grid;
mod rbf_network;
mod basis_network;
// mod leaf;
mod sutton_tiles;

pub mod exact {
    pub use fa::table::*;
}

pub mod linear {
    pub use fa::uniform_grid::*;
    pub use fa::rbf_network::*;
    pub use fa::basis_network::*;
    pub use fa::sutton_tiles::*;
}

pub mod non_linear {
    // pub use fa::leaf::*;
}
<commit_msg>Move VFunctionGroup to new fa::misc module<commit_after>use ndarray::Array1;
use geometry::Space;

/// An interface for dealing with functions that may be evaluated.
pub trait Function<I: ?Sized, O> {
    /// Evaluates the function and returns its output.
    fn evaluate(&self, input: &I) -> O;
}

impl<I: ?Sized, O, T> Function<I, O> for Box<T>
    where T: Function<I, O>
{
    fn evaluate(&self, input: &I) -> O {
        (**self).evaluate(input)
    }
}

/// An interface for dealing with adaptive functions.
pub trait Parameterised<I: ?Sized, E> {
    fn update(&mut self, input: &I, error: E);
}

impl<I: ?Sized, E, T> Parameterised<I, E> for Box<T>
    where T: Parameterised<I, E>
{
    fn update(&mut self, input: &I, error: E) {
        (**self).update(input, error)
    }
}

/// An interface for linearly parameterised functions.
pub trait Linear<S: Space> {
    fn phi(&self, input: &S::Repr) -> Array1<f64>;
}

/// An interface for value functions.
pub trait VFunction<S: Space>:
    Function<S::Repr, f64> + Parameterised<S::Repr, f64>
{
    fn evaluate_phi(&self, _: &Array1<f64>) -> f64 {
        unimplemented!()
    }

    fn update_phi(&mut self, _: &Array1<f64>, _: f64) {
        unimplemented!()
    }
}

impl<S: Space, T> VFunction<S> for Box<T>
    where T: VFunction<S>
{
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        (**self).evaluate_phi(phi)
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        (**self).update_phi(phi, error);
    }
}

/// An interface for action-value functions.
pub trait QFunction<S: Space>:
    Function<S::Repr, Vec<f64>> + Parameterised<S::Repr, Vec<f64>>
{
    fn evaluate_action(&self, input: &S::Repr, action: usize) -> f64;
    fn update_action(&mut self, input: &S::Repr, action: usize, error: f64);

    fn evaluate_phi(&self, _: &Array1<f64>) -> Vec<f64> {
        unimplemented!();
    }

    fn evaluate_action_phi(&self, _: &Array1<f64>, _: usize) -> f64 {
        unimplemented!();
    }

    fn update_phi(&mut self, _: &Array1<f64>, _: Vec<f64>) {
        unimplemented!();
    }

    fn update_action_phi(&mut self, _: &Array1<f64>, _: usize, _: f64) {
        unimplemented!();
    }

    // NOTE: Eventually we may want to distinguish between the feature vector
    //       for each action. I can't see this being needed anytime soon so
    //       for now we will just have a single entry point for computing phi.
    // fn phi(&self, input: &S::Repr) -> Array2<f64> {
        // unimplemented!()
    // }

    // fn phi_action(&self, input: &S::Repr, _: usize) -> Array1<f64>{
        // unimplemented!()
    // }

    // fn evaluate_phi(&self, phi: &Array2<f64>) -> f64 {
        // unimplemented!();
    // }

    // fn evaluate_action_phi(&self, phi: &Array1<f64>, action: usize) -> f64 {
        // unimplemented!();
    // }

    // fn update_phi(&mut self, phi: &Array2<f64>, error: f64) -> f64 {
        // unimplemented!();
    // }

    // fn update_action_phi(&mut self, phi: &Array1<f64>, action: usize, error: f64) -> f64 {
        // unimplemented!();
    // }
}

impl<S: Space, T> QFunction<S> for Box<T>
    where T: QFunction<S>
{
    fn evaluate_action(&self, input: &S::Repr, action: usize) -> f64 {
        (**self).evaluate_action(input, action)
    }

    fn update_action(&mut self, input: &S::Repr, action: usize, error: f64) {
        (**self).update_action(input, action, error);
    }

    fn evaluate_phi(&self, phi: &Array1<f64>) -> Vec<f64> {
        (**self).evaluate_phi(phi)
    }

    fn evaluate_action_phi(&self, phi: &Array1<f64>, action: usize) -> f64 {
        (**self).evaluate_action_phi(phi, action)
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: Vec<f64>) {
        (**self).update_phi(phi, error);
    }

    fn update_action_phi(&mut self, phi: &Array1<f64>, action: usize, error: f64) {
        (**self).update_action_phi(phi, action, error)
    }
}

mod fgroup;
mod table;
mod uniform_grid;
mod rbf_network;
mod basis_network;
// mod leaf;
mod sutton_tiles;

pub mod exact {
    pub use fa::table::*;
}

pub mod linear {
    pub use fa::uniform_grid::*;
    pub use fa::rbf_network::*;
    pub use fa::basis_network::*;
    pub use fa::sutton_tiles::*;
}

pub mod non_linear {
    // pub use fa::leaf::*;
}

pub mod misc {
    pub use fa::fgroup::VFunctionGroup;
}
<|endoftext|>


<commit_before>//! The `filter` element.

use cssparser::{Parser, RGBA};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::slice::Iter;

use crate::coord_units::CoordUnits;
use crate::document::{AcquiredNodes, NodeId};
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::ValueErrorKind;
use crate::filter_func::FilterFunction;
use crate::filters::{FilterResolveError, FilterSpec, UserSpacePrimitive};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{Parse, ParseValue};
use crate::rect::Rect;
use crate::session::Session;
use crate::xml::Attributes;

/// The <filter> node.
pub struct Filter {
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: ULength<Horizontal>,
    height: ULength<Vertical>,
    filter_units: CoordUnits,
    primitive_units: CoordUnits,
}

/// A <filter> element definition in user-space coordinates.
pub struct UserSpaceFilter {
    pub rect: Rect,
    pub filter_units: CoordUnits,
    pub primitive_units: CoordUnits,
}

impl Default for Filter {
    /// Constructs a new `Filter` with default properties.
    fn default() -> Self {
        Self {
            x: Length::<Horizontal>::parse_str("-10%").unwrap(),
            y: Length::<Vertical>::parse_str("-10%").unwrap(),
            width: ULength::<Horizontal>::parse_str("120%").unwrap(),
            height: ULength::<Vertical>::parse_str("120%").unwrap(),
            filter_units: CoordUnits::ObjectBoundingBox,
            primitive_units: CoordUnits::UserSpaceOnUse,
        }
    }
}

impl Filter {
    pub fn get_filter_units(&self) -> CoordUnits {
        self.filter_units
    }

    pub fn to_user_space(&self, params: &NormalizeParams) -> UserSpaceFilter {
        let x = self.x.to_user(params);
        let y = self.y.to_user(params);
        let w = self.width.to_user(params);
        let h = self.height.to_user(params);

        let rect = Rect::new(x, y, x + w, y + h);

        UserSpaceFilter {
            rect,
            filter_units: self.filter_units,
            primitive_units: self.primitive_units,
        }
    }
}

impl SetAttributes for Filter {
    fn set_attributes(&mut self, attrs: &Attributes, _session: &Session) -> ElementResult {
        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "filterUnits") => self.filter_units = attr.parse(value)?,
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "primitiveUnits") => self.primitive_units = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Filter {}

#[derive(Debug, Clone, PartialEq)]
pub enum FilterValue {
    Url(NodeId),
    Function(FilterFunction),
}

impl FilterValue {
    pub fn to_filter_spec(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        user_space_params: &NormalizeParams,
        current_color: RGBA,
        draw_ctx: &DrawingCtx,
        node_being_filtered_name: &str,
    ) -> Result<FilterSpec, FilterResolveError> {
        match *self {
            FilterValue::Url(ref node_id) => filter_spec_from_filter_node(
                acquired_nodes,
                draw_ctx,
                node_id,
                node_being_filtered_name,
            ),

            FilterValue::Function(ref func) => {
                Ok(func.to_filter_spec(user_space_params, current_color))
            }
        }
    }
}

/// Holds the viewport parameters for both objectBoundingBox and userSpaceOnUse units.
///
/// When collecting a set of filter primitives (`feFoo`) into a [`FilterSpec`], which is
/// in user space, we need to convert each primitive's units into user space units.  So,
/// pre-compute both cases and pass them around.
///
/// This struct needs a better name; I didn't want to make it seem specific to filters by
/// calling `FiltersViewParams` or `FilterCollectionProcessViewParams`.  Maybe the
/// original [`ViewParams`] should be this struct, with both cases included...
pub struct ViewParamsGen {
    object_bounding_box: ViewParams,
    user_space_on_use: ViewParams,
}

impl ViewParamsGen {
    pub fn new(draw_ctx: &DrawingCtx) -> Self {
        ViewParamsGen {
            object_bounding_box: draw_ctx.get_view_params_for_units(CoordUnits::ObjectBoundingBox),
            user_space_on_use: draw_ctx.get_view_params_for_units(CoordUnits::UserSpaceOnUse),
        }
    }

    fn get(&self, units: CoordUnits) -> &ViewParams {
        match units {
            CoordUnits::ObjectBoundingBox => &self.object_bounding_box,
            CoordUnits::UserSpaceOnUse => &self.user_space_on_use,
        }
    }
}

fn extract_filter_from_filter_node(
    filter_node: &Node,
    acquired_nodes: &mut AcquiredNodes<'_>,
    session: &Session,
    filter_view_params: &ViewParamsGen,
) -> Result<FilterSpec, FilterResolveError> {
    assert!(is_element_of_type!(filter_node, Filter));

    let filter_element = filter_node.borrow_element();

    let user_space_filter = {
        let filter_values = filter_element.get_computed_values();

        let filter = borrow_element_as!(filter_node, Filter);

        filter.to_user_space(&NormalizeParams::new(
            filter_values,
            filter_view_params.get(filter.get_filter_units()),
        ))
    };

    let primitive_view_params = filter_view_params.get(user_space_filter.primitive_units);

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!(
                    session,
                    "(ignoring filter primitive {} because it is in error)",
                    c
                );
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        .map(|primitive_node| {
            let elt = primitive_node.borrow_element();
            let effect = elt.as_filter_effect().unwrap();

            let primitive_name = format!("{}", primitive_node);

            let primitive_values = elt.get_computed_values();
            let params = NormalizeParams::new(primitive_values, primitive_view_params);

            effect
                .resolve(acquired_nodes, &primitive_node)
                .map_err(|e| {
                    rsvg_log!(
                        session,
                        "(filter primitive {} returned an error: {})",
                        primitive_name,
                        e
                    );
                    e
                })
                .map(|primitive| primitive.into_user_space(&params))
        })
        .collect::<Result<Vec<UserSpacePrimitive>, FilterResolveError>>()?;

    Ok(FilterSpec {
        user_space_filter,
        primitives,
    })
}

fn filter_spec_from_filter_node(
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &DrawingCtx,
    node_id: &NodeId,
    node_being_filtered_name: &str,
) -> Result<FilterSpec, FilterResolveError> {
    let session = draw_ctx.session().clone();

    let filter_view_params = ViewParamsGen::new(draw_ctx);

    acquired_nodes
        .acquire(node_id)
        .map_err(|e| {
            rsvg_log!(
                session,
                "element {} will not be filtered with \"{}\": {}",
                node_being_filtered_name,
                node_id,
                e
            );
            FilterResolveError::ReferenceToNonFilterElement
        })
        .and_then(|acquired| {
            let node = acquired.get();
            let element = node.borrow_element();

            match *element {
                Element::Filter(_) => {
                    if element.is_in_error() {
                        rsvg_log!(
                            session,
                            "element {} will not be filtered since its filter \"{}\" is in error",
                            node_being_filtered_name,
                            node_id,
                        );
                        Err(FilterResolveError::ChildNodeInError)
                    } else {
                        extract_filter_from_filter_node(
                            node,
                            acquired_nodes,
                            &session,
                            &filter_view_params,
                        )
                    }
                }

                _ => {
                    rsvg_log!(
                        session,
                        "element {} will not be filtered since \"{}\" is not a filter",
                        node_being_filtered_name,
                        node_id,
                    );
                    Err(FilterResolveError::ReferenceToNonFilterElement)
                }
            }
        })
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct FilterValueList(Vec<FilterValue>);

impl FilterValueList {
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn iter(&self) -> Iter<'_, FilterValue> {
        self.0.iter()
    }
}

impl Parse for FilterValueList {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, crate::error::ParseError<'i>> {
        let mut result = FilterValueList::default();

        loop {
            let loc = parser.current_source_location();

            let filter_value = if let Ok(func) = parser.try_parse(|p| FilterFunction::parse(p)) {
                FilterValue::Function(func)
            } else {
                let url = parser.expect_url()?;
                let node_id = NodeId::parse(&url)
                    .map_err(|e| loc.new_custom_error(ValueErrorKind::from(e)))?;

                FilterValue::Url(node_id)
            };

            result.0.push(filter_value);

            if parser.is_exhausted() {
                break;
            }
        }

        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_filter_value_list() {
        let n1 = NodeId::External("foo.svg".to_string(), "bar".to_string());
        let n2 = NodeId::External("test.svg".to_string(), "baz".to_string());
        assert_eq!(
            FilterValueList::parse_str("url(foo.svg#bar) url(test.svg#baz)").unwrap(),
            FilterValueList(vec![FilterValue::Url(n1), FilterValue::Url(n2)])
        );
    }

    #[test]
    fn detects_invalid_filter_value_list() {
        assert!(FilterValueList::parse_str("none").is_err());
        assert!(FilterValueList::parse_str("").is_err());
        assert!(FilterValueList::parse_str("fail").is_err());
        assert!(FilterValueList::parse_str("url(#test) none").is_err());
    }
}
<commit_msg>filter.rs: use set_attribute()<commit_after>//! The `filter` element.

use cssparser::{Parser, RGBA};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::slice::Iter;

use crate::coord_units::CoordUnits;
use crate::document::{AcquiredNodes, NodeId};
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::element::{set_attribute, Draw, Element, ElementResult, SetAttributes};
use crate::error::ValueErrorKind;
use crate::filter_func::FilterFunction;
use crate::filters::{FilterResolveError, FilterSpec, UserSpacePrimitive};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{Parse, ParseValue};
use crate::rect::Rect;
use crate::session::Session;
use crate::xml::Attributes;

/// The <filter> node.
pub struct Filter {
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: ULength<Horizontal>,
    height: ULength<Vertical>,
    filter_units: CoordUnits,
    primitive_units: CoordUnits,
}

/// A <filter> element definition in user-space coordinates.
pub struct UserSpaceFilter {
    pub rect: Rect,
    pub filter_units: CoordUnits,
    pub primitive_units: CoordUnits,
}

impl Default for Filter {
    /// Constructs a new `Filter` with default properties.
    fn default() -> Self {
        Self {
            x: Length::<Horizontal>::parse_str("-10%").unwrap(),
            y: Length::<Vertical>::parse_str("-10%").unwrap(),
            width: ULength::<Horizontal>::parse_str("120%").unwrap(),
            height: ULength::<Vertical>::parse_str("120%").unwrap(),
            filter_units: CoordUnits::ObjectBoundingBox,
            primitive_units: CoordUnits::UserSpaceOnUse,
        }
    }
}

impl Filter {
    pub fn get_filter_units(&self) -> CoordUnits {
        self.filter_units
    }

    pub fn to_user_space(&self, params: &NormalizeParams) -> UserSpaceFilter {
        let x = self.x.to_user(params);
        let y = self.y.to_user(params);
        let w = self.width.to_user(params);
        let h = self.height.to_user(params);

        let rect = Rect::new(x, y, x + w, y + h);

        UserSpaceFilter {
            rect,
            filter_units: self.filter_units,
            primitive_units: self.primitive_units,
        }
    }
}

impl SetAttributes for Filter {
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) -> ElementResult {
        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "filterUnits") => {
                    set_attribute(&mut self.filter_units, attr.parse(value), session)
                }
                expanded_name!("", "x") => set_attribute(&mut self.x, attr.parse(value), session),
                expanded_name!("", "y") => set_attribute(&mut self.y, attr.parse(value), session),
                expanded_name!("", "width") => {
                    set_attribute(&mut self.width, attr.parse(value), session)
                }
                expanded_name!("", "height") => {
                    set_attribute(&mut self.height, attr.parse(value), session)
                }
                expanded_name!("", "primitiveUnits") => {
                    set_attribute(&mut self.primitive_units, attr.parse(value), session)
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Filter {}

#[derive(Debug, Clone, PartialEq)]
pub enum FilterValue {
    Url(NodeId),
    Function(FilterFunction),
}

impl FilterValue {
    pub fn to_filter_spec(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        user_space_params: &NormalizeParams,
        current_color: RGBA,
        draw_ctx: &DrawingCtx,
        node_being_filtered_name: &str,
    ) -> Result<FilterSpec, FilterResolveError> {
        match *self {
            FilterValue::Url(ref node_id) => filter_spec_from_filter_node(
                acquired_nodes,
                draw_ctx,
                node_id,
                node_being_filtered_name,
            ),

            FilterValue::Function(ref func) => {
                Ok(func.to_filter_spec(user_space_params, current_color))
            }
        }
    }
}

/// Holds the viewport parameters for both objectBoundingBox and userSpaceOnUse units.
///
/// When collecting a set of filter primitives (`feFoo`) into a [`FilterSpec`], which is
/// in user space, we need to convert each primitive's units into user space units.  So,
/// pre-compute both cases and pass them around.
///
/// This struct needs a better name; I didn't want to make it seem specific to filters by
/// calling `FiltersViewParams` or `FilterCollectionProcessViewParams`.  Maybe the
/// original [`ViewParams`] should be this struct, with both cases included...
pub struct ViewParamsGen {
    object_bounding_box: ViewParams,
    user_space_on_use: ViewParams,
}

impl ViewParamsGen {
    pub fn new(draw_ctx: &DrawingCtx) -> Self {
        ViewParamsGen {
            object_bounding_box: draw_ctx.get_view_params_for_units(CoordUnits::ObjectBoundingBox),
            user_space_on_use: draw_ctx.get_view_params_for_units(CoordUnits::UserSpaceOnUse),
        }
    }

    fn get(&self, units: CoordUnits) -> &ViewParams {
        match units {
            CoordUnits::ObjectBoundingBox => &self.object_bounding_box,
            CoordUnits::UserSpaceOnUse => &self.user_space_on_use,
        }
    }
}

fn extract_filter_from_filter_node(
    filter_node: &Node,
    acquired_nodes: &mut AcquiredNodes<'_>,
    session: &Session,
    filter_view_params: &ViewParamsGen,
) -> Result<FilterSpec, FilterResolveError> {
    assert!(is_element_of_type!(filter_node, Filter));

    let filter_element = filter_node.borrow_element();

    let user_space_filter = {
        let filter_values = filter_element.get_computed_values();

        let filter = borrow_element_as!(filter_node, Filter);

        filter.to_user_space(&NormalizeParams::new(
            filter_values,
            filter_view_params.get(filter.get_filter_units()),
        ))
    };

    let primitive_view_params = filter_view_params.get(user_space_filter.primitive_units);

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!(
                    session,
                    "(ignoring filter primitive {} because it is in error)",
                    c
                );
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        .map(|primitive_node| {
            let elt = primitive_node.borrow_element();
            let effect = elt.as_filter_effect().unwrap();

            let primitive_name = format!("{}", primitive_node);

            let primitive_values = elt.get_computed_values();
            let params = NormalizeParams::new(primitive_values, primitive_view_params);

            effect
                .resolve(acquired_nodes, &primitive_node)
                .map_err(|e| {
                    rsvg_log!(
                        session,
                        "(filter primitive {} returned an error: {})",
                        primitive_name,
                        e
                    );
                    e
                })
                .map(|primitive| primitive.into_user_space(&params))
        })
        .collect::<Result<Vec<UserSpacePrimitive>, FilterResolveError>>()?;

    Ok(FilterSpec {
        user_space_filter,
        primitives,
    })
}

fn filter_spec_from_filter_node(
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &DrawingCtx,
    node_id: &NodeId,
    node_being_filtered_name: &str,
) -> Result<FilterSpec, FilterResolveError> {
    let session = draw_ctx.session().clone();

    let filter_view_params = ViewParamsGen::new(draw_ctx);

    acquired_nodes
        .acquire(node_id)
        .map_err(|e| {
            rsvg_log!(
                session,
                "element {} will not be filtered with \"{}\": {}",
                node_being_filtered_name,
                node_id,
                e
            );
            FilterResolveError::ReferenceToNonFilterElement
        })
        .and_then(|acquired| {
            let node = acquired.get();
            let element = node.borrow_element();

            match *element {
                Element::Filter(_) => {
                    if element.is_in_error() {
                        rsvg_log!(
                            session,
                            "element {} will not be filtered since its filter \"{}\" is in error",
                            node_being_filtered_name,
                            node_id,
                        );
                        Err(FilterResolveError::ChildNodeInError)
                    } else {
                        extract_filter_from_filter_node(
                            node,
                            acquired_nodes,
                            &session,
                            &filter_view_params,
                        )
                    }
                }

                _ => {
                    rsvg_log!(
                        session,
                        "element {} will not be filtered since \"{}\" is not a filter",
                        node_being_filtered_name,
                        node_id,
                    );
                    Err(FilterResolveError::ReferenceToNonFilterElement)
                }
            }
        })
}

#[derive(Debug, Default, Clone, PartialEq)]
pub struct FilterValueList(Vec<FilterValue>);

impl FilterValueList {
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn iter(&self) -> Iter<'_, FilterValue> {
        self.0.iter()
    }
}

impl Parse for FilterValueList {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, crate::error::ParseError<'i>> {
        let mut result = FilterValueList::default();

        loop {
            let loc = parser.current_source_location();

            let filter_value = if let Ok(func) = parser.try_parse(|p| FilterFunction::parse(p)) {
                FilterValue::Function(func)
            } else {
                let url = parser.expect_url()?;
                let node_id = NodeId::parse(&url)
                    .map_err(|e| loc.new_custom_error(ValueErrorKind::from(e)))?;

                FilterValue::Url(node_id)
            };

            result.0.push(filter_value);

            if parser.is_exhausted() {
                break;
            }
        }

        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_filter_value_list() {
        let n1 = NodeId::External("foo.svg".to_string(), "bar".to_string());
        let n2 = NodeId::External("test.svg".to_string(), "baz".to_string());
        assert_eq!(
            FilterValueList::parse_str("url(foo.svg#bar) url(test.svg#baz)").unwrap(),
            FilterValueList(vec![FilterValue::Url(n1), FilterValue::Url(n2)])
        );
    }

    #[test]
    fn detects_invalid_filter_value_list() {
        assert!(FilterValueList::parse_str("none").is_err());
        assert!(FilterValueList::parse_str("").is_err());
        assert!(FilterValueList::parse_str("fail").is_err());
        assert!(FilterValueList::parse_str("url(#test) none").is_err());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly", feature(lang_items, start))]
#![no_std]

#[cfg(feature = "nightly")]
use core::panic::PanicInfo;

extern crate libc;

#[cfg(feature = "nightly")]
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    let _magenta = palette::Srgb::new(255u8, 0, 255);

    0
}

#[cfg(feature = "nightly")]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[cfg(feature = "nightly")]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[cfg(not(feature = "nightly"))]
fn main() {}
<commit_msg>Fix no_std_test<commit_after>#![cfg_attr(feature = "nightly", feature(lang_items, start))]
#![no_std]

#[cfg(feature = "nightly")]
use core::panic::PanicInfo;

extern crate libc;

#[cfg(feature = "nightly")]
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    let _magenta = palette::Srgb::new(255u8, 0, 255);

    0
}

#[cfg(feature = "nightly")]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[cfg(feature = "nightly")]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[cfg(feature = "nightly")]
#[no_mangle]
pub unsafe fn __aeabi_unwind_cpp_pr0() -> () {
    loop {}
}

#[cfg(not(feature = "nightly"))]
fn main() {}
<|endoftext|>


<commit_before>// main.rs
// Main entry point for a Rust version
// of some (micro-) benchmarks
//
// vim: ft=rust sw=4 ts=4
//

extern crate image;
extern crate num;
extern crate num_complex;
extern crate rayon;
extern crate time;

use time::precise_time_ns;

// declare submodules
mod fibonacci;
mod mandelbrot;
mod perfect_number;

#[cfg(test)]
mod test {
    mod test_fib;
    mod test_pn;
}

// a helper function to time closures
fn time_it<F, T>(fun: F) -> (T, u64)
where
    F: Fn() -> T,
{
    let tic = precise_time_ns();
    let res = fun();
    let toc = precise_time_ns();

    (res, (toc - tic) / 1_000_000)
}

fn main() {
    println!("Rust benchmarks");
    println!("===============");

    println!();

    println!("Fibonacci numbers:");
    println!("------------------");

    let (res, elap) = time_it(|| fibonacci::fib_naive(35));
    println!("fib_naive(35) = {}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| fibonacci::fib(35));
    println!("fib(35) = {}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| fibonacci::fib(1000));
    println!("fib(1000) = {}\tElapsed: {}ms", res, elap);

    println!();

    println!("Perfect numbers:");
    println!("----------------");

    let (res, elap) = time_it(|| perfect_number::perfect_numbers(10000));
    println!("pn(10000) = {:?}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| perfect_number::perfect_number_iter(4));
    println!("pn_iter(4) = {:?}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| perfect_number::perfect_numbers_rayon(10000));
    println!("pn_rayon(10000) = {:?}\tElapsed: {}ms", res, elap);

    println!();

    println!("Mandelbrot set:");
    println!("--------------");

    let (res, elap) = time_it(|| mandelbrot::mandelbrot(640, 480, -0.5, 0.0, 4.0 / f64::from(640)));
    println!("mandelbrot(640, 480) done\tElapsed: {}ms", elap);
    let (_, elap) = time_it(|| res.save("./mandelbrot.png").unwrap());
    println!("mandelbrot(640, 480) written to PNG\tElapsed: {}ms", elap);

    let (res, elap) =
        time_it(|| mandelbrot::mandelbrot(1920, 1200, -0.5, 0.0, 4.0 / f64::from(1920)));
    println!("mandelbrot(1920, 1200) done\tElapsed: {}ms", elap);
    let (_, elap) = time_it(|| res.save("./mandelbrot.png").unwrap());
    println!("mandelbrot(1920, 1200) written to PNG\tElapsed: {}ms", elap);

    let _: Vec<()> = vec![2, 4, 8]
        .into_iter()
        .map(|i| {
            let (_res, elap) = time_it(|| {
                mandelbrot::mandelbrot_rayon(1920, 1200, -0.5, 0.0, 4.0 / f64::from(1920), i)
            });
            println!("mandelbrot_rayon(1920, 1200, {}) done\tElapsed: {}ms", i, elap);
        })
        .collect();

    let (_, elap) = time_it(|| res.save("./mandelbrot.png").unwrap());
    println!(
        "mandelbrot_rayon(1920, 1200) written to PNG\tElapsed: {}ms",
        elap
    );
    println!();

    println!("------------------");
    println!("Done!");
}
<commit_msg>more multithread variants<commit_after>// main.rs
// Main entry point for a Rust version
// of some (micro-) benchmarks
//
// vim: ft=rust sw=4 ts=4
//

extern crate image;
extern crate num;
extern crate num_complex;
extern crate rayon;
extern crate time;

use time::precise_time_ns;

// declare submodules
mod fibonacci;
mod mandelbrot;
mod perfect_number;

#[cfg(test)]
mod test {
    mod test_fib;
    mod test_pn;
}

// a helper function to time closures
fn time_it<F, T>(fun: F) -> (T, u64)
where
    F: Fn() -> T,
{
    let tic = precise_time_ns();
    let res = fun();
    let toc = precise_time_ns();

    (res, (toc - tic) / 1_000_000)
}

fn main() {
    println!("Rust benchmarks");
    println!("===============");

    println!();

    println!("Fibonacci numbers:");
    println!("------------------");

    let (res, elap) = time_it(|| fibonacci::fib_naive(35));
    println!("fib_naive(35) = {}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| fibonacci::fib(35));
    println!("fib(35) = {}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| fibonacci::fib(1000));
    println!("fib(1000) = {}\tElapsed: {}ms", res, elap);

    println!();

    println!("Perfect numbers:");
    println!("----------------");

    let (res, elap) = time_it(|| perfect_number::perfect_numbers(10000));
    println!("pn(10000) = {:?}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| perfect_number::perfect_number_iter(4));
    println!("pn_iter(4) = {:?}\tElapsed: {}ms", res, elap);

    let (res, elap) = time_it(|| perfect_number::perfect_numbers_rayon(10000));
    println!("pn_rayon(10000) = {:?}\tElapsed: {}ms", res, elap);

    println!();

    println!("Mandelbrot set:");
    println!("--------------");

    let (res, elap) = time_it(|| mandelbrot::mandelbrot(640, 480, -0.5, 0.0, 4.0 / f64::from(640)));
    println!("mandelbrot(640, 480) done\tElapsed: {}ms", elap);
    let (_, elap) = time_it(|| res.save("./mandelbrot.png").unwrap());
    println!("mandelbrot(640, 480) written to PNG\tElapsed: {}ms", elap);

    let (res, elap) =
        time_it(|| mandelbrot::mandelbrot(1920, 1200, -0.5, 0.0, 4.0 / f64::from(1920)));
    println!("mandelbrot(1920, 1200) done\tElapsed: {}ms", elap);
    let (_, elap) = time_it(|| res.save("./mandelbrot.png").unwrap());
    println!("mandelbrot(1920, 1200) written to PNG\tElapsed: {}ms", elap);

    let _: Vec<()> = vec![1, 2, 4, 8, 16, 30, 40]
        .into_iter()
        .map(|i| {
            let (_res, elap) = time_it(|| {
                mandelbrot::mandelbrot_rayon(1920, 1200, -0.5, 0.0, 4.0 / f64::from(1920), i)
            });
            println!("mandelbrot_rayon(1920, 1200, {}) done\tElapsed: {}ms", i, elap);
        })
        .collect();

    let (_, elap) = time_it(|| res.save("./mandelbrot.png").unwrap());
    println!(
        "mandelbrot_rayon(1920, 1200) written to PNG\tElapsed: {}ms",
        elap
    );
    println!();

    println!("------------------");
    println!("Done!");
}
<|endoftext|>