//===--- Casting.h - Swift type-casting runtime support ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Swift runtime functions for casting values.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_RUNTIME_CASTING_H
#define SWIFT_RUNTIME_CASTING_H

#include "swift/Runtime/Metadata.h"

namespace swift {

/// Perform a checked dynamic cast of a value to a target type.
///
/// \param dest A buffer into which to write the destination value.
/// In all cases, this will be left uninitialized if the cast fails.
///
/// \param src Pointer to the source value to cast.  This may be left
///   uninitialized after the operation, depending on the flags.
///
/// \param targetType The type to which we are casting.
///
/// \param srcType The static type of the source value.
///
/// \param flags Flags to control the operation.
///
/// \return true if the cast succeeded. Depending on the flags,
///   swift_dynamicCast may fail rather than return false.
SWIFT_RUNTIME_EXPORT
bool
swift_dynamicCast(OpaqueValue *dest, OpaqueValue *src,
                  const Metadata *srcType,
                  const Metadata *targetType,
                  DynamicCastFlags flags);

/// Checked dynamic cast to a Swift class type.
///
/// \param object The object to cast.
/// \param targetType The type to which we are casting, which is known to be
/// a Swift class type.
///
/// \returns the object if the cast succeeds, or null otherwise.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastClass(const void *object, const ClassMetadata *targetType);

/// Unconditional, checked dynamic cast to a Swift class type.
///
/// Aborts if the object isn't of the target type.
///
/// \param object The object to cast.
/// \param targetType The type to which we are casting, which is known to be
/// a Swift class type.
/// \param file The source filename from which to report failure. May be null.
/// \param line The source line from which to report failure.
/// \param column The source column from which to report failure.
///
/// \returns the object.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastClassUnconditional(const void *object,
                                    const ClassMetadata *targetType,
                                    const char *file, unsigned line, unsigned column);

#if SWIFT_OBJC_INTEROP
/// Checked Objective-C-style dynamic cast to a class type.
///
/// \param object The object to cast, or nil.
/// \param targetType The type to which we are casting, which is known to be
/// a class type, but not necessarily valid type metadata.
///
/// \returns the object if the cast succeeds, or null otherwise.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastObjCClass(const void *object, const ClassMetadata *targetType);

/// Checked dynamic cast to a foreign class type.
///
/// \param object The object to cast, or nil.
/// \param targetType The type to which we are casting, which is known to be
/// a foreign class type.
///
/// \returns the object if the cast succeeds, or null otherwise.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastForeignClass(const void *object,
                              const ForeignClassMetadata *targetType);

/// Unconditional, checked, Objective-C-style dynamic cast to a class
/// type.
///
/// Aborts if the object isn't of the target type.
/// Note that unlike swift_dynamicCastClassUnconditional, this does not abort
/// if the object is 'nil'.
///
/// \param object The object to cast, or nil.
/// \param targetType The type to which we are casting, which is known to be
/// a class type, but not necessarily valid type metadata.
/// \param file The source filename from which to report failure. May be null.
/// \param line The source line from which to report failure.
/// \param column The source column from which to report failure.
///
/// \returns the object.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastObjCClassUnconditional(const void *object,
                                        const ClassMetadata *targetType,
                                        const char *file, unsigned line, unsigned column);

/// Unconditional, checked dynamic cast to a foreign class type.
///
/// \param object The object to cast, or nil.
/// \param targetType The type to which we are casting, which is known to be
/// a foreign class type.
/// \param file The source filename from which to report failure. May be null.
/// \param line The source line from which to report failure.
/// \param column The source column from which to report failure.
///
/// \returns the object if the cast succeeds, or null otherwise.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastForeignClassUnconditional(
  const void *object,
  const ForeignClassMetadata *targetType,
  const char *file, unsigned line, unsigned column);
#endif

/// Checked dynamic cast of a class instance pointer to the given type.
///
/// \param object The class instance to cast.
///
/// \param targetType The type to which we are casting, which may be either a
/// class type or a wrapped Objective-C class type.
///
/// \returns the object, or null if it doesn't have the given target type.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastUnknownClass(const void *object, const Metadata *targetType);

/// Unconditional checked dynamic cast of a class instance pointer to
/// the given type.
///
/// Aborts if the object isn't of the target type.
///
/// \param object The class instance to cast.
///
/// \param targetType The type to which we are casting, which may be either a
/// class type or a wrapped Objective-C class type.
///
/// \param file The source filename from which to report failure. May be null.
/// \param line The source line from which to report failure.
/// \param column The source column from which to report failure.
///
/// \returns the object.
SWIFT_RUNTIME_EXPORT
const void *
swift_dynamicCastUnknownClassUnconditional(const void *object,
                                           const Metadata *targetType,
                                           const char *file, unsigned line, unsigned column);

SWIFT_RUNTIME_EXPORT
const Metadata *
swift_dynamicCastMetatype(const Metadata *sourceType,
                          const Metadata *targetType);
SWIFT_RUNTIME_EXPORT
const Metadata *
swift_dynamicCastMetatypeUnconditional(const Metadata *sourceType,
                                       const Metadata *targetType,
                                       const char *file, unsigned line, unsigned column);
#if SWIFT_OBJC_INTEROP
SWIFT_RUNTIME_EXPORT
const ClassMetadata *
swift_dynamicCastObjCClassMetatype(const ClassMetadata *sourceType,
                                   const ClassMetadata *targetType);
SWIFT_RUNTIME_EXPORT
const ClassMetadata *
swift_dynamicCastObjCClassMetatypeUnconditional(const ClassMetadata *sourceType,
                                                const ClassMetadata *targetType,
                                                const char *file, unsigned line, unsigned column);
#endif

SWIFT_RUNTIME_EXPORT
const ClassMetadata *
swift_dynamicCastForeignClassMetatype(const ClassMetadata *sourceType,
                                   const ClassMetadata *targetType);
SWIFT_RUNTIME_EXPORT
const ClassMetadata *
swift_dynamicCastForeignClassMetatypeUnconditional(
  const ClassMetadata *sourceType,
  const ClassMetadata *targetType,
  const char *file, unsigned line, unsigned column);

/// Return the dynamic type of an opaque value.
///
/// \param value An opaque value.
/// \param self  The static type metadata for the opaque value and the result
///              type value.
/// \param existentialMetatype Whether the result type value is an existential
///                            metatype. If `self` is an existential type,
///                            then a `false` value indicates that the result
///                            is of concrete metatype type `self.Protocol`,
///                            and existential containers will not be projected
///                            through. A `true` value indicates that the result
///                            is of existential metatype type `self.Type`,
///                            so existential containers can be projected
///                            through as long as a subtype relationship holds
///                            from `self` to the contained dynamic type.
SWIFT_RUNTIME_EXPORT
const Metadata *
swift_getDynamicType(OpaqueValue *value, const Metadata *self,
                     bool existentialMetatype);

/// Fetch the type metadata associated with the formal dynamic
/// type of the given (possibly Objective-C) object.  The formal
/// dynamic type ignores dynamic subclasses such as those introduced
/// by KVO. See [NOTE: Dynamic-subclass-KVO]
///
/// The object pointer may be a tagged pointer, but cannot be null.
SWIFT_RUNTIME_EXPORT
const Metadata *swift_getObjectType(HeapObject *object);

/// Check whether a type conforms to a given native Swift protocol,
/// visible from the named module.
///
/// If so, returns a pointer to the witness table for its conformance.
/// Returns void if the type does not conform to the protocol.
///
/// \param type The metadata for the type for which to do the conformance
///             check.
/// \param protocol The protocol descriptor for the protocol to check
///                 conformance for. This pointer does not have ptrauth applied.
SWIFT_RUNTIME_EXPORT
const WitnessTable *swift_conformsToProtocol(const Metadata *type,
                                             const void *protocol);

/// Check whether a type conforms to a given native Swift protocol. Identical to
/// swift_conformsToProtocol, except that the protocol parameter has a ptrauth
/// signature on ARM64e that is signed with a process independent key.
SWIFT_RUNTIME_EXPORT
const WitnessTable *
swift_conformsToProtocol2(const Metadata *type,
                          const ProtocolDescriptor *protocol);

/// Check whether a type conforms to a given native Swift protocol. Identical to
/// swift_conformsToProtocol, except that the protocol parameter has a ptrauth
/// signature on ARM64e that is signed with a process dependent key.
SWIFT_RUNTIME_EXPORT
const WitnessTable *
swift_conformsToProtocolCommon(const Metadata *type,
                               const ProtocolDescriptor *protocol);

/// The size of the ConformanceExecutionContext structure.
SWIFT_RUNTIME_EXPORT
size_t swift_ConformanceExecutionContextSize;

/// Check whether a type conforms to a given native Swift protocol. This
/// is similar to swift_conformsToProtocolCommon, but allows the caller to
/// either capture the execution context (in *context).
SWIFT_RUNTIME_EXPORT
const WitnessTable *
swift_conformsToProtocolWithExecutionContext(
    const Metadata *type,
    const ProtocolDescriptor *protocol,
    ConformanceExecutionContext *context);

/// Determine whether this function is being executed within the execution
/// context for a conformance. For example, if the conformance is
/// isolated to a given global actor, checks whether this code is running on
/// that global actor's executor.
///
/// The context should have been filled in by
/// swift_conformsToProtocolWithExecutionContext.
SWIFT_RUNTIME_EXPORT
bool swift_isInConformanceExecutionContext(
    const Metadata *type,
    const ConformanceExecutionContext *context);

} // end namespace swift

#endif // SWIFT_RUNTIME_CASTING_H
