<commit_before>//! Intermediate representation for C/C++ functions and methods.

use super::context::{BindgenContext, ItemId};
use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
use clang;
use clang_sys::CXCallingConv;
use ir::derive::CanDeriveDebug;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::io;
use syntax::abi;

/// A function declaration, with a signature, arguments, and argument names.
///
/// The argument names vector must be the same length as the ones in the
/// signature.
#[derive(Debug)]
pub struct Function {
    /// The name of this function.
    name: String,

    /// The mangled name, that is, the symbol.
    mangled_name: Option<String>,

    /// The id pointing to the current function signature.
    signature: ItemId,

    /// The doc comment on the function, if any.
    comment: Option<String>,
}

impl Function {
    /// Construct a new function.
    pub fn new(name: String,
               mangled_name: Option<String>,
               sig: ItemId,
               comment: Option<String>)
               -> Self {
        Function {
            name: name,
            mangled_name: mangled_name,
            signature: sig,
            comment: comment,
        }
    }

    /// Get this function's name.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get this function's name.
    pub fn mangled_name(&self) -> Option<&str> {
        self.mangled_name.as_ref().map(|n| &**n)
    }

    /// Get this function's signature.
    pub fn signature(&self) -> ItemId {
        self.signature
    }
}

impl DotAttributes for Function {
    fn dot_attributes<W>(&self,
                         _ctx: &BindgenContext,
                         out: &mut W)
                         -> io::Result<()>
        where W: io::Write,
    {
        if let Some(ref mangled) = self.mangled_name {
            try!(writeln!(out,
                          "
mangled name	{}
",
                          mangled));
        }

        Ok(())
    }
}

/// A function signature.
#[derive(Debug)]
pub struct FunctionSig {
    /// The return type of the function.
    return_type: ItemId,

    /// The type of the arguments, optionally with the name of the argument when
    /// declared.
    argument_types: Vec<(Option<String>, ItemId)>,

    /// Whether this function is variadic.
    is_variadic: bool,

    /// The ABI of this function.
    abi: Option<abi::Abi>,
}

fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
    use clang_sys::*;
    match cc {
        CXCallingConv_Default => Some(abi::Abi::C),
        CXCallingConv_C => Some(abi::Abi::C),
        CXCallingConv_X86StdCall => Some(abi::Abi::Stdcall),
        CXCallingConv_X86FastCall => Some(abi::Abi::Fastcall),
        CXCallingConv_AAPCS => Some(abi::Abi::Aapcs),
        CXCallingConv_X86_64Win64 => Some(abi::Abi::Win64),
        CXCallingConv_Invalid => None,
        other => panic!("unsupported calling convention: {:?}", other),
    }
}

/// Get the mangled name for the cursor's referent.
pub fn cursor_mangling(ctx: &BindgenContext,
                       cursor: &clang::Cursor)
                       -> Option<String> {
    use clang_sys;
    if !ctx.options().enable_mangling {
        return None;
    }

    // We early return here because libclang may crash in some case
    // if we pass in a variable inside a partial specialized template.
    // See servo/rust-bindgen#67, and servo/rust-bindgen#462.
    if cursor.is_in_non_fully_specialized_template() {
        return None;
    }

    if let Ok(mut manglings) = cursor.cxx_manglings() {
        if let Some(m) = manglings.pop() {
            return Some(m);
        }
    }

    let mut mangling = cursor.mangling();
    if mangling.is_empty() {
        return None;
    }

    // Try to undo backend linkage munging (prepended _, generally)
    //
    // TODO(emilio): This is wrong when the target system is not the host
    // system. See https://github.com/servo/rust-bindgen/issues/593
    if cfg!(target_os = "macos") {
        mangling.remove(0);
    }

    if cursor.kind() == clang_sys::CXCursor_Destructor {
        // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
        // the "destructor group 0" symbol, which means that it'll try to free
        // memory, which definitely isn't what we want.
        //
        // Explicitly force the destructor group 1 symbol.
        //
        // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
        // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
        // a more friendly explanation.
        //
        // We don't need to do this for constructors since clang seems to always
        // have returned the C1 constructor.
        //
        // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
        // I don't think so, but if it can this would become a linker error
        // anyway, not an invalid free at runtime.
        //
        // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
        // time.
        if mangling.ends_with("D0Ev") {
            let new_len = mangling.len() - 4;
            mangling.truncate(new_len);
            mangling.push_str("D1Ev");
        }
    }

    Some(mangling)
}

impl FunctionSig {
    /// Construct a new function signature.
    pub fn new(return_type: ItemId,
               arguments: Vec<(Option<String>, ItemId)>,
               is_variadic: bool,
               abi: Option<abi::Abi>)
               -> Self {
        FunctionSig {
            return_type: return_type,
            argument_types: arguments,
            is_variadic: is_variadic,
            abi: abi,
        }
    }

    /// Construct a new function signature from the given Clang type.
    pub fn from_ty(ty: &clang::Type,
                   cursor: &clang::Cursor,
                   ctx: &mut BindgenContext)
                   -> Result<Self, ParseError> {
        use clang_sys::*;
        debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);

        // Skip function templates
        if cursor.kind() == CXCursor_FunctionTemplate {
            return Err(ParseError::Continue);
        }

        // Don't parse operatorxx functions in C++
        let spelling = cursor.spelling();
        if spelling.starts_with("operator") {
            return Err(ParseError::Continue);
        }

        let cursor = if cursor.is_valid() {
            *cursor
        } else {
            ty.declaration()
        };

        let mut args: Vec<_> = match cursor.kind() {
            CXCursor_FunctionDecl |
            CXCursor_Constructor |
            CXCursor_CXXMethod |
            CXCursor_ObjCInstanceMethodDecl |
            CXCursor_ObjCClassMethodDecl => {
                // For CXCursor_FunctionDecl, cursor.args() is the reliable way
                // to get parameter names and types.
                cursor.args()
                    .unwrap()
                    .iter()
                    .map(|arg| {
                        let arg_ty = arg.cur_type();
                        let name = arg.spelling();
                        let name =
                            if name.is_empty() { None } else { Some(name) };
                        let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx);
                        (name, ty)
                    })
                    .collect()
            }
            _ => {
                // For non-CXCursor_FunctionDecl, visiting the cursor's children
                // is the only reliable way to get parameter names.
                let mut args = vec![];
                cursor.visit(|c| {
                    if c.kind() == CXCursor_ParmDecl {
                        let ty =
                            Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
                        let name = c.spelling();
                        let name =
                            if name.is_empty() { None } else { Some(name) };
                        args.push((name, ty));
                    }
                    CXChildVisit_Continue
                });
                args
            }
        };

        let is_method = cursor.kind() == CXCursor_CXXMethod;
        let is_constructor = cursor.kind() == CXCursor_Constructor;
        let is_destructor = cursor.kind() == CXCursor_Destructor;
        if (is_constructor || is_destructor || is_method) &&
           cursor.lexical_parent() != cursor.semantic_parent() {
            // Only parse constructors once.
            return Err(ParseError::Continue);
        }

        if is_method || is_constructor || is_destructor {
            let is_const = is_method && cursor.method_is_const();
            let is_virtual = is_method && cursor.method_is_virtual();
            let is_static = is_method && cursor.method_is_static();
            if !is_static && !is_virtual {
                let class = Item::parse(cursor.semantic_parent(), None, ctx)
                    .expect("Expected to parse the class");
                let ptr =
                    Item::builtin_type(TypeKind::Pointer(class), is_const, ctx);
                args.insert(0, (Some("this".into()), ptr));
            } else if is_virtual {
                let void = Item::builtin_type(TypeKind::Void, false, ctx);
                let ptr =
                    Item::builtin_type(TypeKind::Pointer(void), false, ctx);
                args.insert(0, (Some("this".into()), ptr));
            }
        }

        let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
                             cursor.kind() == CXCursor_ObjCClassMethodDecl {
            try!(ty.ret_type()
                   .or_else(|| cursor.ret_type())
                   .ok_or(ParseError::Continue))
        } else {
            try!(ty.ret_type().ok_or(ParseError::Continue))
        };
        let ret = Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx);
        let abi = get_abi(ty.call_conv());

        if abi.is_none() {
            assert!(cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
                    cursor.kind() == CXCursor_ObjCClassMethodDecl,
                       "Invalid ABI for function signature")
        }

        Ok(Self::new(ret, args, ty.is_variadic(), abi))
    }

    /// Get this function signature's return type.
    pub fn return_type(&self) -> ItemId {
        self.return_type
    }

    /// Get this function signature's argument (name, type) pairs.
    pub fn argument_types(&self) -> &[(Option<String>, ItemId)] {
        &self.argument_types
    }

    /// Get this function signature's ABI.
    pub fn abi(&self) -> Option<abi::Abi> {
        self.abi
    }

    /// Is this function signature variadic?
    pub fn is_variadic(&self) -> bool {
        // Clang reports some functions as variadic when they *might* be
        // variadic. We do the argument check because rust doesn't codegen well
        // variadic functions without an initial argument.
        self.is_variadic && !self.argument_types.is_empty()
    }
}

impl ClangSubItemParser for Function {
    fn parse(cursor: clang::Cursor,
             context: &mut BindgenContext)
             -> Result<ParseResult<Self>, ParseError> {
        use clang_sys::*;
        match cursor.kind() {
            CXCursor_FunctionDecl |
            CXCursor_Constructor |
            CXCursor_Destructor |
            CXCursor_CXXMethod => {}
            _ => return Err(ParseError::Continue),
        };

        debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());

        let visibility = cursor.visibility();
        if visibility != CXVisibility_Default {
            return Err(ParseError::Continue);
        }

        if cursor.access_specifier() == CX_CXXPrivate {
            return Err(ParseError::Continue);
        }

        if !context.options().generate_inline_functions &&
            cursor.is_inlined_function() {
            return Err(ParseError::Continue);
        }

        let linkage = cursor.linkage();
        if linkage != CXLinkage_External &&
           linkage != CXLinkage_UniqueExternal {
            return Err(ParseError::Continue);
        }

        // Grab the signature using Item::from_ty.
        let sig =
            try!(Item::from_ty(&cursor.cur_type(), cursor, None, context));

        let mut name = cursor.spelling();
        assert!(!name.is_empty(), "Empty function name?");

        if cursor.kind() == CXCursor_Destructor {
            // Remove the leading `~`. The alternative to this is special-casing
            // code-generation for destructor functions, which seems less than
            // ideal.
            if name.starts_with('~') {
                name.remove(0);
            }

            // Add a suffix to avoid colliding with constructors. This would be
            // technically fine (since we handle duplicated functions/methods),
            // but seems easy enough to handle it here.
            name.push_str("_destructor");
        }

        let mut mangled_name = cursor_mangling(context, &cursor);
        if mangled_name.as_ref() == Some(&name) {
            mangled_name = None;
        }

        let comment = cursor.raw_comment();

        let function = Self::new(name, mangled_name, sig, comment);
        Ok(ParseResult::New(function, Some(cursor)))
    }
}

impl Trace for FunctionSig {
    type Extra = ();

    fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.return_type(), EdgeKind::FunctionReturn);

        for &(_, ty) in self.argument_types() {
            tracer.visit_kind(ty, EdgeKind::FunctionParameter);
        }
    }
}

// Function pointers follow special rules, see:
//
// https://github.com/servo/rust-bindgen/issues/547,
// https://github.com/rust-lang/rust/issues/38848,
// and https://github.com/rust-lang/rust/issues/40158
//
// Note that copy is always derived, so we don't need to implement it.
impl CanDeriveDebug for FunctionSig {
    type Extra = ();

    fn can_derive_debug(&self, _ctx: &BindgenContext, _: ()) -> bool {
        const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
        if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
            return false;
        }

        match self.abi {
            Some(abi::Abi::C) |
            None => true,
            _ => false,
        }
    }
}
<commit_msg>Fix osx mangling hack<commit_after>//! Intermediate representation for C/C++ functions and methods.

use super::context::{BindgenContext, ItemId};
use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
use clang;
use clang_sys::CXCallingConv;
use ir::derive::CanDeriveDebug;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::io;
use syntax::abi;

/// A function declaration, with a signature, arguments, and argument names.
///
/// The argument names vector must be the same length as the ones in the
/// signature.
#[derive(Debug)]
pub struct Function {
    /// The name of this function.
    name: String,

    /// The mangled name, that is, the symbol.
    mangled_name: Option<String>,

    /// The id pointing to the current function signature.
    signature: ItemId,

    /// The doc comment on the function, if any.
    comment: Option<String>,
}

impl Function {
    /// Construct a new function.
    pub fn new(name: String,
               mangled_name: Option<String>,
               sig: ItemId,
               comment: Option<String>)
               -> Self {
        Function {
            name: name,
            mangled_name: mangled_name,
            signature: sig,
            comment: comment,
        }
    }

    /// Get this function's name.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get this function's name.
    pub fn mangled_name(&self) -> Option<&str> {
        self.mangled_name.as_ref().map(|n| &**n)
    }

    /// Get this function's signature.
    pub fn signature(&self) -> ItemId {
        self.signature
    }
}

impl DotAttributes for Function {
    fn dot_attributes<W>(&self,
                         _ctx: &BindgenContext,
                         out: &mut W)
                         -> io::Result<()>
        where W: io::Write,
    {
        if let Some(ref mangled) = self.mangled_name {
            try!(writeln!(out,
                          "
mangled name	{}
",
                          mangled));
        }

        Ok(())
    }
}

/// A function signature.
#[derive(Debug)]
pub struct FunctionSig {
    /// The return type of the function.
    return_type: ItemId,

    /// The type of the arguments, optionally with the name of the argument when
    /// declared.
    argument_types: Vec<(Option<String>, ItemId)>,

    /// Whether this function is variadic.
    is_variadic: bool,

    /// The ABI of this function.
    abi: Option<abi::Abi>,
}

fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
    use clang_sys::*;
    match cc {
        CXCallingConv_Default => Some(abi::Abi::C),
        CXCallingConv_C => Some(abi::Abi::C),
        CXCallingConv_X86StdCall => Some(abi::Abi::Stdcall),
        CXCallingConv_X86FastCall => Some(abi::Abi::Fastcall),
        CXCallingConv_AAPCS => Some(abi::Abi::Aapcs),
        CXCallingConv_X86_64Win64 => Some(abi::Abi::Win64),
        CXCallingConv_Invalid => None,
        other => panic!("unsupported calling convention: {:?}", other),
    }
}

// Mac os needs __ for mangled symbols but rust will automatically prepend the extra _.
// We need to make sure that we don't include __ because rust will turn into ___.
//
// TODO(emilio): This is wrong when the target system is not the host
// system. See https://github.com/servo/rust-bindgen/issues/593
fn macos_mangling(symbol: &mut String) {
    if cfg!(target_os = "macos") && symbol.starts_with("_") {
        symbol.remove(0);
    }
}

/// Get the mangled name for the cursor's referent.
pub fn cursor_mangling(ctx: &BindgenContext,
                       cursor: &clang::Cursor)
                       -> Option<String> {
    use clang_sys;
    if !ctx.options().enable_mangling {
        return None;
    }

    // We early return here because libclang may crash in some case
    // if we pass in a variable inside a partial specialized template.
    // See servo/rust-bindgen#67, and servo/rust-bindgen#462.
    if cursor.is_in_non_fully_specialized_template() {
        return None;
    }

    if let Ok(mut manglings) = cursor.cxx_manglings() {
        if let Some(mut m) = manglings.pop() {
            macos_mangling(&mut m);
            return Some(m);
        }
    }

    let mut mangling = cursor.mangling();
    if mangling.is_empty() {
        return None;
    }

    macos_mangling(&mut mangling);

    if cursor.kind() == clang_sys::CXCursor_Destructor {
        // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
        // the "destructor group 0" symbol, which means that it'll try to free
        // memory, which definitely isn't what we want.
        //
        // Explicitly force the destructor group 1 symbol.
        //
        // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
        // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
        // a more friendly explanation.
        //
        // We don't need to do this for constructors since clang seems to always
        // have returned the C1 constructor.
        //
        // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
        // I don't think so, but if it can this would become a linker error
        // anyway, not an invalid free at runtime.
        //
        // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
        // time.
        if mangling.ends_with("D0Ev") {
            let new_len = mangling.len() - 4;
            mangling.truncate(new_len);
            mangling.push_str("D1Ev");
        }
    }

    Some(mangling)
}

impl FunctionSig {
    /// Construct a new function signature.
    pub fn new(return_type: ItemId,
               arguments: Vec<(Option<String>, ItemId)>,
               is_variadic: bool,
               abi: Option<abi::Abi>)
               -> Self {
        FunctionSig {
            return_type: return_type,
            argument_types: arguments,
            is_variadic: is_variadic,
            abi: abi,
        }
    }

    /// Construct a new function signature from the given Clang type.
    pub fn from_ty(ty: &clang::Type,
                   cursor: &clang::Cursor,
                   ctx: &mut BindgenContext)
                   -> Result<Self, ParseError> {
        use clang_sys::*;
        debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);

        // Skip function templates
        if cursor.kind() == CXCursor_FunctionTemplate {
            return Err(ParseError::Continue);
        }

        // Don't parse operatorxx functions in C++
        let spelling = cursor.spelling();
        if spelling.starts_with("operator") {
            return Err(ParseError::Continue);
        }

        let cursor = if cursor.is_valid() {
            *cursor
        } else {
            ty.declaration()
        };

        let mut args: Vec<_> = match cursor.kind() {
            CXCursor_FunctionDecl |
            CXCursor_Constructor |
            CXCursor_CXXMethod |
            CXCursor_ObjCInstanceMethodDecl |
            CXCursor_ObjCClassMethodDecl => {
                // For CXCursor_FunctionDecl, cursor.args() is the reliable way
                // to get parameter names and types.
                cursor.args()
                    .unwrap()
                    .iter()
                    .map(|arg| {
                        let arg_ty = arg.cur_type();
                        let name = arg.spelling();
                        let name =
                            if name.is_empty() { None } else { Some(name) };
                        let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx);
                        (name, ty)
                    })
                    .collect()
            }
            _ => {
                // For non-CXCursor_FunctionDecl, visiting the cursor's children
                // is the only reliable way to get parameter names.
                let mut args = vec![];
                cursor.visit(|c| {
                    if c.kind() == CXCursor_ParmDecl {
                        let ty =
                            Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
                        let name = c.spelling();
                        let name =
                            if name.is_empty() { None } else { Some(name) };
                        args.push((name, ty));
                    }
                    CXChildVisit_Continue
                });
                args
            }
        };

        let is_method = cursor.kind() == CXCursor_CXXMethod;
        let is_constructor = cursor.kind() == CXCursor_Constructor;
        let is_destructor = cursor.kind() == CXCursor_Destructor;
        if (is_constructor || is_destructor || is_method) &&
           cursor.lexical_parent() != cursor.semantic_parent() {
            // Only parse constructors once.
            return Err(ParseError::Continue);
        }

        if is_method || is_constructor || is_destructor {
            let is_const = is_method && cursor.method_is_const();
            let is_virtual = is_method && cursor.method_is_virtual();
            let is_static = is_method && cursor.method_is_static();
            if !is_static && !is_virtual {
                let class = Item::parse(cursor.semantic_parent(), None, ctx)
                    .expect("Expected to parse the class");
                let ptr =
                    Item::builtin_type(TypeKind::Pointer(class), is_const, ctx);
                args.insert(0, (Some("this".into()), ptr));
            } else if is_virtual {
                let void = Item::builtin_type(TypeKind::Void, false, ctx);
                let ptr =
                    Item::builtin_type(TypeKind::Pointer(void), false, ctx);
                args.insert(0, (Some("this".into()), ptr));
            }
        }

        let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
                             cursor.kind() == CXCursor_ObjCClassMethodDecl {
            try!(ty.ret_type()
                   .or_else(|| cursor.ret_type())
                   .ok_or(ParseError::Continue))
        } else {
            try!(ty.ret_type().ok_or(ParseError::Continue))
        };
        let ret = Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx);
        let abi = get_abi(ty.call_conv());

        if abi.is_none() {
            assert!(cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
                    cursor.kind() == CXCursor_ObjCClassMethodDecl,
                       "Invalid ABI for function signature")
        }

        Ok(Self::new(ret, args, ty.is_variadic(), abi))
    }

    /// Get this function signature's return type.
    pub fn return_type(&self) -> ItemId {
        self.return_type
    }

    /// Get this function signature's argument (name, type) pairs.
    pub fn argument_types(&self) -> &[(Option<String>, ItemId)] {
        &self.argument_types
    }

    /// Get this function signature's ABI.
    pub fn abi(&self) -> Option<abi::Abi> {
        self.abi
    }

    /// Is this function signature variadic?
    pub fn is_variadic(&self) -> bool {
        // Clang reports some functions as variadic when they *might* be
        // variadic. We do the argument check because rust doesn't codegen well
        // variadic functions without an initial argument.
        self.is_variadic && !self.argument_types.is_empty()
    }
}

impl ClangSubItemParser for Function {
    fn parse(cursor: clang::Cursor,
             context: &mut BindgenContext)
             -> Result<ParseResult<Self>, ParseError> {
        use clang_sys::*;
        match cursor.kind() {
            CXCursor_FunctionDecl |
            CXCursor_Constructor |
            CXCursor_Destructor |
            CXCursor_CXXMethod => {}
            _ => return Err(ParseError::Continue),
        };

        debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());

        let visibility = cursor.visibility();
        if visibility != CXVisibility_Default {
            return Err(ParseError::Continue);
        }

        if cursor.access_specifier() == CX_CXXPrivate {
            return Err(ParseError::Continue);
        }

        if !context.options().generate_inline_functions &&
            cursor.is_inlined_function() {
            return Err(ParseError::Continue);
        }

        let linkage = cursor.linkage();
        if linkage != CXLinkage_External &&
           linkage != CXLinkage_UniqueExternal {
            return Err(ParseError::Continue);
        }

        // Grab the signature using Item::from_ty.
        let sig =
            try!(Item::from_ty(&cursor.cur_type(), cursor, None, context));

        let mut name = cursor.spelling();
        assert!(!name.is_empty(), "Empty function name?");

        if cursor.kind() == CXCursor_Destructor {
            // Remove the leading `~`. The alternative to this is special-casing
            // code-generation for destructor functions, which seems less than
            // ideal.
            if name.starts_with('~') {
                name.remove(0);
            }

            // Add a suffix to avoid colliding with constructors. This would be
            // technically fine (since we handle duplicated functions/methods),
            // but seems easy enough to handle it here.
            name.push_str("_destructor");
        }

        let mut mangled_name = cursor_mangling(context, &cursor);
        if mangled_name.as_ref() == Some(&name) {
            mangled_name = None;
        }

        let comment = cursor.raw_comment();

        let function = Self::new(name, mangled_name, sig, comment);
        Ok(ParseResult::New(function, Some(cursor)))
    }
}

impl Trace for FunctionSig {
    type Extra = ();

    fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
        where T: Tracer,
    {
        tracer.visit_kind(self.return_type(), EdgeKind::FunctionReturn);

        for &(_, ty) in self.argument_types() {
            tracer.visit_kind(ty, EdgeKind::FunctionParameter);
        }
    }
}

// Function pointers follow special rules, see:
//
// https://github.com/servo/rust-bindgen/issues/547,
// https://github.com/rust-lang/rust/issues/38848,
// and https://github.com/rust-lang/rust/issues/40158
//
// Note that copy is always derived, so we don't need to implement it.
impl CanDeriveDebug for FunctionSig {
    type Extra = ();

    fn can_derive_debug(&self, _ctx: &BindgenContext, _: ()) -> bool {
        const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
        if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
            return false;
        }

        match self.abi {
            Some(abi::Abi::C) |
            None => true,
            _ => false,
        }
    }
}
<|endoftext|>


<commit_before>use std::marker;
use fixedbitset::FixedBitSet;

use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

use super::visit::GetAdjacencyMatrix;

#[derive(Debug)]
struct Vf2State<Ty, Ix> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    out_size: usize,
    ins_size: usize,
    adjacency_matrix: FixedBitSet,
    generation: usize,
    _etype: marker::PhantomData<Ty>,
}

impl<Ty, Ix> Vf2State<Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self {
        let c0 = g.node_count();
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
            out_size: 0,
            ins_size: 0,
            adjacency_matrix: g.adjacency_matrix(),
            generation: 0,
            _etype: marker::PhantomData,
        };
        for _ in 0..c0 {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if Ty::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
            }
            self.out_size += 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                }
            }
            self.ins_size += 1;
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
            }
            self.out_size -= 1;
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                }
            }
            self.ins_size -= 1;
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !Ty::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ty, Ix>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool
    where Ty: EdgeType,
          Ix: IndexType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ty, Ix>(st: &mut [Vf2State<Ty, Ix>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool>
        where Ty: EdgeType,
              Ix: IndexType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            //
            // Note: We want to check the lookahead measures here if we can,
            // R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
            // R_in: Same with Tin
            // R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
            //      Ñ is G0 - M - Tin - Tout
            // last attempt to add these did not speed up any of the testcases
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Check counts in Tin/Tout
            if st[0].out_size == st[0].out_size ||
               st[1].ins_size == st[1].ins_size
            {

                // Recurse
                match try_match(st, g0, g1) {
                    None => {}
                    result => return result,
                }
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<commit_msg>isomorphism: Fix Tin == Tout cardinality check<commit_after>use std::marker;
use fixedbitset::FixedBitSet;

use super::{
    EdgeType,
    Incoming,
};
use super::graph::{
    Graph,
    IndexType,
    NodeIndex,
};

use super::visit::GetAdjacencyMatrix;

#[derive(Debug)]
struct Vf2State<Ty, Ix> {
    /// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
    /// NodeIndex::end() for no mapping.
    mapping: Vec<NodeIndex<Ix>>,
    /// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
    /// These are all the next vertices that are not mapped yet, but
    /// have an outgoing edge from the mapping.
    out: Vec<usize>,
    /// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
    /// These are all the incoming vertices, those not mapped yet, but
    /// have an edge from them into the mapping.
    /// Unused if graph is undirected -- it's identical with out in that case.
    ins: Vec<usize>,
    out_size: usize,
    ins_size: usize,
    adjacency_matrix: FixedBitSet,
    generation: usize,
    _etype: marker::PhantomData<Ty>,
}

impl<Ty, Ix> Vf2State<Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType,
{
    pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self {
        let c0 = g.node_count();
        let mut state = Vf2State {
            mapping: Vec::with_capacity(c0),
            out: Vec::with_capacity(c0),
            ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
            out_size: 0,
            ins_size: 0,
            adjacency_matrix: g.adjacency_matrix(),
            generation: 0,
            _etype: marker::PhantomData,
        };
        for _ in 0..c0 {
            state.mapping.push(NodeIndex::end());
            state.out.push(0);
            if Ty::is_directed() {
                state.ins.push(0);
            }
        }
        state
    }

    /// Return **true** if we have a complete mapping
    pub fn is_complete(&self) -> bool {
        self.generation == self.mapping.len()
    }

    /// Add mapping **from** <-> **to** to the state.
    pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
                              g: &Graph<N, E, Ty, Ix>)
    {
        self.generation += 1;
        let s = self.generation;
        self.mapping[from.index()] = to;
        // update T0 & T1 ins/outs
        // T0out: Node in G0 not in M0 but successor of a node in M0.
        // st.out[0]: Node either in M0 or successor of M0
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == 0 {
                self.out[ix.index()] = s;
                self.out_size += 1;
            }
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == 0 {
                    self.ins[ix.index()] = s;
                    self.ins_size += 1;
                }
            }
        }
    }

    /// Restore the state to before the last added mapping
    pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
                             g: &Graph<N, E, Ty, Ix>)
    {
        let s = self.generation;
        self.generation -= 1;

        // undo (n, m) mapping
        self.mapping[from.index()] = NodeIndex::end();

        // unmark in ins and outs
        for ix in g.neighbors(from) {
            if self.out[ix.index()] == s {
                self.out[ix.index()] = 0;
                self.out_size -= 1;
            }
        }
        if g.is_directed() {
            for ix in g.neighbors_directed(from, Incoming) {
                if self.ins[ix.index()] == s {
                    self.ins[ix.index()] = 0;
                    self.ins_size -= 1;
                }
            }
        }
    }

    /// Find the next (least) node in the Tout set.
    pub fn next_out_index(&self, from_index: usize) -> Option<usize>
    {
        self.out[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the Tin set.
    pub fn next_in_index(&self, from_index: usize) -> Option<usize>
    {
        if !Ty::is_directed() {
            return None
        }
        self.ins[from_index..].iter()
                    .enumerate()
                    .filter(|&(index, elt)| *elt > 0 && self.mapping[from_index + index] == NodeIndex::end())
                    .next()
                    .map(|(index, _)| index)
    }

    /// Find the next (least) node in the N - M set.
    pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
    {
        self.mapping[from_index..].iter()
               .enumerate()
               .filter(|&(_, elt)| *elt == NodeIndex::end())
               .next()
               .map(|(index, _)| index)
    }
}

/// Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm.
///
/// Not implemented: Vertex or edge weight matching.
///
/// ## References
///
/// * A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs
///   Luigi P. Cordella, Pasquale Foggia, Carlo Sansone,
///   and Mario Vento
pub fn is_isomorphic<N, E, Ty, Ix>(g0: &Graph<N, E, Ty, Ix>,
                                   g1: &Graph<N, E, Ty, Ix>) -> bool
    where Ty: EdgeType,
          Ix: IndexType,
{
    if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
        return false
    }

    /// Return Some(bool) if isomorphism is decided, else None.
    fn try_match<N, E, Ty, Ix>(st: &mut [Vf2State<Ty, Ix>; 2],
                               g0: &Graph<N, E, Ty, Ix>,
                               g1: &Graph<N, E, Ty, Ix>) -> Option<bool>
        where Ty: EdgeType,
              Ix: IndexType,
    {
        let g = [g0, g1];
        let graph_indices = 0..2;
        let end = NodeIndex::end();

        // if all are mapped -- we are done and have an iso
        if st[0].is_complete() {
            return Some(true)
        }

        // A "depth first" search of a valid mapping from graph 1 to graph 2

        // F(s, n, m) -- evaluate state s and add mapping n <-> m

        // Find least T1out node (in st.out[1] but not in M[1])
        #[derive(Copy, Clone, PartialEq, Debug)]
        enum OpenList {
            Out,
            In,
            Other,
        }
        let mut open_list = OpenList::Out;

        let mut to_index;
        let mut from_index = None;
        // Try the out list
        to_index = st[1].next_out_index(0);

        if to_index.is_some() {
            from_index = st[0].next_out_index(0);
            open_list = OpenList::Out;
        }

        // Try the in list
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_in_index(0);

            if to_index.is_some() {
                from_index = st[0].next_in_index(0);
                open_list = OpenList::In;
            }
        }

        // Try the other list -- disconnected graph
        if to_index.is_none() || from_index.is_none() {
            to_index = st[1].next_rest_index(0);
            if to_index.is_some() {
                from_index = st[0].next_rest_index(0);
                open_list = OpenList::Other;
            }
        }

        let (cand0, cand1) = match (from_index, to_index) {
            (Some(n), Some(m)) => (n, m),
            // No more candidates
            _ => return None,
        };

        let mut nx = NodeIndex::new(cand0);
        let mx = NodeIndex::new(cand1);

        let mut first = true;

        'candidates: loop {
            if !first {
                // Find the next node index to try on the `from` side of the mapping
                let start = nx.index() + 1;
                let cand0 = match open_list {
                    OpenList::Out => st[0].next_out_index(start),
                    OpenList::In => st[0].next_in_index(start),
                    OpenList::Other => st[0].next_rest_index(start),
                }.map(|c| c + start); // compensate for start offset.
                nx = match cand0 {
                    None => break, // no more candidates
                    Some(ix) => NodeIndex::new(ix),
                };
                debug_assert!(nx.index() >= start);
            }
            first = false;

            let nodes = [nx, mx];

            // Check syntactic feasibility of mapping by ensuring adjacencies
            // of nx map to adjacencies of mx.
            //
            // nx == map to => mx
            //
            // R_succ
            //
            // Check that every neighbor of nx is mapped to a neighbor of mx,
            // then check the reverse, from mx to nx. Check that they have the same
            // count of edges.
            //
            // Note: We want to check the lookahead measures here if we can,
            // R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
            // R_in: Same with Tin
            // R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
            //      Ñ is G0 - M - Tin - Tout
            // last attempt to add these did not speed up any of the testcases
            let mut succ_count = [0, 0];
            for j in graph_indices.clone() {
                for n_neigh in g[j].neighbors(nodes[j]) {
                    succ_count[j] += 1;
                    let m_neigh = st[j].mapping[n_neigh.index()];
                    if m_neigh == end {
                        continue;
                    }
                    let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
                    if !has_edge {
                        continue 'candidates;
                    }
                }
            }
            if succ_count[0] != succ_count[1] {
                continue 'candidates;
            }

            // R_pred
            if g[0].is_directed() {
                let mut pred_count = [0, 0];
                for j in graph_indices.clone() {
                    for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
                        pred_count[j] += 1;
                        let m_neigh = st[j].mapping[n_neigh.index()];
                        if m_neigh == end {
                            continue;
                        }
                        let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
                        if !has_edge {
                            continue 'candidates;
                        }
                    }
                }
                if pred_count[0] != pred_count[1] {
                    continue 'candidates;
                }
            }

            // Add mapping nx <-> mx to the state
            for j in graph_indices.clone() {
                st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
            }

            // Check cardinalities of Tin, Tout sets
            if st[0].out_size == st[1].out_size &&
               st[0].ins_size == st[1].ins_size
            {

                // Recurse
                match try_match(st, g0, g1) {
                    None => {}
                    result => return result,
                }
            }

            // Restore state.
            for j in graph_indices.clone() {
                st[j].pop_mapping(nodes[j], g[j]);
            }
        }
        None
    }
    let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
    try_match(&mut st, g0, g1).unwrap_or(false)
}

<|endoftext|>


<commit_before>use std::{collections::VecDeque, fmt, mem, os::raw::c_void};

use winapi::{
    shared::{
        dxgi,
        dxgi1_4,
        windef::{HWND, RECT},
        winerror,
    },
    um::{
        synchapi,
        winbase,
        winnt::HANDLE,
        winuser::GetClientRect,
    },
};

use crate::{conv, resource as r, Backend, Device, Instance, PhysicalDevice, QueueFamily};
use hal::{device::{Device as _}, format as f, image as i, window as w};

impl Instance {
    pub fn create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface {
        Surface {
            factory: self.factory,
            wnd_handle: hwnd as *mut _,
            presentation: None,
        }
    }
}

#[derive(Debug)]
struct Presentation {
    swapchain: Swapchain,
    format: f::Format,
    size: w::Extent2D,
}

pub struct Surface {
    pub(crate) factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
    pub(crate) wnd_handle: HWND,
    presentation: Option<Presentation>,
}

impl fmt::Debug for Surface {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str("Surface")
    }
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl Surface {
    pub(crate) unsafe fn present(&self) {
        self.presentation
            .as_ref()
            .unwrap()
            .swapchain
            .inner
            .Present(1, 0);
    }
}

impl w::Surface<Backend> for Surface {
    fn supports_queue_family(&self, queue_family: &QueueFamily) -> bool {
        match queue_family {
            &QueueFamily::Present => true,
            _ => false,
        }
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        let current_extent = unsafe {
            let mut rect: RECT = mem::zeroed();
            if GetClientRect(self.wnd_handle as *mut _, &mut rect as *mut RECT) == 0 {
                panic!("GetClientRect failed");
            }
            Some(w::Extent2D {
                width: (rect.right - rect.left) as u32,
                height: (rect.bottom - rect.top) as u32,
            })
        };

        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=16, // we currently use a flip effect which supports 2..=16 buffers
            current_extent,
            extents: w::Extent2D {
                width: 16,
                height: 16,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: i::Usage::COLOR_ATTACHMENT | i::Usage::TRANSFER_SRC | i::Usage::TRANSFER_DST,
        }
    }

    fn supported_formats(&self, _physical_device: &PhysicalDevice) -> Option<Vec<f::Format>> {
        Some(vec![
            f::Format::Bgra8Srgb,
            f::Format::Bgra8Unorm,
            f::Format::Rgba8Srgb,
            f::Format::Rgba8Unorm,
            f::Format::A2b10g10r10Unorm,
            f::Format::Rgba16Sfloat,
        ])
    }
}

impl w::PresentationSurface<Backend> for Surface {
    type SwapchainImage = r::ImageView;

    unsafe fn configure_swapchain(
        &mut self,
        device: &Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::CreationError> {
        assert!(i::Usage::COLOR_ATTACHMENT.contains(config.image_usage));

        let swapchain = match self.presentation.take() {
            Some(present) => {
                if present.format == config.format && present.size == config.extent {
                    self.presentation = Some(present);
                    return Ok(());
                }
                // can't have image resources in flight used by GPU
                device.wait_idle().unwrap();

                let inner = present.swapchain.release_resources();
                let result = inner.ResizeBuffers(
                    config.image_count,
                    config.extent.width,
                    config.extent.height,
                    conv::map_format_nosrgb(config.format).unwrap(),
                    dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT,
                );
                if result != winerror::S_OK {
                    error!("ResizeBuffers failed with 0x{:x}", result as u32);
                    return Err(w::CreationError::WindowInUse(hal::device::WindowInUse));
                }
                inner
            }
            None => {
                let (swapchain, _) =
                    device.create_swapchain_impl(&config, self.wnd_handle, self.factory.clone())?;
                swapchain
            }
        };

        self.presentation = Some(Presentation {
            swapchain: device.wrap_swapchain(swapchain, &config),
            format: config.format,
            size: config.extent,
        });
        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, _device: &Device) {
        if let Some(present) = self.presentation.take() {
            let inner = present.swapchain.release_resources();
            inner.destroy();
        }
    }

    unsafe fn acquire_image(
        &mut self,
        timeout_ns: u64,
    ) -> Result<(r::ImageView, Option<w::Suboptimal>), w::AcquireError> {
        let present = self.presentation.as_mut().unwrap();
        let sc = &mut present.swapchain;

        match synchapi::WaitForSingleObject(
            sc.waitable,
            (timeout_ns / 1_000_000) as u32,
        ) {
            winbase::WAIT_ABANDONED |
            winbase::WAIT_FAILED => return Err(w::AcquireError::DeviceLost(hal::device::DeviceLost)),
            winbase::WAIT_OBJECT_0 => (),
            winerror::WAIT_TIMEOUT => return Err(w::AcquireError::Timeout),
            hr => panic!("Unexpected wait status 0x{:X}", hr),
        }

        let index = sc.inner.GetCurrentBackBufferIndex();
        let view = r::ImageView {
            resource: sc.resources[index as usize],
            handle_srv: None,
            handle_rtv: Some(sc.rtv_heap.at(index as _, 0).cpu),
            handle_uav: None,
            handle_dsv: None,
            dxgi_format: conv::map_format(present.format).unwrap(),
            num_levels: 1,
            mip_levels: (0, 1),
            layers: (0, 1),
            kind: i::Kind::D2(present.size.width, present.size.height, 1, 1),
        };

        Ok((view, None))
    }
}

#[derive(Debug)]
pub struct Swapchain {
    pub(crate) inner: native::WeakPtr<dxgi1_4::IDXGISwapChain3>,
    pub(crate) frame_queue: VecDeque<usize>,
    #[allow(dead_code)]
    pub(crate) rtv_heap: r::DescriptorHeap,
    // need to associate raw image pointers with the swapchain so they can be properly released
    // when the swapchain is destroyed
    pub(crate) resources: Vec<native::Resource>,
    pub(crate) waitable: HANDLE,
}

impl Swapchain {
    pub(crate) unsafe fn release_resources(self) -> native::WeakPtr<dxgi1_4::IDXGISwapChain3> {
        for resource in &self.resources {
            resource.destroy();
        }
        self.rtv_heap.destroy();
        self.inner
    }
}

unsafe impl Send for Swapchain {}
unsafe impl Sync for Swapchain {}
<commit_msg>[dx12] wait for device idle on swapchain destruction<commit_after>use std::{collections::VecDeque, fmt, mem, os::raw::c_void};

use winapi::{
    shared::{
        dxgi,
        dxgi1_4,
        windef::{HWND, RECT},
        winerror,
    },
    um::{
        synchapi,
        winbase,
        winnt::HANDLE,
        winuser::GetClientRect,
    },
};

use crate::{conv, resource as r, Backend, Device, Instance, PhysicalDevice, QueueFamily};
use hal::{device::{Device as _}, format as f, image as i, window as w};

impl Instance {
    pub fn create_surface_from_hwnd(&self, hwnd: *mut c_void) -> Surface {
        Surface {
            factory: self.factory,
            wnd_handle: hwnd as *mut _,
            presentation: None,
        }
    }
}

#[derive(Debug)]
struct Presentation {
    swapchain: Swapchain,
    format: f::Format,
    size: w::Extent2D,
}

pub struct Surface {
    pub(crate) factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
    pub(crate) wnd_handle: HWND,
    presentation: Option<Presentation>,
}

impl fmt::Debug for Surface {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str("Surface")
    }
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl Surface {
    pub(crate) unsafe fn present(&self) {
        self.presentation
            .as_ref()
            .unwrap()
            .swapchain
            .inner
            .Present(1, 0);
    }
}

impl w::Surface<Backend> for Surface {
    fn supports_queue_family(&self, queue_family: &QueueFamily) -> bool {
        match queue_family {
            &QueueFamily::Present => true,
            _ => false,
        }
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        let current_extent = unsafe {
            let mut rect: RECT = mem::zeroed();
            if GetClientRect(self.wnd_handle as *mut _, &mut rect as *mut RECT) == 0 {
                panic!("GetClientRect failed");
            }
            Some(w::Extent2D {
                width: (rect.right - rect.left) as u32,
                height: (rect.bottom - rect.top) as u32,
            })
        };

        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=16, // we currently use a flip effect which supports 2..=16 buffers
            current_extent,
            extents: w::Extent2D {
                width: 16,
                height: 16,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: i::Usage::COLOR_ATTACHMENT | i::Usage::TRANSFER_SRC | i::Usage::TRANSFER_DST,
        }
    }

    fn supported_formats(&self, _physical_device: &PhysicalDevice) -> Option<Vec<f::Format>> {
        Some(vec![
            f::Format::Bgra8Srgb,
            f::Format::Bgra8Unorm,
            f::Format::Rgba8Srgb,
            f::Format::Rgba8Unorm,
            f::Format::A2b10g10r10Unorm,
            f::Format::Rgba16Sfloat,
        ])
    }
}

impl w::PresentationSurface<Backend> for Surface {
    type SwapchainImage = r::ImageView;

    unsafe fn configure_swapchain(
        &mut self,
        device: &Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::CreationError> {
        assert!(i::Usage::COLOR_ATTACHMENT.contains(config.image_usage));

        let swapchain = match self.presentation.take() {
            Some(present) => {
                if present.format == config.format && present.size == config.extent {
                    self.presentation = Some(present);
                    return Ok(());
                }
                // can't have image resources in flight used by GPU
                device.wait_idle().unwrap();

                let inner = present.swapchain.release_resources();
                let result = inner.ResizeBuffers(
                    config.image_count,
                    config.extent.width,
                    config.extent.height,
                    conv::map_format_nosrgb(config.format).unwrap(),
                    dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT,
                );
                if result != winerror::S_OK {
                    error!("ResizeBuffers failed with 0x{:x}", result as u32);
                    return Err(w::CreationError::WindowInUse(hal::device::WindowInUse));
                }
                inner
            }
            None => {
                let (swapchain, _) =
                    device.create_swapchain_impl(&config, self.wnd_handle, self.factory.clone())?;
                swapchain
            }
        };

        self.presentation = Some(Presentation {
            swapchain: device.wrap_swapchain(swapchain, &config),
            format: config.format,
            size: config.extent,
        });
        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &Device) {
        if let Some(mut present) = self.presentation.take() {
            let _ = present.swapchain.wait(winbase::INFINITE);
            let _ = device.wait_idle(); //TODO: this shouldn't be needed,
            // but it complains that the queue is still used otherwise
            let inner = present.swapchain.release_resources();
            inner.destroy();
        }
    }

    unsafe fn acquire_image(
        &mut self,
        timeout_ns: u64,
    ) -> Result<(r::ImageView, Option<w::Suboptimal>), w::AcquireError> {
        let present = self.presentation.as_mut().unwrap();
        let sc = &mut present.swapchain;

        sc.wait((timeout_ns / 1_000_000) as u32)?;

        let index = sc.inner.GetCurrentBackBufferIndex();
        let view = r::ImageView {
            resource: sc.resources[index as usize],
            handle_srv: None,
            handle_rtv: Some(sc.rtv_heap.at(index as _, 0).cpu),
            handle_uav: None,
            handle_dsv: None,
            dxgi_format: conv::map_format(present.format).unwrap(),
            num_levels: 1,
            mip_levels: (0, 1),
            layers: (0, 1),
            kind: i::Kind::D2(present.size.width, present.size.height, 1, 1),
        };

        Ok((view, None))
    }
}

#[derive(Debug)]
pub struct Swapchain {
    pub(crate) inner: native::WeakPtr<dxgi1_4::IDXGISwapChain3>,
    pub(crate) frame_queue: VecDeque<usize>,
    #[allow(dead_code)]
    pub(crate) rtv_heap: r::DescriptorHeap,
    // need to associate raw image pointers with the swapchain so they can be properly released
    // when the swapchain is destroyed
    pub(crate) resources: Vec<native::Resource>,
    pub(crate) waitable: HANDLE,
}

impl Swapchain {
    pub(crate) unsafe fn release_resources(self) -> native::WeakPtr<dxgi1_4::IDXGISwapChain3> {
        for resource in &self.resources {
            resource.destroy();
        }
        self.rtv_heap.destroy();
        self.inner
    }

    pub(crate) fn wait(&mut self, timeout_ms: u32) -> Result<(), w::AcquireError> {
        match unsafe {
            synchapi::WaitForSingleObject(self.waitable, timeout_ms)
        } {
            winbase::WAIT_ABANDONED |
            winbase::WAIT_FAILED => Err(w::AcquireError::DeviceLost(hal::device::DeviceLost)),
            winbase::WAIT_OBJECT_0 => Ok(()),
            winerror::WAIT_TIMEOUT => Err(w::AcquireError::Timeout),
            hr => panic!("Unexpected wait status 0x{:X}", hr),
        }
    }
}

unsafe impl Send for Swapchain {}
unsafe impl Sync for Swapchain {}
<|endoftext|>


<commit_before>//! # version
//!
//! Checks if the currently running version is the most up to date version and
//! if not, it will print a notification message.
//!

#[cfg(test)]
#[path = "./version_test.rs"]
mod version_test;

use crate::cache;
use crate::command;
use crate::types::{Cache, GlobalConfig};
use semver::Version;
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

static VERSION: &str = env!("CARGO_PKG_VERSION");

fn get_version_from_output(line: &str) -> Option<String> {
    let parts: Vec<&str> = line.split(' ').collect();

    if parts.len() >= 3 {
        let version_part = parts[2];
        let version = str::replace(version_part, "\"", "");

        Some(version)
    } else {
        None
    }
}

fn get_latest_version() -> Option<String> {
    let result = Command::new("cargo")
        .args(&["search", "cargo-make"])
        .output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);
            if exit_code == 0 {
                let stdout = String::from_utf8_lossy(&output.stdout);
                let lines: Vec<&str> = stdout.split('\n').collect();

                let mut output = None;
                for mut line in lines {
                    line = line.trim();

                    debug!("Checking: {}", &line);

                    if line.starts_with("cargo-make = ") {
                        output = get_version_from_output(line);

                        break;
                    }
                }

                output
            } else {
                None
            }
        }
        _ => None,
    }
}

pub(crate) fn is_newer(old_string: &str, new_string: &str, default_result: bool) -> bool {
    let old_version = Version::parse(old_string);
    match old_version {
        Ok(old_values) => {
            let new_version = Version::parse(new_string);

            match new_version {
                Ok(new_values) => {
                    if new_values.major > old_values.major {
                        true
                    } else if new_values.major == old_values.major {
                        if new_values.minor > old_values.minor {
                            true
                        } else {
                            new_values.minor == old_values.minor
                                && new_values.patch > old_values.patch
                        }
                    } else {
                        false
                    }
                }
                _ => default_result,
            }
        }
        _ => default_result,
    }
}

pub(crate) fn is_newer_found(version_string: &str) -> bool {
    debug!("Checking Version: {}", &version_string);

    is_newer(&VERSION, &version_string, false)
}

fn print_notification(latest_string: &str) {
    warn!("#####################################################################");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#                  NEW CARGO-MAKE VERSION FOUND!!!                  #");
    warn!(
        "#{:^67}#",
        format!("Current: {}, Latest: {}", VERSION, latest_string)
    );
    warn!("#    Run 'cargo install --force cargo-make' to get latest version   #");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#####################################################################");
}

fn get_now_as_seconds() -> u64 {
    let now = SystemTime::now();
    match now.duration_since(UNIX_EPOCH) {
        Ok(duration) => duration.as_secs(),
        _ => 0,
    }
}

fn has_amount_of_days_passed_from_last_check(days: u64, last_check_seconds: u64) -> bool {
    let now_seconds = get_now_as_seconds();
    if now_seconds > 0 && days > 0 {
        if last_check_seconds > now_seconds {
            false
        } else {
            let diff_seconds = now_seconds - last_check_seconds;
            let minimum_diff_seconds = days * 24 * 60 * 60;

            diff_seconds >= minimum_diff_seconds
        }
    } else {
        true
    }
}

fn has_amount_of_days_passed(days: u64, cache_data: &Cache) -> bool {
    match cache_data.last_update_check {
        Some(last_check_seconds) => {
            has_amount_of_days_passed_from_last_check(days, last_check_seconds)
        }
        None => true,
    }
}

fn get_days(global_config: &GlobalConfig) -> u64 {
    match global_config.update_check_minimum_interval {
        Some(ref value) => {
            if value == "always" {
                0
            } else if value == "daily" {
                1
            } else if value == "monthly" {
                30
            } else {
                // default to weekly
                7
            }
        }
        None => 7, // default to weekly
    }
}

pub(crate) fn should_check(global_config: &GlobalConfig) -> bool {
    let days = get_days(global_config);

    if days > 0 {
        let cache_data = cache::load();
        has_amount_of_days_passed(1, &cache_data)
    } else {
        true
    }
}

pub(crate) fn check() {
    let latest = get_latest_version();

    let mut cache_data = cache::load();
    let now = get_now_as_seconds();
    if now > 0 {
        cache_data.last_update_check = Some(now);
        cache::store(&cache_data);
    }

    match latest {
        Some(value) => {
            if is_newer_found(&value) {
                print_notification(&value);
            }
        }
        None => (),
    }
}
<commit_msg>Revert change of `src/lib/version.rs`<commit_after>//! # version
//!
//! Checks if the currently running version is the most up to date version and
//! if not, it will print a notification message.
//!

#[cfg(test)]
#[path = "./version_test.rs"]
mod version_test;

use crate::cache;
use crate::command;
use crate::types::{Cache, GlobalConfig};
use semver::Version;
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

static VERSION: &str = env!("CARGO_PKG_VERSION");

fn get_version_from_output(line: &str) -> Option<String> {
    let parts: Vec<&str> = line.split(' ').collect();

    if parts.len() >= 3 {
        let version_part = parts[2];
        let version = str::replace(version_part, "\"", "");

        Some(version)
    } else {
        None
    }
}

fn get_latest_version() -> Option<String> {
    let result = Command::new("cargo")
        .arg("search")
        .arg("cargo-make")
        .output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);
            if exit_code == 0 {
                let stdout = String::from_utf8_lossy(&output.stdout);
                let lines: Vec<&str> = stdout.split('\n').collect();

                let mut output = None;
                for mut line in lines {
                    line = line.trim();

                    debug!("Checking: {}", &line);

                    if line.starts_with("cargo-make = ") {
                        output = get_version_from_output(line);

                        break;
                    }
                }

                output
            } else {
                None
            }
        }
        _ => None,
    }
}

pub(crate) fn is_newer(old_string: &str, new_string: &str, default_result: bool) -> bool {
    let old_version = Version::parse(old_string);
    match old_version {
        Ok(old_values) => {
            let new_version = Version::parse(new_string);

            match new_version {
                Ok(new_values) => {
                    if new_values.major > old_values.major {
                        true
                    } else if new_values.major == old_values.major {
                        if new_values.minor > old_values.minor {
                            true
                        } else {
                            new_values.minor == old_values.minor
                                && new_values.patch > old_values.patch
                        }
                    } else {
                        false
                    }
                }
                _ => default_result,
            }
        }
        _ => default_result,
    }
}

pub(crate) fn is_newer_found(version_string: &str) -> bool {
    debug!("Checking Version: {}", &version_string);

    is_newer(&VERSION, &version_string, false)
}

fn print_notification(latest_string: &str) {
    warn!("#####################################################################");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#                  NEW CARGO-MAKE VERSION FOUND!!!                  #");
    warn!(
        "#{:^67}#",
        format!("Current: {}, Latest: {}", VERSION, latest_string)
    );
    warn!("#    Run 'cargo install --force cargo-make' to get latest version   #");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#####################################################################");
}

fn get_now_as_seconds() -> u64 {
    let now = SystemTime::now();
    match now.duration_since(UNIX_EPOCH) {
        Ok(duration) => duration.as_secs(),
        _ => 0,
    }
}

fn has_amount_of_days_passed_from_last_check(days: u64, last_check_seconds: u64) -> bool {
    let now_seconds = get_now_as_seconds();
    if now_seconds > 0 && days > 0 {
        if last_check_seconds > now_seconds {
            false
        } else {
            let diff_seconds = now_seconds - last_check_seconds;
            let minimum_diff_seconds = days * 24 * 60 * 60;

            diff_seconds >= minimum_diff_seconds
        }
    } else {
        true
    }
}

fn has_amount_of_days_passed(days: u64, cache_data: &Cache) -> bool {
    match cache_data.last_update_check {
        Some(last_check_seconds) => {
            has_amount_of_days_passed_from_last_check(days, last_check_seconds)
        }
        None => true,
    }
}

fn get_days(global_config: &GlobalConfig) -> u64 {
    match global_config.update_check_minimum_interval {
        Some(ref value) => {
            if value == "always" {
                0
            } else if value == "daily" {
                1
            } else if value == "monthly" {
                30
            } else {
                // default to weekly
                7
            }
        }
        None => 7, // default to weekly
    }
}

pub(crate) fn should_check(global_config: &GlobalConfig) -> bool {
    let days = get_days(global_config);

    if days > 0 {
        let cache_data = cache::load();
        has_amount_of_days_passed(1, &cache_data)
    } else {
        true
    }
}

pub(crate) fn check() {
    let latest = get_latest_version();

    let mut cache_data = cache::load();
    let now = get_now_as_seconds();
    if now > 0 {
        cache_data.last_update_check = Some(now);
        cache::store(&cache_data);
    }

    match latest {
        Some(value) => {
            if is_newer_found(&value) {
                print_notification(&value);
            }
        }
        None => (),
    }
}
<|endoftext|>


<commit_before>//! Unsafe pointer utility functions

export addr_of;
export assimilate;
export mut_addr_of;
export offset;
export const_offset;
export mut_offset;
export null;
export is_null;
export is_not_null;
export memcpy;
export memmove;
export memset;
export to_uint;
export ref_eq;
export buf_len;
export position;
export Ptr;

import libc::{c_void, size_t};

#[nolink]
#[abi = "cdecl"]
extern mod libc_ {
    #[rust_stack]
    fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memset(dest: *c_void, c: libc::c_int, len: libc::size_t) -> *c_void;
}

#[abi = "rust-intrinsic"]
extern mod rusti {
    fn addr_of<T>(val: T) -> *T;
}

/// Get an unsafe pointer to a value
#[inline(always)]
pure fn addr_of<T>(val: T) -> *T { unchecked { rusti::addr_of(val) } }

/// Get an unsafe mut pointer to a value
#[inline(always)]
pure fn mut_addr_of<T>(val: T) -> *mut T {
    unsafe {
        unsafe::reinterpret_cast(rusti::addr_of(val))
    }
}

/// Calculate the offset from a pointer
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T {
    unsafe {
        (ptr as uint + count * sys::size_of::<T>()) as *T
    }
}

/// Calculate the offset from a const pointer
#[inline(always)]
fn const_offset<T>(ptr: *const T, count: uint) -> *const T {
    unsafe {
        (ptr as uint + count * sys::size_of::<T>()) as *T
    }
}

/// Calculate the offset from a mut pointer
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
    (ptr as uint + count * sys::size_of::<T>()) as *mut T
}

/// Return the offset of the first null pointer in `buf`.
#[inline(always)]
unsafe fn buf_len<T>(buf: **T) -> uint {
    position(buf, |i| i == null())
}

/// Return the first offset `i` such that `f(buf[i]) == true`.
#[inline(always)]
unsafe fn position<T>(buf: *T, f: fn(T) -> bool) -> uint {
    let mut i = 0u;
    loop {
        if f(*offset(buf, i)) { return i; }
        else { i += 1u; }
    }
}

/// Create an unsafe null pointer
#[inline(always)]
pure fn null<T>() -> *T { unsafe { unsafe::reinterpret_cast(0u) } }

/// Returns true if the pointer is equal to the null pointer.
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }

/// Returns true if the pointer is not equal to the null pointer.
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }

/**
 * Copies data from one location to another
 *
 * Copies `count` elements (not bytes) from `src` to `dst`. The source
 * and destination may not overlap.
 */
#[inline(always)]
unsafe fn memcpy<T>(dst: *T, src: *T, count: uint) {
    let n = count * sys::size_of::<T>();
    libc_::memcpy(dst as *c_void, src as *c_void, n as size_t);
}

/**
 * Copies data from one location to another
 *
 * Copies `count` elements (not bytes) from `src` to `dst`. The source
 * and destination may overlap.
 */
#[inline(always)]
unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memmove(dst as *c_void, src as *c_void, n as size_t);
}

#[inline(always)]
unsafe fn memset<T>(dst: *mut T, c: int, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memset(dst as *c_void, c as libc::c_int, n as size_t);
}

/**
  Transform a region pointer - &T - to an unsafe pointer - *T.
  This is safe, but is implemented with an unsafe block due to
  reinterpret_cast.

  ("assimilate" because it makes the pointer forget its region.)
*/
#[inline(always)]
fn assimilate<T>(thing: &T) -> *T unsafe {
    unsafe::reinterpret_cast(thing)
}
/**
  Cast a region pointer - &T - to a uint.
  This is safe, but is implemented with an unsafe block due to
  reinterpret_cast.

  (I couldn't think of a cutesy name for this one.)
*/
#[inline(always)]
fn to_uint<T>(thing: &T) -> uint unsafe {
    unsafe::reinterpret_cast(thing)
}

/// Determine if two borrowed pointers point to the same thing.
#[inline(always)]
fn ref_eq<T>(thing: &a/T, other: &b/T) -> bool {
    to_uint(thing) == to_uint(other)
}

trait Ptr {
    pure fn is_null() -> bool;
    pure fn is_not_null() -> bool;
}

/// Extension methods for pointers
impl<T> *T: Ptr {
    /// Returns true if the pointer is equal to the null pointer.
    pure fn is_null() -> bool { is_null(self) }

    /// Returns true if the pointer is not equal to the null pointer.
    pure fn is_not_null() -> bool { is_not_null(self) }
}

#[test]
fn test() {
    unsafe {
        type Pair = {mut fst: int, mut snd: int};
        let p = {mut fst: 10, mut snd: 20};
        let pptr: *mut Pair = mut_addr_of(p);
        let iptr: *mut int = unsafe::reinterpret_cast(pptr);
        assert (*iptr == 10);;
        *iptr = 30;
        assert (*iptr == 30);
        assert (p.fst == 30);;

        *pptr = {mut fst: 50, mut snd: 60};
        assert (*iptr == 50);
        assert (p.fst == 50);
        assert (p.snd == 60);

        let v0 = ~[32000u16, 32001u16, 32002u16];
        let v1 = ~[0u16, 0u16, 0u16];

        ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 1u),
                    ptr::offset(vec::unsafe::to_ptr(v0), 1u), 1u);
        assert (v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
        ptr::memcpy(vec::unsafe::to_ptr(v1),
                    ptr::offset(vec::unsafe::to_ptr(v0), 2u), 1u);
        assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
        ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 2u),
                    vec::unsafe::to_ptr(v0), 1u);
        assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
    }
}

#[test]
fn test_position() {
    import str::as_c_str;
    import libc::c_char;

    let s = ~"hello";
    unsafe {
        assert 2u == as_c_str(s, |p| position(p, |c| c == 'l' as c_char));
        assert 4u == as_c_str(s, |p| position(p, |c| c == 'o' as c_char));
        assert 5u == as_c_str(s, |p| position(p, |c| c == 0 as c_char));
    }
}

#[test]
fn test_buf_len() {
    let s0 = ~"hello";
    let s1 = ~"there";
    let s2 = ~"thing";
    do str::as_c_str(s0) |p0| {
        do str::as_c_str(s1) |p1| {
            do str::as_c_str(s2) |p2| {
                let v = ~[p0, p1, p2, null()];
                do vec::as_buf(v) |vp, len| {
                    assert unsafe { buf_len(vp) } == 3u;
                    assert len == 4u;
                }
            }
        }
    }
}

#[test]
fn test_is_null() {
   let p: *int = ptr::null();
   assert p.is_null();
   assert !p.is_not_null();

   let q = ptr::offset(p, 1u);
   assert !q.is_null();
   assert q.is_not_null();
}
<commit_msg>libcore: Implement equality for pointers<commit_after>//! Unsafe pointer utility functions

export addr_of;
export assimilate;
export mut_addr_of;
export offset;
export const_offset;
export mut_offset;
export null;
export is_null;
export is_not_null;
export memcpy;
export memmove;
export memset;
export to_uint;
export ref_eq;
export buf_len;
export position;
export Ptr;

import cmp::Eq;
import libc::{c_void, size_t};

#[nolink]
#[abi = "cdecl"]
extern mod libc_ {
    #[rust_stack]
    fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memset(dest: *c_void, c: libc::c_int, len: libc::size_t) -> *c_void;
}

#[abi = "rust-intrinsic"]
extern mod rusti {
    fn addr_of<T>(val: T) -> *T;
}

/// Get an unsafe pointer to a value
#[inline(always)]
pure fn addr_of<T>(val: T) -> *T { unchecked { rusti::addr_of(val) } }

/// Get an unsafe mut pointer to a value
#[inline(always)]
pure fn mut_addr_of<T>(val: T) -> *mut T {
    unsafe {
        unsafe::reinterpret_cast(rusti::addr_of(val))
    }
}

/// Calculate the offset from a pointer
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T {
    unsafe {
        (ptr as uint + count * sys::size_of::<T>()) as *T
    }
}

/// Calculate the offset from a const pointer
#[inline(always)]
fn const_offset<T>(ptr: *const T, count: uint) -> *const T {
    unsafe {
        (ptr as uint + count * sys::size_of::<T>()) as *T
    }
}

/// Calculate the offset from a mut pointer
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
    (ptr as uint + count * sys::size_of::<T>()) as *mut T
}

/// Return the offset of the first null pointer in `buf`.
#[inline(always)]
unsafe fn buf_len<T>(buf: **T) -> uint {
    position(buf, |i| i == null())
}

/// Return the first offset `i` such that `f(buf[i]) == true`.
#[inline(always)]
unsafe fn position<T>(buf: *T, f: fn(T) -> bool) -> uint {
    let mut i = 0u;
    loop {
        if f(*offset(buf, i)) { return i; }
        else { i += 1u; }
    }
}

/// Create an unsafe null pointer
#[inline(always)]
pure fn null<T>() -> *T { unsafe { unsafe::reinterpret_cast(0u) } }

/// Returns true if the pointer is equal to the null pointer.
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }

/// Returns true if the pointer is not equal to the null pointer.
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }

/**
 * Copies data from one location to another
 *
 * Copies `count` elements (not bytes) from `src` to `dst`. The source
 * and destination may not overlap.
 */
#[inline(always)]
unsafe fn memcpy<T>(dst: *T, src: *T, count: uint) {
    let n = count * sys::size_of::<T>();
    libc_::memcpy(dst as *c_void, src as *c_void, n as size_t);
}

/**
 * Copies data from one location to another
 *
 * Copies `count` elements (not bytes) from `src` to `dst`. The source
 * and destination may overlap.
 */
#[inline(always)]
unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memmove(dst as *c_void, src as *c_void, n as size_t);
}

#[inline(always)]
unsafe fn memset<T>(dst: *mut T, c: int, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memset(dst as *c_void, c as libc::c_int, n as size_t);
}

/**
  Transform a region pointer - &T - to an unsafe pointer - *T.
  This is safe, but is implemented with an unsafe block due to
  reinterpret_cast.

  ("assimilate" because it makes the pointer forget its region.)
*/
#[inline(always)]
fn assimilate<T>(thing: &T) -> *T unsafe {
    unsafe::reinterpret_cast(thing)
}
/**
  Cast a region pointer - &T - to a uint.
  This is safe, but is implemented with an unsafe block due to
  reinterpret_cast.

  (I couldn't think of a cutesy name for this one.)
*/
#[inline(always)]
fn to_uint<T>(thing: &T) -> uint unsafe {
    unsafe::reinterpret_cast(thing)
}

/// Determine if two borrowed pointers point to the same thing.
#[inline(always)]
fn ref_eq<T>(thing: &a/T, other: &b/T) -> bool {
    to_uint(thing) == to_uint(other)
}

trait Ptr {
    pure fn is_null() -> bool;
    pure fn is_not_null() -> bool;
}

/// Extension methods for pointers
impl<T> *T: Ptr {
    /// Returns true if the pointer is equal to the null pointer.
    pure fn is_null() -> bool { is_null(self) }

    /// Returns true if the pointer is not equal to the null pointer.
    pure fn is_not_null() -> bool { is_not_null(self) }
}

// Equality for pointers
impl<T: Eq> *T : Eq {
    pure fn eq(&&other: *T) -> bool { self == other }
}

#[test]
fn test() {
    unsafe {
        type Pair = {mut fst: int, mut snd: int};
        let p = {mut fst: 10, mut snd: 20};
        let pptr: *mut Pair = mut_addr_of(p);
        let iptr: *mut int = unsafe::reinterpret_cast(pptr);
        assert (*iptr == 10);;
        *iptr = 30;
        assert (*iptr == 30);
        assert (p.fst == 30);;

        *pptr = {mut fst: 50, mut snd: 60};
        assert (*iptr == 50);
        assert (p.fst == 50);
        assert (p.snd == 60);

        let v0 = ~[32000u16, 32001u16, 32002u16];
        let v1 = ~[0u16, 0u16, 0u16];

        ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 1u),
                    ptr::offset(vec::unsafe::to_ptr(v0), 1u), 1u);
        assert (v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
        ptr::memcpy(vec::unsafe::to_ptr(v1),
                    ptr::offset(vec::unsafe::to_ptr(v0), 2u), 1u);
        assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
        ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 2u),
                    vec::unsafe::to_ptr(v0), 1u);
        assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
    }
}

#[test]
fn test_position() {
    import str::as_c_str;
    import libc::c_char;

    let s = ~"hello";
    unsafe {
        assert 2u == as_c_str(s, |p| position(p, |c| c == 'l' as c_char));
        assert 4u == as_c_str(s, |p| position(p, |c| c == 'o' as c_char));
        assert 5u == as_c_str(s, |p| position(p, |c| c == 0 as c_char));
    }
}

#[test]
fn test_buf_len() {
    let s0 = ~"hello";
    let s1 = ~"there";
    let s2 = ~"thing";
    do str::as_c_str(s0) |p0| {
        do str::as_c_str(s1) |p1| {
            do str::as_c_str(s2) |p2| {
                let v = ~[p0, p1, p2, null()];
                do vec::as_buf(v) |vp, len| {
                    assert unsafe { buf_len(vp) } == 3u;
                    assert len == 4u;
                }
            }
        }
    }
}

#[test]
fn test_is_null() {
   let p: *int = ptr::null();
   assert p.is_null();
   assert !p.is_not_null();

   let q = ptr::offset(p, 1u);
   assert !q.is_null();
   assert q.is_not_null();
}
<|endoftext|>