<commit_before>use crate::back::write::create_informational_target_machine;
use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
use std::ffi::{CStr, CString};

use std::slice;
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len();
    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
    let mut llvm_args = Vec::with_capacity(n_args + 1);

    llvm::LLVMRustInstallFatalErrorHandler();

    fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
        full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
    }

    let cg_opts = sess.opts.cg.llvm_args.iter();
    let tg_opts = sess.target.llvm_args.iter();
    let sess_args = cg_opts.chain(tg_opts);

    let user_specified_args: FxHashSet<_> =
        sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect();

    {
        // This adds the given argument to LLVM. Unless `force` is true
        // user specified arguments are *not* overridden.
        let mut add = |arg: &str, force: bool| {
            if force || !user_specified_args.contains(llvm_arg_to_arg_name(arg)) {
                let s = CString::new(arg).unwrap();
                llvm_args.push(s.as_ptr());
                llvm_c_strs.push(s);
            }
        };
        // Set the llvm "program name" to make usage and invalid argument messages more clear.
        add("rustc -Cllvm-args=\"...\" with", true);
        if sess.time_llvm_passes() {
            add("-time-passes", false);
        }
        if sess.print_llvm_passes() {
            add("-debug-pass=Structure", false);
        }
        if !sess.opts.debugging_opts.no_generate_arange_section {
            add("-generate-arange-section", false);
        }
        match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
            MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
            MergeFunctions::Aliases => {
                add("-mergefunc-use-aliases", false);
            }
        }

        if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
            add("-enable-emscripten-cxx-exceptions", false);
        }

        // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
        // during inlining. Unfortunately these may block other optimizations.
        add("-preserve-alignment-assumptions-during-inlining=false", false);

        for arg in sess_args {
            add(&(*arg), true);
        }
    }

    if sess.opts.debugging_opts.llvm_time_trace {
        // time-trace is not thread safe and running it in parallel will cause seg faults.
        if !sess.opts.debugging_opts.no_parallel_llvm {
            bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
        }

        llvm::LLVMTimeTraceProfilerInitialize();
    }

    llvm::LLVMInitializePasses();

    rustc_llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
}

pub fn time_trace_profiler_finish(file_name: &str) {
    unsafe {
        let file_name = CString::new(file_name).unwrap();
        llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr());
    }
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def
// where the * matches the architecture's name
// Beware to not use the llvm github project for this, but check the git submodule
// found in src/llvm-project
// Though note that Rust can also be build with an external precompiled version of LLVM
// which might lead to failures if the oldest tested / supported LLVM version
// doesn't yet support the relevant intrinsics
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
    match (arch, s) {
        ("x86", "pclmulqdq") => "pclmul",
        ("x86", "rdrand") => "rdrnd",
        ("x86", "bmi1") => "bmi",
        ("x86", "cmpxchg16b") => "cx16",
        ("x86", "avx512vaes") => "vaes",
        ("x86", "avx512gfni") => "gfni",
        ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
        ("aarch64", "fp") => "fp-armv8",
        ("aarch64", "fp16") => "fullfp16",
        (_, s) => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_informational_target_machine(sess);
    supported_target_features(sess)
        .iter()
        .filter_map(
            |&(feature, gate)| {
                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
            },
        )
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(sess, feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature))
        .collect()
}

pub fn print_version() {
    let (major, minor, patch) = get_version();
    println!("LLVM version: {}.{}.{}", major, minor, patch);
}

pub fn get_version() -> (u32, u32, u32) {
    // Can be called without initializing LLVM
    unsafe {
        (llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch())
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe {
        llvm::LLVMRustPrintPasses();
    }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_informational_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
        }
    }
}

fn handle_native(name: &str) -> &str {
    if name != "native" {
        return name;
    }

    unsafe {
        let mut len = 0;
        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
    }
}

pub fn target_cpu(sess: &Session) -> &str {
    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
    handle_native(name)
}

/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
// FIXME(nagisa): Cache the output of this somehow? Maybe make this a query? We're calling this
// for every function that has `#[target_feature]` on it. The global features won't change between
// the functions; only crates, maybe…
pub fn llvm_global_features(sess: &Session) -> Vec<String> {
    // FIXME(nagisa): this should definitely be available more centrally and to other codegen backends.
    /// These features control behaviour of rustc rather than llvm.
    const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];

    // Features that come earlier are overriden by conflicting features later in the string.
    // Typically we'll want more explicit settings to override the implicit ones, so:
    //
    // * Features from -Ctarget-cpu=*; are overriden by [^1]
    // * Features implied by --target; are overriden by
    // * Features from -Ctarget-feature; are overriden by
    // * function specific features.
    //
    // [^1]: target-cpu=native is handled here, other target-cpu values are handled implicitly
    // through LLVM TargetMachine implementation.
    //
    // FIXME(nagisa): it isn't clear what's the best interaction between features implied by
    // `-Ctarget-cpu` and `--target` are. On one hand, you'd expect CLI arguments to always
    // override anything that's implicit, so e.g. when there's no `--target` flag, features implied
    // the host target are overriden by `-Ctarget-cpu=*`. On the other hand, what about when both
    // `--target` and `-Ctarget-cpu=*` are specified? Both then imply some target features and both
    // flags are specified by the user on the CLI. It isn't as clear-cut which order of precedence
    // should be taken in cases like these.
    let mut features = vec![];

    // -Ctarget-cpu=native
    match sess.opts.cg.target_cpu {
        Some(ref s) if s == "native" => {
            let features_string = unsafe {
                let ptr = llvm::LLVMGetHostCPUFeatures();
                let features_string = if !ptr.is_null() {
                    CStr::from_ptr(ptr)
                        .to_str()
                        .unwrap_or_else(|e| {
                            bug!("LLVM returned a non-utf8 features string: {}", e);
                        })
                        .to_owned()
                } else {
                    bug!("could not allocate host CPU features, LLVM returned a `null` string");
                };

                llvm::LLVMDisposeMessage(ptr);

                features_string
            };
            features.extend(features_string.split(",").map(String::from));
        }
        Some(_) | None => {}
    };

    // Features implied by an implicit or explicit `--target`.
    features.extend(
        sess.target
            .features
            .split(',')
            .filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
            .map(String::from),
    );

    // -Ctarget-features
    features.extend(
        sess.opts
            .cg
            .target_feature
            .split(',')
            .filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
            .map(String::from),
    );

    features
}

pub fn tune_cpu(sess: &Session) -> Option<&str> {
    let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
    Some(handle_native(name))
}
<commit_msg>Auto merge of #82980 - tmiasko:import-cold-multiplier, r=michaelwoerister<commit_after>use crate::back::write::create_informational_target_machine;
use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
use std::ffi::{CStr, CString};

use std::slice;
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len();
    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
    let mut llvm_args = Vec::with_capacity(n_args + 1);

    llvm::LLVMRustInstallFatalErrorHandler();

    fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
        full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
    }

    let cg_opts = sess.opts.cg.llvm_args.iter();
    let tg_opts = sess.target.llvm_args.iter();
    let sess_args = cg_opts.chain(tg_opts);

    let user_specified_args: FxHashSet<_> =
        sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect();

    {
        // This adds the given argument to LLVM. Unless `force` is true
        // user specified arguments are *not* overridden.
        let mut add = |arg: &str, force: bool| {
            if force || !user_specified_args.contains(llvm_arg_to_arg_name(arg)) {
                let s = CString::new(arg).unwrap();
                llvm_args.push(s.as_ptr());
                llvm_c_strs.push(s);
            }
        };
        // Set the llvm "program name" to make usage and invalid argument messages more clear.
        add("rustc -Cllvm-args=\"...\" with", true);
        if sess.time_llvm_passes() {
            add("-time-passes", false);
        }
        if sess.print_llvm_passes() {
            add("-debug-pass=Structure", false);
        }
        if !sess.opts.debugging_opts.no_generate_arange_section {
            add("-generate-arange-section", false);
        }
        match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
            MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
            MergeFunctions::Aliases => {
                add("-mergefunc-use-aliases", false);
            }
        }

        if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
            add("-enable-emscripten-cxx-exceptions", false);
        }

        // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
        // during inlining. Unfortunately these may block other optimizations.
        add("-preserve-alignment-assumptions-during-inlining=false", false);

        // Use non-zero `import-instr-limit` multiplier for cold callsites.
        add("-import-cold-multiplier=0.1", false);

        for arg in sess_args {
            add(&(*arg), true);
        }
    }

    if sess.opts.debugging_opts.llvm_time_trace {
        // time-trace is not thread safe and running it in parallel will cause seg faults.
        if !sess.opts.debugging_opts.no_parallel_llvm {
            bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
        }

        llvm::LLVMTimeTraceProfilerInitialize();
    }

    llvm::LLVMInitializePasses();

    rustc_llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
}

pub fn time_trace_profiler_finish(file_name: &str) {
    unsafe {
        let file_name = CString::new(file_name).unwrap();
        llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr());
    }
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def
// where the * matches the architecture's name
// Beware to not use the llvm github project for this, but check the git submodule
// found in src/llvm-project
// Though note that Rust can also be build with an external precompiled version of LLVM
// which might lead to failures if the oldest tested / supported LLVM version
// doesn't yet support the relevant intrinsics
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
    match (arch, s) {
        ("x86", "pclmulqdq") => "pclmul",
        ("x86", "rdrand") => "rdrnd",
        ("x86", "bmi1") => "bmi",
        ("x86", "cmpxchg16b") => "cx16",
        ("x86", "avx512vaes") => "vaes",
        ("x86", "avx512gfni") => "gfni",
        ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
        ("aarch64", "fp") => "fp-armv8",
        ("aarch64", "fp16") => "fullfp16",
        (_, s) => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_informational_target_machine(sess);
    supported_target_features(sess)
        .iter()
        .filter_map(
            |&(feature, gate)| {
                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
            },
        )
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(sess, feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature))
        .collect()
}

pub fn print_version() {
    let (major, minor, patch) = get_version();
    println!("LLVM version: {}.{}.{}", major, minor, patch);
}

pub fn get_version() -> (u32, u32, u32) {
    // Can be called without initializing LLVM
    unsafe {
        (llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch())
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe {
        llvm::LLVMRustPrintPasses();
    }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_informational_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
        }
    }
}

fn handle_native(name: &str) -> &str {
    if name != "native" {
        return name;
    }

    unsafe {
        let mut len = 0;
        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
    }
}

pub fn target_cpu(sess: &Session) -> &str {
    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
    handle_native(name)
}

/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
// FIXME(nagisa): Cache the output of this somehow? Maybe make this a query? We're calling this
// for every function that has `#[target_feature]` on it. The global features won't change between
// the functions; only crates, maybe…
pub fn llvm_global_features(sess: &Session) -> Vec<String> {
    // FIXME(nagisa): this should definitely be available more centrally and to other codegen backends.
    /// These features control behaviour of rustc rather than llvm.
    const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];

    // Features that come earlier are overriden by conflicting features later in the string.
    // Typically we'll want more explicit settings to override the implicit ones, so:
    //
    // * Features from -Ctarget-cpu=*; are overriden by [^1]
    // * Features implied by --target; are overriden by
    // * Features from -Ctarget-feature; are overriden by
    // * function specific features.
    //
    // [^1]: target-cpu=native is handled here, other target-cpu values are handled implicitly
    // through LLVM TargetMachine implementation.
    //
    // FIXME(nagisa): it isn't clear what's the best interaction between features implied by
    // `-Ctarget-cpu` and `--target` are. On one hand, you'd expect CLI arguments to always
    // override anything that's implicit, so e.g. when there's no `--target` flag, features implied
    // the host target are overriden by `-Ctarget-cpu=*`. On the other hand, what about when both
    // `--target` and `-Ctarget-cpu=*` are specified? Both then imply some target features and both
    // flags are specified by the user on the CLI. It isn't as clear-cut which order of precedence
    // should be taken in cases like these.
    let mut features = vec![];

    // -Ctarget-cpu=native
    match sess.opts.cg.target_cpu {
        Some(ref s) if s == "native" => {
            let features_string = unsafe {
                let ptr = llvm::LLVMGetHostCPUFeatures();
                let features_string = if !ptr.is_null() {
                    CStr::from_ptr(ptr)
                        .to_str()
                        .unwrap_or_else(|e| {
                            bug!("LLVM returned a non-utf8 features string: {}", e);
                        })
                        .to_owned()
                } else {
                    bug!("could not allocate host CPU features, LLVM returned a `null` string");
                };

                llvm::LLVMDisposeMessage(ptr);

                features_string
            };
            features.extend(features_string.split(",").map(String::from));
        }
        Some(_) | None => {}
    };

    // Features implied by an implicit or explicit `--target`.
    features.extend(
        sess.target
            .features
            .split(',')
            .filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
            .map(String::from),
    );

    // -Ctarget-features
    features.extend(
        sess.opts
            .cg
            .target_feature
            .split(',')
            .filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
            .map(String::from),
    );

    features
}

pub fn tune_cpu(sess: &Session) -> Option<&str> {
    let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
    Some(handle_native(name))
}
<|endoftext|>


<commit_before>// Copyright (C) 2017-2018 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Module that contains all types needed for creating a direct subclass of `GObject`
//! or implementing virtual methods of it.
use ffi;
use gobject_ffi;

use std::mem;
use std::ptr;

use translate::*;
use {Closure, Object, ObjectClass, Type, Value};

use super::prelude::*;
use super::types;

#[macro_export]
/// Macro for boilerplate of [`ObjectImpl`] implementations
///
/// [`ObjectImpl`]: subclass/object/trait.ObjectImpl.html
macro_rules! glib_object_impl {
    () => {
        fn get_type_data(&self) -> ::std::ptr::NonNull<$crate::subclass::TypeData> {
            Self::type_data()
        }
    };
}

/// Trait for implementors of `glib::Object` subclasses
///
/// This allows overriding the virtual methods of `glib::Object`
pub trait ObjectImpl: 'static {
    /// Storage for the type-specific data used during registration
    ///
    /// This is usually generated by the [`object_impl!`] macro.
    ///
    /// [`object_impl!`]: ../../macro.glib_object_impl.html
    fn get_type_data(&self) -> ptr::NonNull<types::TypeData>;

    /// Property setter
    ///
    /// This is called whenever the property of this specific subclass with the
    /// given index is set. The new value is passed as `glib::Value`.
    fn set_property(&self, _obj: &Object, _id: usize, _value: &Value) {
        unimplemented!()
    }

    /// Property getter
    ///
    /// This is called whenever the property value of the specific subclass with the
    /// given index should be returned.
    fn get_property(&self, _obj: &Object, _id: usize) -> Result<Value, ()> {
        unimplemented!()
    }

    /// Constructed
    ///
    /// This is called once construction of the instance is finished.
    ///
    /// Should chain up to the parent class' implementation.
    fn constructed(&self, obj: &Object) {
        self.parent_constructed(obj);
    }

    /// Chain up to the parent class' implementation of `glib::Object::constructed()`
    ///
    /// Do not override this, it has no effect.
    fn parent_constructed(&self, obj: &Object) {
        unsafe {
            let data = self.get_type_data();
            let parent_class = data.as_ref().get_parent_class() as *mut gobject_ffi::GObjectClass;

            if let Some(ref func) = (*parent_class).constructed {
                func(obj.to_glib_none().0);
            }
        }
    }
}

unsafe extern "C" fn get_property<T: ObjectSubclass>(
    obj: *mut gobject_ffi::GObject,
    id: u32,
    value: *mut gobject_ffi::GValue,
    _pspec: *mut gobject_ffi::GParamSpec,
) {
    glib_floating_reference_guard!(obj);
    let instance = &*(obj as *mut T::Instance);
    let imp = instance.get_impl();

    match imp.get_property(&from_glib_borrow(obj), (id - 1) as usize) {
        Ok(v) => {
            // Here we overwrite the value directly with ours
            // and forget ours because otherwise we would do
            // an additional copy of the value, which for
            // non-refcounted types involves a deep copy
            gobject_ffi::g_value_unset(value);
            ptr::write(value, ptr::read(v.to_glib_none().0));
            mem::forget(v);
        }
        Err(()) => eprintln!("Failed to get property"),
    }
}

unsafe extern "C" fn set_property<T: ObjectSubclass>(
    obj: *mut gobject_ffi::GObject,
    id: u32,
    value: *mut gobject_ffi::GValue,
    _pspec: *mut gobject_ffi::GParamSpec,
) {
    glib_floating_reference_guard!(obj);
    let instance = &*(obj as *mut T::Instance);
    let imp = instance.get_impl();
    imp.set_property(&from_glib_borrow(obj), (id - 1) as usize, &*(value as *mut Value));
}

unsafe extern "C" fn constructed<T: ObjectSubclass>(obj: *mut gobject_ffi::GObject) {
    glib_floating_reference_guard!(obj);
    let instance = &*(obj as *mut T::Instance);
    let imp = instance.get_impl();

    imp.constructed(&from_glib_borrow(obj));
}

/// Definition of a property
pub struct Property<'a>(pub &'a str, pub fn() -> ::ParamSpec);

/// Extension trait for `glib::Object`'s class struct
///
/// This contains various class methods and allows subclasses to override the virtual methods.
pub unsafe trait ObjectClassSubclassExt: Sized + 'static {
    /// Install properties on the subclass
    ///
    /// The index in the properties array is going to be the index passed to the
    /// property setters and getters.
    fn install_properties(&mut self, properties: &[Property]) {
        if properties.is_empty() {
            return;
        }

        let mut pspecs = Vec::with_capacity(properties.len());

        for property in properties {
            let pspec = (property.1)();
            assert_eq!(property.0, pspec.get_name());
            pspecs.push(pspec);
        }

        unsafe {
            let mut pspecs_ptrs = Vec::with_capacity(properties.len());

            pspecs_ptrs.push(ptr::null_mut());

            for pspec in &pspecs {
                pspecs_ptrs.push(pspec.to_glib_none().0);
            }

            gobject_ffi::g_object_class_install_properties(
                self as *mut _ as *mut gobject_ffi::GObjectClass,
                pspecs_ptrs.len() as u32,
                pspecs_ptrs.as_mut_ptr(),
            );
        }
    }

    /// Add a new signal to the subclass
    ///
    /// This can be emitted later by `glib::Object::emit` and external code
    /// can connect to the signal to get notified about emissions.
    fn add_signal(&mut self, name: &str, arg_types: &[Type], ret_type: Type) {
        let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
        unsafe {
            gobject_ffi::g_signal_newv(
                name.to_glib_none().0,
                *(self as *mut _ as *mut ffi::GType),
                gobject_ffi::G_SIGNAL_RUN_LAST,
                ptr::null_mut(),
                None,
                ptr::null_mut(),
                None,
                ret_type.to_glib(),
                arg_types.len() as u32,
                arg_types.as_ptr() as *mut _,
            );
        }
    }

    /// Add a new signal with accumulator to the subclass
    ///
    /// This can be emitted later by `glib::Object::emit` and external code
    /// can connect to the signal to get notified about emissions.
    ///
    /// The accumulator function is used for accumulating the return values of
    /// multiple signal handlers. The new value is passed as second argument and
    /// should be combined with the old value in the first argument. If no further
    /// signal handlers should be called, `false` should be returned.
    fn add_signal_with_accumulator<F>(
        &mut self,
        name: &str,
        arg_types: &[Type],
        ret_type: Type,
        accumulator: F,
    ) where
        F: Fn(&mut Value, &Value) -> bool + Send + Sync + 'static,
    {
        let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();

        let accumulator: Box<Box<Fn(&mut Value, &Value) -> bool + Send + Sync + 'static>> =
            Box::new(Box::new(accumulator));

        unsafe extern "C" fn accumulator_trampoline(
            _ihint: *mut gobject_ffi::GSignalInvocationHint,
            return_accu: *mut gobject_ffi::GValue,
            handler_return: *const gobject_ffi::GValue,
            data: ffi::gpointer,
        ) -> ffi::gboolean {
            let accumulator: &&(Fn(&mut Value, &Value) -> bool + Send + Sync + 'static) =
                &*(data as *const &(Fn(&mut Value, &Value) -> bool + Send + Sync + 'static));
            accumulator(
                &mut *(return_accu as *mut Value),
                &*(handler_return as *const Value),
            )
            .to_glib()
        }

        unsafe {
            gobject_ffi::g_signal_newv(
                name.to_glib_none().0,
                *(self as *mut _ as *mut ffi::GType),
                gobject_ffi::G_SIGNAL_RUN_LAST,
                ptr::null_mut(),
                Some(accumulator_trampoline),
                Box::into_raw(accumulator) as ffi::gpointer,
                None,
                ret_type.to_glib(),
                arg_types.len() as u32,
                arg_types.as_ptr() as *mut _,
            );
        }
    }

    /// Add a new action signal with accumulator to the subclass
    ///
    /// Different to normal signals, action signals are supposed to be emitted
    /// by external code and will cause the provided handler to be called.
    ///
    /// It can be thought of as a dynamic function call.
    fn add_action_signal<F>(&mut self, name: &str, arg_types: &[Type], ret_type: Type, handler: F)
    where
        F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static,
    {
        let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
        let handler = Closure::new(handler);
        unsafe {
            gobject_ffi::g_signal_newv(
                name.to_glib_none().0,
                *(self as *mut _ as *mut ffi::GType),
                gobject_ffi::G_SIGNAL_RUN_LAST | gobject_ffi::G_SIGNAL_ACTION,
                handler.to_glib_none().0,
                None,
                ptr::null_mut(),
                None,
                ret_type.to_glib(),
                arg_types.len() as u32,
                arg_types.as_ptr() as *mut _,
            );
        }
    }
}

unsafe impl ObjectClassSubclassExt for ObjectClass {}

unsafe impl<T: ObjectSubclass> IsSubclassable<T> for ObjectClass {
    fn override_vfuncs(&mut self) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gobject_ffi::GObjectClass);
            klass.set_property = Some(set_property::<T>);
            klass.get_property = Some(get_property::<T>);
            klass.constructed = Some(constructed::<T>);
        }
    }
}

#[cfg(test)]
mod test {
    use super::super::super::object::ObjectExt;
    use super::super::super::subclass;
    use super::super::super::value::{ToValue, Value};
    use super::*;

    use std::cell::RefCell;

    static PROPERTIES: [Property; 1] = [Property("name", || {
        ::ParamSpec::string(
            "name",
            "Name",
            "Name of this object",
            None,
            ::ParamFlags::READWRITE,
        )
    })];

    pub struct SimpleObject {
        name: RefCell<Option<String>>,
    }

    impl SimpleObject {
        glib_object_get_type!();
    }

    impl ObjectSubclass for SimpleObject {
        const NAME: &'static str = "SimpleObject";
        type ParentType = Object;
        type Instance = subclass::simple::InstanceStruct<Self>;
        type Class = subclass::simple::ClassStruct<Self>;

        glib_object_subclass!();

        fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
            klass.install_properties(&PROPERTIES);
        }

        fn new() -> Self {
            Self {
                name: RefCell::new(None),
            }
        }
    }

    impl ObjectImpl for SimpleObject {
        glib_object_impl!();

        fn set_property(&self, _obj: &Object, id: usize, value: &Value) {
            let prop = &PROPERTIES[id];

            match *prop {
                Property("name", ..) => {
                    let name = value.get();
                    self.name.replace(name.clone());
                }
                _ => unimplemented!(),
            }
        }

        fn get_property(&self, _obj: &Object, id: usize) -> Result<Value, ()> {
            let prop = &PROPERTIES[id];

            match *prop {
                Property("name", ..) => Ok(self.name.borrow().clone().to_value()),
                _ => unimplemented!(),
            }
        }

        fn constructed(&self, obj: &Object) {
            self.parent_constructed(obj);
        }
    }

    #[test]
    fn test_create() {
        let type_ = SimpleObject::get_type();
        let obj = Object::new(type_, &[]).unwrap();

        assert_eq!(obj.get_property("name").unwrap().get::<&str>(), None);
        obj.set_property("name", &"test").unwrap();
        assert_eq!(
            obj.get_property("name").unwrap().get::<&str>(),
            Some("test")
        );

        let weak = obj.downgrade();
        drop(obj);
        assert!(weak.upgrade().is_none());
    }
}
<commit_msg>Extend Object subclassing unit test to check if the constructed virtual method is actually called<commit_after>// Copyright (C) 2017-2018 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Module that contains all types needed for creating a direct subclass of `GObject`
//! or implementing virtual methods of it.
use ffi;
use gobject_ffi;

use std::mem;
use std::ptr;

use translate::*;
use {Closure, Object, ObjectClass, Type, Value};

use super::prelude::*;
use super::types;

#[macro_export]
/// Macro for boilerplate of [`ObjectImpl`] implementations
///
/// [`ObjectImpl`]: subclass/object/trait.ObjectImpl.html
macro_rules! glib_object_impl {
    () => {
        fn get_type_data(&self) -> ::std::ptr::NonNull<$crate::subclass::TypeData> {
            Self::type_data()
        }
    };
}

/// Trait for implementors of `glib::Object` subclasses
///
/// This allows overriding the virtual methods of `glib::Object`
pub trait ObjectImpl: 'static {
    /// Storage for the type-specific data used during registration
    ///
    /// This is usually generated by the [`object_impl!`] macro.
    ///
    /// [`object_impl!`]: ../../macro.glib_object_impl.html
    fn get_type_data(&self) -> ptr::NonNull<types::TypeData>;

    /// Property setter
    ///
    /// This is called whenever the property of this specific subclass with the
    /// given index is set. The new value is passed as `glib::Value`.
    fn set_property(&self, _obj: &Object, _id: usize, _value: &Value) {
        unimplemented!()
    }

    /// Property getter
    ///
    /// This is called whenever the property value of the specific subclass with the
    /// given index should be returned.
    fn get_property(&self, _obj: &Object, _id: usize) -> Result<Value, ()> {
        unimplemented!()
    }

    /// Constructed
    ///
    /// This is called once construction of the instance is finished.
    ///
    /// Should chain up to the parent class' implementation.
    fn constructed(&self, obj: &Object) {
        self.parent_constructed(obj);
    }

    /// Chain up to the parent class' implementation of `glib::Object::constructed()`
    ///
    /// Do not override this, it has no effect.
    fn parent_constructed(&self, obj: &Object) {
        unsafe {
            let data = self.get_type_data();
            let parent_class = data.as_ref().get_parent_class() as *mut gobject_ffi::GObjectClass;

            if let Some(ref func) = (*parent_class).constructed {
                func(obj.to_glib_none().0);
            }
        }
    }
}

unsafe extern "C" fn get_property<T: ObjectSubclass>(
    obj: *mut gobject_ffi::GObject,
    id: u32,
    value: *mut gobject_ffi::GValue,
    _pspec: *mut gobject_ffi::GParamSpec,
) {
    glib_floating_reference_guard!(obj);
    let instance = &*(obj as *mut T::Instance);
    let imp = instance.get_impl();

    match imp.get_property(&from_glib_borrow(obj), (id - 1) as usize) {
        Ok(v) => {
            // Here we overwrite the value directly with ours
            // and forget ours because otherwise we would do
            // an additional copy of the value, which for
            // non-refcounted types involves a deep copy
            gobject_ffi::g_value_unset(value);
            ptr::write(value, ptr::read(v.to_glib_none().0));
            mem::forget(v);
        }
        Err(()) => eprintln!("Failed to get property"),
    }
}

unsafe extern "C" fn set_property<T: ObjectSubclass>(
    obj: *mut gobject_ffi::GObject,
    id: u32,
    value: *mut gobject_ffi::GValue,
    _pspec: *mut gobject_ffi::GParamSpec,
) {
    glib_floating_reference_guard!(obj);
    let instance = &*(obj as *mut T::Instance);
    let imp = instance.get_impl();
    imp.set_property(
        &from_glib_borrow(obj),
        (id - 1) as usize,
        &*(value as *mut Value),
    );
}

unsafe extern "C" fn constructed<T: ObjectSubclass>(obj: *mut gobject_ffi::GObject) {
    glib_floating_reference_guard!(obj);
    let instance = &*(obj as *mut T::Instance);
    let imp = instance.get_impl();

    imp.constructed(&from_glib_borrow(obj));
}

/// Definition of a property
pub struct Property<'a>(pub &'a str, pub fn() -> ::ParamSpec);

/// Extension trait for `glib::Object`'s class struct
///
/// This contains various class methods and allows subclasses to override the virtual methods.
pub unsafe trait ObjectClassSubclassExt: Sized + 'static {
    /// Install properties on the subclass
    ///
    /// The index in the properties array is going to be the index passed to the
    /// property setters and getters.
    fn install_properties(&mut self, properties: &[Property]) {
        if properties.is_empty() {
            return;
        }

        let mut pspecs = Vec::with_capacity(properties.len());

        for property in properties {
            let pspec = (property.1)();
            assert_eq!(property.0, pspec.get_name());
            pspecs.push(pspec);
        }

        unsafe {
            let mut pspecs_ptrs = Vec::with_capacity(properties.len());

            pspecs_ptrs.push(ptr::null_mut());

            for pspec in &pspecs {
                pspecs_ptrs.push(pspec.to_glib_none().0);
            }

            gobject_ffi::g_object_class_install_properties(
                self as *mut _ as *mut gobject_ffi::GObjectClass,
                pspecs_ptrs.len() as u32,
                pspecs_ptrs.as_mut_ptr(),
            );
        }
    }

    /// Add a new signal to the subclass
    ///
    /// This can be emitted later by `glib::Object::emit` and external code
    /// can connect to the signal to get notified about emissions.
    fn add_signal(&mut self, name: &str, arg_types: &[Type], ret_type: Type) {
        let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
        unsafe {
            gobject_ffi::g_signal_newv(
                name.to_glib_none().0,
                *(self as *mut _ as *mut ffi::GType),
                gobject_ffi::G_SIGNAL_RUN_LAST,
                ptr::null_mut(),
                None,
                ptr::null_mut(),
                None,
                ret_type.to_glib(),
                arg_types.len() as u32,
                arg_types.as_ptr() as *mut _,
            );
        }
    }

    /// Add a new signal with accumulator to the subclass
    ///
    /// This can be emitted later by `glib::Object::emit` and external code
    /// can connect to the signal to get notified about emissions.
    ///
    /// The accumulator function is used for accumulating the return values of
    /// multiple signal handlers. The new value is passed as second argument and
    /// should be combined with the old value in the first argument. If no further
    /// signal handlers should be called, `false` should be returned.
    fn add_signal_with_accumulator<F>(
        &mut self,
        name: &str,
        arg_types: &[Type],
        ret_type: Type,
        accumulator: F,
    ) where
        F: Fn(&mut Value, &Value) -> bool + Send + Sync + 'static,
    {
        let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();

        let accumulator: Box<Box<Fn(&mut Value, &Value) -> bool + Send + Sync + 'static>> =
            Box::new(Box::new(accumulator));

        unsafe extern "C" fn accumulator_trampoline(
            _ihint: *mut gobject_ffi::GSignalInvocationHint,
            return_accu: *mut gobject_ffi::GValue,
            handler_return: *const gobject_ffi::GValue,
            data: ffi::gpointer,
        ) -> ffi::gboolean {
            let accumulator: &&(Fn(&mut Value, &Value) -> bool + Send + Sync + 'static) =
                &*(data as *const &(Fn(&mut Value, &Value) -> bool + Send + Sync + 'static));
            accumulator(
                &mut *(return_accu as *mut Value),
                &*(handler_return as *const Value),
            )
            .to_glib()
        }

        unsafe {
            gobject_ffi::g_signal_newv(
                name.to_glib_none().0,
                *(self as *mut _ as *mut ffi::GType),
                gobject_ffi::G_SIGNAL_RUN_LAST,
                ptr::null_mut(),
                Some(accumulator_trampoline),
                Box::into_raw(accumulator) as ffi::gpointer,
                None,
                ret_type.to_glib(),
                arg_types.len() as u32,
                arg_types.as_ptr() as *mut _,
            );
        }
    }

    /// Add a new action signal with accumulator to the subclass
    ///
    /// Different to normal signals, action signals are supposed to be emitted
    /// by external code and will cause the provided handler to be called.
    ///
    /// It can be thought of as a dynamic function call.
    fn add_action_signal<F>(&mut self, name: &str, arg_types: &[Type], ret_type: Type, handler: F)
    where
        F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static,
    {
        let arg_types = arg_types.iter().map(|t| t.to_glib()).collect::<Vec<_>>();
        let handler = Closure::new(handler);
        unsafe {
            gobject_ffi::g_signal_newv(
                name.to_glib_none().0,
                *(self as *mut _ as *mut ffi::GType),
                gobject_ffi::G_SIGNAL_RUN_LAST | gobject_ffi::G_SIGNAL_ACTION,
                handler.to_glib_none().0,
                None,
                ptr::null_mut(),
                None,
                ret_type.to_glib(),
                arg_types.len() as u32,
                arg_types.as_ptr() as *mut _,
            );
        }
    }
}

unsafe impl ObjectClassSubclassExt for ObjectClass {}

unsafe impl<T: ObjectSubclass> IsSubclassable<T> for ObjectClass {
    fn override_vfuncs(&mut self) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gobject_ffi::GObjectClass);
            klass.set_property = Some(set_property::<T>);
            klass.get_property = Some(get_property::<T>);
            klass.constructed = Some(constructed::<T>);
        }
    }
}

#[cfg(test)]
mod test {
    use super::super::super::object::ObjectExt;
    use super::super::super::subclass;
    use super::super::super::value::{ToValue, Value};
    use super::*;

    use std::cell::RefCell;

    static PROPERTIES: [Property; 2] = [
        Property("name", || {
            ::ParamSpec::string(
                "name",
                "Name",
                "Name of this object",
                None,
                ::ParamFlags::READWRITE,
            )
        }),
        Property("constructed", || {
            ::ParamSpec::boolean(
                "constructed",
                "Constructed",
                "True if the constructed() virtual method was called",
                false,
                ::ParamFlags::READABLE,
            )
        }),
    ];

    pub struct SimpleObject {
        name: RefCell<Option<String>>,
        constructed: RefCell<bool>,
    }

    impl SimpleObject {
        glib_object_get_type!();
    }

    impl ObjectSubclass for SimpleObject {
        const NAME: &'static str = "SimpleObject";
        type ParentType = Object;
        type Instance = subclass::simple::InstanceStruct<Self>;
        type Class = subclass::simple::ClassStruct<Self>;

        glib_object_subclass!();

        fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
            klass.install_properties(&PROPERTIES);
        }

        fn new() -> Self {
            Self {
                name: RefCell::new(None),
                constructed: RefCell::new(false),
            }
        }
    }

    impl ObjectImpl for SimpleObject {
        glib_object_impl!();

        fn set_property(&self, _obj: &Object, id: usize, value: &Value) {
            let prop = &PROPERTIES[id];

            match *prop {
                Property("name", ..) => {
                    let name = value.get();
                    self.name.replace(name.clone());
                }
                _ => unimplemented!(),
            }
        }

        fn get_property(&self, _obj: &Object, id: usize) -> Result<Value, ()> {
            let prop = &PROPERTIES[id];

            match *prop {
                Property("name", ..) => Ok(self.name.borrow().clone().to_value()),
                Property("constructed", ..) => Ok(self.constructed.borrow().clone().to_value()),
                _ => unimplemented!(),
            }
        }

        fn constructed(&self, obj: &Object) {
            self.parent_constructed(obj);
            *self.constructed.borrow_mut() = true;
        }
    }

    #[test]
    fn test_create() {
        let type_ = SimpleObject::get_type();
        let obj = Object::new(type_, &[]).unwrap();

        assert_eq!(
            obj.get_property("constructed").unwrap().get::<bool>(),
            Some(true)
        );

        assert_eq!(obj.get_property("name").unwrap().get::<&str>(), None);
        obj.set_property("name", &"test").unwrap();
        assert_eq!(
            obj.get_property("name").unwrap().get::<&str>(),
            Some("test")
        );

        let weak = obj.downgrade();
        drop(obj);
        assert!(weak.upgrade().is_none());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        match self.cp.get_many(&mut self.statuses[..], timeout) {
            Err(ref e) if e.raw_os_error() == Some(258) => Ok(()), // winapi::WAIT_TIMEOUT
            Err(e) => Err(e),
            Ok(statuses) => {
                for status in statuses {
                    let token = status.token();
                    let overlapped = status.overlapped();
                    let bytes_transferred = status.bytes_transferred();
                    let handle = Handle { val: token };
                    if self.observers[handle].read_overlapped == overlapped {
                        match self.observers[handle].read_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                    if self.observers[handle].write_overlapped == overlapped {
                        match self.observers[handle].write_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                }
                Ok(())
            }
        }

    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v4());
                pry!(builder.bind("0.0.0.0:0"));
                builder
            }
            ::std::net::SocketAddr::V6(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v6());
                pry!(builder.bind("[::]:0")); // TODO: does this work?
                builder
            }
        };

        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = pry!(
            self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped,
                                                 &mut *write_overlapped));

        let (stream, _ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped))
        };

        let reactor2 = self.reactor.clone();
        let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| {
            Ok(SocketStreamInner::new_already_registered(
                reactor2, stream,
                read_overlapped, write_overlapped,
                handle))
        });

        result
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl Drop for SocketListenerInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> {
        self.listener.local_addr()
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl Drop for SocketStreamInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    fn new_already_registered(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream,
                              read_overlapped: Box<::miow::Overlapped>,
                              write_overlapped: Box<::miow::Overlapped>,
                              handle: Handle)
           -> SocketStreamInner
    {
        SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        }
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            println!("read transferred this many bytes: {}", n);
            let total_read = n as usize + already_read;
            if n == 0 {
                println!("EOF");
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            println!("write transferred this many bytes: {}", n);
            let total_written = n as usize + already_written;
            if n == 0 {
                println!("wrote zero bytes!?");
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<commit_msg>remove stray printlns<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        match self.cp.get_many(&mut self.statuses[..], timeout) {
            Err(ref e) if e.raw_os_error() == Some(258) => Ok(()), // winapi::WAIT_TIMEOUT
            Err(e) => Err(e),
            Ok(statuses) => {
                for status in statuses {
                    let token = status.token();
                    let overlapped = status.overlapped();
                    let bytes_transferred = status.bytes_transferred();
                    let handle = Handle { val: token };
                    if self.observers[handle].read_overlapped == overlapped {
                        match self.observers[handle].read_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                    if self.observers[handle].write_overlapped == overlapped {
                        match self.observers[handle].write_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                }
                Ok(())
            }
        }

    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v4());
                pry!(builder.bind("0.0.0.0:0"));
                builder
            }
            ::std::net::SocketAddr::V6(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v6());
                pry!(builder.bind("[::]:0")); // TODO: does this work?
                builder
            }
        };

        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = pry!(
            self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped,
                                                 &mut *write_overlapped));

        let (stream, _ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped))
        };

        let reactor2 = self.reactor.clone();
        let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| {
            Ok(SocketStreamInner::new_already_registered(
                reactor2, stream,
                read_overlapped, write_overlapped,
                handle))
        });

        result
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl Drop for SocketListenerInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> {
        self.listener.local_addr()
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl Drop for SocketStreamInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    fn new_already_registered(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream,
                              read_overlapped: Box<::miow::Overlapped>,
                              write_overlapped: Box<::miow::Overlapped>,
                              handle: Handle)
           -> SocketStreamInner
    {
        SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        }
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            let total_read = n as usize + already_read;
            if n == 0 {
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            let total_written = n as usize + already_written;
            if n == 0 {
                // TODO: do we need to handle this specially?
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<|endoftext|>


<commit_before>use crate::poll;
use crate::{event, Interests, Registry, Token};

use std::sync::{Arc, Mutex};
use std::{fmt, io};

use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.

use winapi::um::winsock2::{bind, closesocket, SOCKET_ERROR, SOCK_DGRAM};

use crate::sys::windows::init;

use super::{new_socket, socket_addr};

use super::selector::SockState;
use super::InternalState;

pub struct UdpSocket {
    internal: Arc<Mutex<Option<InternalState>>>,
    io: net::UdpSocket,
}

macro_rules! wouldblock {
    ($self:ident, $method:ident, $($args:expr),* )  => {{
        let result = $self.io.$method($($args),*);
        if let Err(ref e) = result {
            if e.kind() == io::ErrorKind::WouldBlock {
                let internal = $self.internal.lock().unwrap();
                if internal.is_some() {
                    let selector = internal.as_ref().unwrap().selector.clone();
                    let token = internal.as_ref().unwrap().token;
                    let interests = internal.as_ref().unwrap().interests;
                    drop(internal);
                    selector.reregister(
                        $self,
                        token,
                        interests,
                    )?;
                }
            }
        }
        result
    }};
}

impl UdpSocket {
    pub fn bind(addr: SocketAddr) -> io::Result<UdpSocket> {
        init();
        new_socket(addr, SOCK_DGRAM).and_then(|socket| {
            let (raw_addr, raw_addr_length) = socket_addr(&addr);
            syscall!(
                bind(socket, raw_addr, raw_addr_length,),
                PartialEq::eq,
                SOCKET_ERROR
            )
            .map_err(|err| {
                // Close the socket if we hit an error, ignoring the error
                // from closing since we can't pass back two errors.
                let _ = unsafe { closesocket(socket) };
                err
            })
            .map(|_| UdpSocket {
                internal: Arc::new(Mutex::new(None)),
                io: unsafe { net::UdpSocket::from_raw_socket(socket as StdSocket) },
            })
        })
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.io.local_addr()
    }

    pub fn try_clone(&self) -> io::Result<UdpSocket> {
        self.io.try_clone().map(|io| UdpSocket {
            internal: Arc::new(Mutex::new(None)),
            io,
        })
    }

    pub fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
        self.io.send_to(buf, target)
    }

    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
        self.io.recv_from(buf)
    }

    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
        self.io.peek_from(buf)
    }

    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
        wouldblock!(self, send, buf)
    }

    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
        wouldblock!(self, recv, buf)
    }

    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
        wouldblock!(self, peek, buf)
    }

    pub fn connect(&self, addr: SocketAddr) -> io::Result<()> {
        wouldblock!(self, connect, addr)
    }

    pub fn broadcast(&self) -> io::Result<bool> {
        self.io.broadcast()
    }

    pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
        self.io.set_broadcast(on)
    }

    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
        self.io.multicast_loop_v4()
    }

    pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
        self.io.set_multicast_loop_v4(on)
    }

    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
        self.io.multicast_ttl_v4()
    }

    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
        self.io.set_multicast_ttl_v4(ttl)
    }

    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
        self.io.multicast_loop_v6()
    }

    pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
        self.io.set_multicast_loop_v6(on)
    }

    pub fn ttl(&self) -> io::Result<u32> {
        self.io.ttl()
    }

    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        self.io.set_ttl(ttl)
    }

    pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
        self.io.join_multicast_v4(&multiaddr, &interface)
    }

    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
        self.io.join_multicast_v6(multiaddr, interface)
    }

    pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
        self.io.leave_multicast_v4(&multiaddr, &interface)
    }

    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
        self.io.leave_multicast_v6(multiaddr, interface)
    }

    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.io.take_error()
    }
}

impl super::SocketState for UdpSocket {
    fn get_sock_state(&self) -> Option<Arc<Mutex<SockState>>> {
        let internal = self.internal.lock().unwrap();
        match &*internal {
            Some(internal) => match &internal.sock_state {
                Some(arc) => Some(arc.clone()),
                None => None,
            },
            None => None,
        }
    }
    fn set_sock_state(&self, sock_state: Option<Arc<Mutex<SockState>>>) {
        let mut internal = self.internal.lock().unwrap();
        match &mut *internal {
            Some(internal) => {
                internal.sock_state = sock_state;
            }
            None => {}
        };
    }
}

impl event::Source for UdpSocket {
    fn register(&self, registry: &Registry, token: Token, interests: Interests) -> io::Result<()> {
        {
            let mut internal = self.internal.lock().unwrap();
            if internal.is_none() {
                *internal = Some(InternalState::new(
                    poll::selector(registry).clone_inner(),
                    token,
                    interests,
                ));
            }
        }
        let result = poll::selector(registry).register(self, token, interests);
        match result {
            Ok(_) => {}
            Err(_) => {
                let mut internal = self.internal.lock().unwrap();
                *internal = None;
            }
        }
        result
    }

    fn reregister(
        &self,
        registry: &Registry,
        token: Token,
        interests: Interests,
    ) -> io::Result<()> {
        let result = poll::selector(registry).reregister(self, token, interests);
        match result {
            Ok(_) => {
                let mut internal = self.internal.lock().unwrap();
                internal.as_mut().unwrap().token = token;
                internal.as_mut().unwrap().interests = interests;
            }
            Err(_) => {}
        };
        result
    }

    fn deregister(&self, registry: &Registry) -> io::Result<()> {
        let result = poll::selector(registry).deregister(self);
        match result {
            Ok(_) => {
                let mut internal = self.internal.lock().unwrap();
                *internal = None;
            }
            Err(_) => {}
        };
        result
    }
}

impl fmt::Debug for UdpSocket {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.io, f)
    }
}

impl FromRawSocket for UdpSocket {
    unsafe fn from_raw_socket(rawsocket: RawSocket) -> UdpSocket {
        UdpSocket {
            internal: Arc::new(Mutex::new(None)),
            io: net::UdpSocket::from_raw_socket(rawsocket),
        }
    }
}

impl IntoRawSocket for UdpSocket {
    fn into_raw_socket(self) -> RawSocket {
        self.io.as_raw_socket()
    }
}

impl AsRawSocket for UdpSocket {
    fn as_raw_socket(&self) -> RawSocket {
        self.io.as_raw_socket()
    }
}
<commit_msg>Fix udp issue in #1062<commit_after>use crate::poll;
use crate::{event, Interests, Registry, Token};

use std::sync::{Arc, Mutex};
use std::{fmt, io};

use std::net::{self, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.

use winapi::um::winsock2::{bind, closesocket, SOCKET_ERROR, SOCK_DGRAM};

use crate::sys::windows::init;

use super::{new_socket, socket_addr};

use super::selector::SockState;
use super::InternalState;

pub struct UdpSocket {
    internal: Arc<Mutex<Option<InternalState>>>,
    io: net::UdpSocket,
}

macro_rules! wouldblock {
    ($self:ident, $method:ident, $($args:expr),* )  => {{
        let result = $self.io.$method($($args),*);
        if let Err(ref e) = result {
            if e.kind() == io::ErrorKind::WouldBlock {
                let internal = $self.internal.lock().unwrap();
                if internal.is_some() {
                    let selector = internal.as_ref().unwrap().selector.clone();
                    let token = internal.as_ref().unwrap().token;
                    let interests = internal.as_ref().unwrap().interests;
                    drop(internal);
                    selector.reregister(
                        $self,
                        token,
                        interests,
                    )?;
                }
            }
        }
        result
    }};
}

impl UdpSocket {
    pub fn bind(addr: SocketAddr) -> io::Result<UdpSocket> {
        init();
        new_socket(addr, SOCK_DGRAM).and_then(|socket| {
            let (raw_addr, raw_addr_length) = socket_addr(&addr);
            syscall!(
                bind(socket, raw_addr, raw_addr_length,),
                PartialEq::eq,
                SOCKET_ERROR
            )
            .map_err(|err| {
                // Close the socket if we hit an error, ignoring the error
                // from closing since we can't pass back two errors.
                let _ = unsafe { closesocket(socket) };
                err
            })
            .map(|_| UdpSocket {
                internal: Arc::new(Mutex::new(None)),
                io: unsafe { net::UdpSocket::from_raw_socket(socket as StdSocket) },
            })
        })
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.io.local_addr()
    }

    pub fn try_clone(&self) -> io::Result<UdpSocket> {
        self.io.try_clone().map(|io| UdpSocket {
            internal: Arc::new(Mutex::new(None)),
            io,
        })
    }

    pub fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
        wouldblock!(self, send_to, buf, target)
    }

    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
        wouldblock!(self, recv_from, buf)
    }

    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
        wouldblock!(self, peek_from, buf)
    }

    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
        wouldblock!(self, send, buf)
    }

    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
        wouldblock!(self, recv, buf)
    }

    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
        wouldblock!(self, peek, buf)
    }

    pub fn connect(&self, addr: SocketAddr) -> io::Result<()> {
        self.io.connect(addr)
    }

    pub fn broadcast(&self) -> io::Result<bool> {
        self.io.broadcast()
    }

    pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
        self.io.set_broadcast(on)
    }

    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
        self.io.multicast_loop_v4()
    }

    pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
        self.io.set_multicast_loop_v4(on)
    }

    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
        self.io.multicast_ttl_v4()
    }

    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
        self.io.set_multicast_ttl_v4(ttl)
    }

    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
        self.io.multicast_loop_v6()
    }

    pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
        self.io.set_multicast_loop_v6(on)
    }

    pub fn ttl(&self) -> io::Result<u32> {
        self.io.ttl()
    }

    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        self.io.set_ttl(ttl)
    }

    pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
        self.io.join_multicast_v4(&multiaddr, &interface)
    }

    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
        self.io.join_multicast_v6(multiaddr, interface)
    }

    pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
        self.io.leave_multicast_v4(&multiaddr, &interface)
    }

    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
        self.io.leave_multicast_v6(multiaddr, interface)
    }

    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.io.take_error()
    }
}

impl super::SocketState for UdpSocket {
    fn get_sock_state(&self) -> Option<Arc<Mutex<SockState>>> {
        let internal = self.internal.lock().unwrap();
        match &*internal {
            Some(internal) => match &internal.sock_state {
                Some(arc) => Some(arc.clone()),
                None => None,
            },
            None => None,
        }
    }
    fn set_sock_state(&self, sock_state: Option<Arc<Mutex<SockState>>>) {
        let mut internal = self.internal.lock().unwrap();
        match &mut *internal {
            Some(internal) => {
                internal.sock_state = sock_state;
            }
            None => {}
        };
    }
}

impl event::Source for UdpSocket {
    fn register(&self, registry: &Registry, token: Token, interests: Interests) -> io::Result<()> {
        {
            let mut internal = self.internal.lock().unwrap();
            if internal.is_none() {
                *internal = Some(InternalState::new(
                    poll::selector(registry).clone_inner(),
                    token,
                    interests,
                ));
            }
        }
        let result = poll::selector(registry).register(self, token, interests);
        match result {
            Ok(_) => {}
            Err(_) => {
                let mut internal = self.internal.lock().unwrap();
                *internal = None;
            }
        }
        result
    }

    fn reregister(
        &self,
        registry: &Registry,
        token: Token,
        interests: Interests,
    ) -> io::Result<()> {
        let result = poll::selector(registry).reregister(self, token, interests);
        match result {
            Ok(_) => {
                let mut internal = self.internal.lock().unwrap();
                internal.as_mut().unwrap().token = token;
                internal.as_mut().unwrap().interests = interests;
            }
            Err(_) => {}
        };
        result
    }

    fn deregister(&self, registry: &Registry) -> io::Result<()> {
        let result = poll::selector(registry).deregister(self);
        match result {
            Ok(_) => {
                let mut internal = self.internal.lock().unwrap();
                *internal = None;
            }
            Err(_) => {}
        };
        result
    }
}

impl fmt::Debug for UdpSocket {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.io, f)
    }
}

impl FromRawSocket for UdpSocket {
    unsafe fn from_raw_socket(rawsocket: RawSocket) -> UdpSocket {
        UdpSocket {
            internal: Arc::new(Mutex::new(None)),
            io: net::UdpSocket::from_raw_socket(rawsocket),
        }
    }
}

impl IntoRawSocket for UdpSocket {
    fn into_raw_socket(self) -> RawSocket {
        self.io.as_raw_socket()
    }
}

impl AsRawSocket for UdpSocket {
    fn as_raw_socket(&self) -> RawSocket {
        self.io.as_raw_socket()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use logging::*;
use scheduler::*;

#[no_mangle]
#[naked]
pub unsafe extern "C" fn sys_invalid()
{
	let mut rax: i64 = 0;

	asm!("push %rax; pop $0" : "=r"(rax));

	error!("Invalid syscall {}", rax);
	do_exit();
}
<commit_msg>update license text<commit_after>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use logging::*;
use scheduler::*;

#[no_mangle]
#[naked]
pub unsafe extern "C" fn sys_invalid()
{
	let mut rax: i64 = 0;

	asm!("push %rax; pop $0" : "=r"(rax));

	error!("Invalid syscall {}", rax);
	do_exit();
}
<|endoftext|>