xpcom/ds/nsVariant.cpp
author Petru Lingurar <petru.lingurar@softvision.ro>
Fri, 13 Jul 2018 17:16:37 +0300
changeset 426733 c2b1f1b52866d2c58f5e23fe2df97c9127ebcacf
parent 414199 90e79480ebc68009799722ec9882df00f3ec986f
child 428508 7e2e13953e19169da602f50c51c7edc9b7706200
permissions -rw-r--r--
Bug 1385464 - Start using support library v. 26; r=nalexander This patch also: Resolves missing resources and api changes - LeanplumActionBarActivity was removed because Support Library 26 deprecated ActionBarActivity. Class was already not in use. - CustomTabsService added two new methods which we need to override. Tested to make sure that previous functionality was maintained but with the addition of the two new methods maybe that feature could be improved. - For checking layout direction we'll use our own new method from ViewUtil which mimics what the now restricted method from the support library would do. - Upgraded to use AppCompatResources#getDrawable(..) in place of the now restricted AppCompatDrawableManager.get().getDrawable(..). Resolves obscure leaks and crashes after the upgrade - LoaderManager.destroyLoader(..) was added before the existing call to LoaderManager.restartLoader(..) to prevent potential Cursor leaks - Disable website suggestions depending on the address bar inputs when running in automation to avoid Robocop tests failing (they were entering serially maybe 100 characters in <5 ms which created around that many new Threads, operation that could cause the Executor to throw a RejectedExecutionException) At the moment this functionality is not covered by tests anyway and it was the only fix I could find that would not involve changing the whole implemenation for address bar suggestions, implementation which in the real world works ok. MozReview-Commit-ID: 2fX1SBHiSh0

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsVariant.h"
#include "prprf.h"
#include "prdtoa.h"
#include <math.h>
#include "nsCycleCollectionParticipant.h"
#include "xptinfo.h"
#include "nsReadableUtils.h"
#include "nsMemory.h"
#include "nsString.h"
#include "nsCRTGlue.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Printf.h"

/***************************************************************************/
// Helpers for static convert functions...

static nsresult
String2Double(const char* aString, double* aResult)
{
  char* next;
  double value = PR_strtod(aString, &next);
  if (next == aString) {
    return NS_ERROR_CANNOT_CONVERT_DATA;
  }
  *aResult = value;
  return NS_OK;
}

static nsresult
AString2Double(const nsAString& aString, double* aResult)
{
  char* pChars = ToNewCString(aString);
  if (!pChars) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  nsresult rv = String2Double(pChars, aResult);
  free(pChars);
  return rv;
}

static nsresult
AUTF8String2Double(const nsAUTF8String& aString, double* aResult)
{
  return String2Double(PromiseFlatUTF8String(aString).get(), aResult);
}

static nsresult
ACString2Double(const nsACString& aString, double* aResult)
{
  return String2Double(PromiseFlatCString(aString).get(), aResult);
}

// Fills aOutData with double, uint32_t, or int32_t.
// Returns NS_OK, an error code, or a non-NS_OK success code
nsresult
nsDiscriminatedUnion::ToManageableNumber(nsDiscriminatedUnion* aOutData) const
{
  nsresult rv;

  switch (mType) {
    // This group results in a int32_t...

#define CASE__NUMBER_INT32(type_, member_)                                    \
    case nsIDataType::type_ :                                                 \
        aOutData->u.mInt32Value = u.member_ ;                                 \
        aOutData->mType = nsIDataType::VTYPE_INT32;                           \
        return NS_OK;

    CASE__NUMBER_INT32(VTYPE_INT8,   mInt8Value)
    CASE__NUMBER_INT32(VTYPE_INT16,  mInt16Value)
    CASE__NUMBER_INT32(VTYPE_INT32,  mInt32Value)
    CASE__NUMBER_INT32(VTYPE_UINT8,  mUint8Value)
    CASE__NUMBER_INT32(VTYPE_UINT16, mUint16Value)
    CASE__NUMBER_INT32(VTYPE_BOOL,   mBoolValue)
    CASE__NUMBER_INT32(VTYPE_CHAR,   mCharValue)
    CASE__NUMBER_INT32(VTYPE_WCHAR,  mWCharValue)

#undef CASE__NUMBER_INT32

    // This group results in a uint32_t...

    case nsIDataType::VTYPE_UINT32:
      aOutData->u.mInt32Value = u.mUint32Value;
      aOutData->mType = nsIDataType::VTYPE_INT32;
      return NS_OK;

    // This group results in a double...

    case nsIDataType::VTYPE_INT64:
    case nsIDataType::VTYPE_UINT64:
      // XXX Need boundary checking here.
      // We may need to return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
      aOutData->u.mDoubleValue = double(u.mInt64Value);
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_FLOAT:
      aOutData->u.mDoubleValue = u.mFloatValue;
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_DOUBLE:
      aOutData->u.mDoubleValue = u.mDoubleValue;
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      rv = String2Double(u.str.mStringValue, &aOutData->u.mDoubleValue);
      if (NS_FAILED(rv)) {
        return rv;
      }
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_ASTRING:
      rv = AString2Double(*u.mAStringValue, &aOutData->u.mDoubleValue);
      if (NS_FAILED(rv)) {
        return rv;
      }
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_UTF8STRING:
      rv = AUTF8String2Double(*u.mUTF8StringValue,
                              &aOutData->u.mDoubleValue);
      if (NS_FAILED(rv)) {
        return rv;
      }
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_CSTRING:
      rv = ACString2Double(*u.mCStringValue,
                           &aOutData->u.mDoubleValue);
      if (NS_FAILED(rv)) {
        return rv;
      }
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      rv = AString2Double(nsDependentString(u.wstr.mWStringValue),
                          &aOutData->u.mDoubleValue);
      if (NS_FAILED(rv)) {
        return rv;
      }
      aOutData->mType = nsIDataType::VTYPE_DOUBLE;
      return NS_OK;

    // This group fails...

    case nsIDataType::VTYPE_VOID:
    case nsIDataType::VTYPE_ID:
    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
    case nsIDataType::VTYPE_ARRAY:
    case nsIDataType::VTYPE_EMPTY_ARRAY:
    case nsIDataType::VTYPE_EMPTY:
    default:
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }
}

/***************************************************************************/
// Array helpers...

void
nsDiscriminatedUnion::FreeArray()
{
  NS_ASSERTION(mType == nsIDataType::VTYPE_ARRAY, "bad FreeArray call");
  NS_ASSERTION(u.array.mArrayValue, "bad array");
  NS_ASSERTION(u.array.mArrayCount, "bad array count");

#define CASE__FREE_ARRAY_PTR(type_, ctype_)                                   \
        case nsIDataType::type_ :                                             \
        {                                                                     \
            ctype_** p = (ctype_**) u.array.mArrayValue;                      \
            for (uint32_t i = u.array.mArrayCount; i > 0; p++, i--)           \
                if (*p)                                                       \
                    free((char*)*p);                                          \
            break;                                                            \
        }

#define CASE__FREE_ARRAY_IFACE(type_, ctype_)                                 \
        case nsIDataType::type_ :                                             \
        {                                                                     \
            ctype_** p = (ctype_**) u.array.mArrayValue;                      \
            for (uint32_t i = u.array.mArrayCount; i > 0; p++, i--)           \
                if (*p)                                                       \
                    (*p)->Release();                                          \
            break;                                                            \
        }

  switch (u.array.mArrayType) {
    case nsIDataType::VTYPE_INT8:
    case nsIDataType::VTYPE_INT16:
    case nsIDataType::VTYPE_INT32:
    case nsIDataType::VTYPE_INT64:
    case nsIDataType::VTYPE_UINT8:
    case nsIDataType::VTYPE_UINT16:
    case nsIDataType::VTYPE_UINT32:
    case nsIDataType::VTYPE_UINT64:
    case nsIDataType::VTYPE_FLOAT:
    case nsIDataType::VTYPE_DOUBLE:
    case nsIDataType::VTYPE_BOOL:
    case nsIDataType::VTYPE_CHAR:
    case nsIDataType::VTYPE_WCHAR:
      break;

    // XXX We ASSUME that "array of nsID" means "array of pointers to nsID".
    CASE__FREE_ARRAY_PTR(VTYPE_ID, nsID)
    CASE__FREE_ARRAY_PTR(VTYPE_CHAR_STR, char)
    CASE__FREE_ARRAY_PTR(VTYPE_WCHAR_STR, char16_t)
    CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE, nsISupports)
    CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE_IS, nsISupports)

    // The rest are illegal.
    case nsIDataType::VTYPE_VOID:
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_UTF8STRING:
    case nsIDataType::VTYPE_CSTRING:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
    case nsIDataType::VTYPE_ARRAY:
    case nsIDataType::VTYPE_EMPTY_ARRAY:
    case nsIDataType::VTYPE_EMPTY:
    default:
      NS_ERROR("bad type in array!");
      break;
  }

  // Free the array memory.
  free((char*)u.array.mArrayValue);

#undef CASE__FREE_ARRAY_PTR
#undef CASE__FREE_ARRAY_IFACE
}

static nsresult
CloneArray(uint16_t aInType, const nsIID* aInIID,
           uint32_t aInCount, void* aInValue,
           uint16_t* aOutType, nsIID* aOutIID,
           uint32_t* aOutCount, void** aOutValue)
{
  NS_ASSERTION(aInCount, "bad param");
  NS_ASSERTION(aInValue, "bad param");
  NS_ASSERTION(aOutType, "bad param");
  NS_ASSERTION(aOutCount, "bad param");
  NS_ASSERTION(aOutValue, "bad param");

  uint32_t i;

  // First we figure out the size of the elements for the new u.array.

  size_t elementSize;
  size_t allocSize;

  switch (aInType) {
    case nsIDataType::VTYPE_INT8:
      elementSize = sizeof(int8_t);
      break;
    case nsIDataType::VTYPE_INT16:
      elementSize = sizeof(int16_t);
      break;
    case nsIDataType::VTYPE_INT32:
      elementSize = sizeof(int32_t);
      break;
    case nsIDataType::VTYPE_INT64:
      elementSize = sizeof(int64_t);
      break;
    case nsIDataType::VTYPE_UINT8:
      elementSize = sizeof(uint8_t);
      break;
    case nsIDataType::VTYPE_UINT16:
      elementSize = sizeof(uint16_t);
      break;
    case nsIDataType::VTYPE_UINT32:
      elementSize = sizeof(uint32_t);
      break;
    case nsIDataType::VTYPE_UINT64:
      elementSize = sizeof(uint64_t);
      break;
    case nsIDataType::VTYPE_FLOAT:
      elementSize = sizeof(float);
      break;
    case nsIDataType::VTYPE_DOUBLE:
      elementSize = sizeof(double);
      break;
    case nsIDataType::VTYPE_BOOL:
      elementSize = sizeof(bool);
      break;
    case nsIDataType::VTYPE_CHAR:
      elementSize = sizeof(char);
      break;
    case nsIDataType::VTYPE_WCHAR:
      elementSize = sizeof(char16_t);
      break;

    // XXX We ASSUME that "array of nsID" means "array of pointers to nsID".
    case nsIDataType::VTYPE_ID:
    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
      elementSize = sizeof(void*);
      break;

    // The rest are illegal.
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_UTF8STRING:
    case nsIDataType::VTYPE_CSTRING:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
    case nsIDataType::VTYPE_VOID:
    case nsIDataType::VTYPE_ARRAY:
    case nsIDataType::VTYPE_EMPTY_ARRAY:
    case nsIDataType::VTYPE_EMPTY:
    default:
      NS_ERROR("bad type in array!");
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }


  // Alloc the u.array.

  allocSize = aInCount * elementSize;
  *aOutValue = moz_xmalloc(allocSize);
  if (!*aOutValue) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  // Clone the elements.

  switch (aInType) {
    case nsIDataType::VTYPE_INT8:
    case nsIDataType::VTYPE_INT16:
    case nsIDataType::VTYPE_INT32:
    case nsIDataType::VTYPE_INT64:
    case nsIDataType::VTYPE_UINT8:
    case nsIDataType::VTYPE_UINT16:
    case nsIDataType::VTYPE_UINT32:
    case nsIDataType::VTYPE_UINT64:
    case nsIDataType::VTYPE_FLOAT:
    case nsIDataType::VTYPE_DOUBLE:
    case nsIDataType::VTYPE_BOOL:
    case nsIDataType::VTYPE_CHAR:
    case nsIDataType::VTYPE_WCHAR:
      memcpy(*aOutValue, aInValue, allocSize);
      break;

    case nsIDataType::VTYPE_INTERFACE_IS:
      if (aOutIID) {
        *aOutIID = *aInIID;
      }
      MOZ_FALLTHROUGH;

    case nsIDataType::VTYPE_INTERFACE: {
      memcpy(*aOutValue, aInValue, allocSize);

      nsISupports** p = (nsISupports**)*aOutValue;
      for (i = aInCount; i > 0; ++p, --i)
        if (*p) {
          (*p)->AddRef();
        }
      break;
    }

    // XXX We ASSUME that "array of nsID" means "array of pointers to nsID".
    case nsIDataType::VTYPE_ID: {
      nsID** inp  = (nsID**)aInValue;
      nsID** outp = (nsID**)*aOutValue;
      for (i = aInCount; i > 0; --i) {
        nsID* idp = *(inp++);
        if (idp) {
          *(outp++) = idp->Clone();
        } else {
          *(outp++) = nullptr;
        }
      }
      break;
    }

    case nsIDataType::VTYPE_CHAR_STR: {
      char** inp  = (char**)aInValue;
      char** outp = (char**)*aOutValue;
      for (i = aInCount; i > 0; i--) {
        char* str = *(inp++);
        if (str) {
          *(outp++) = moz_xstrdup(str);
        } else {
          *(outp++) = nullptr;
        }
      }
      break;
    }

    case nsIDataType::VTYPE_WCHAR_STR: {
      char16_t** inp  = (char16_t**)aInValue;
      char16_t** outp = (char16_t**)*aOutValue;
      for (i = aInCount; i > 0; i--) {
        char16_t* str = *(inp++);
        if (str) {
          *(outp++) = NS_strdup(str);
        } else {
          *(outp++) = nullptr;
        }
      }
      break;
    }

    // The rest are illegal.
    case nsIDataType::VTYPE_VOID:
    case nsIDataType::VTYPE_ARRAY:
    case nsIDataType::VTYPE_EMPTY_ARRAY:
    case nsIDataType::VTYPE_EMPTY:
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_UTF8STRING:
    case nsIDataType::VTYPE_CSTRING:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
    default:
      NS_ERROR("bad type in array!");
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }

  *aOutType = aInType;
  *aOutCount = aInCount;
  return NS_OK;
}

/***************************************************************************/

#define TRIVIAL_DATA_CONVERTER(type_, member_, retval_)                       \
    if (mType == nsIDataType::type_) {                                        \
        *retval_ = u.member_;                                                 \
        return NS_OK;                                                         \
    }

#define NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_)                 \
nsresult                                                                      \
nsDiscriminatedUnion::ConvertTo##name_ (Ctype_* aResult) const                \
{                                                                             \
    TRIVIAL_DATA_CONVERTER(type_, m##name_##Value, aResult)                   \
    nsDiscriminatedUnion tempData;                                            \
    nsresult rv = ToManageableNumber(&tempData);                              \
    /*                                                                     */ \
    /* NOTE: rv may indicate a success code that we want to preserve       */ \
    /* For the final return. So all the return cases below should return   */ \
    /* this rv when indicating success.                                    */ \
    /*                                                                     */ \
    if (NS_FAILED(rv))                                                        \
        return rv;                                                            \
    switch(tempData.mType)                                                    \
    {

#define CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(Ctype_)                      \
    case nsIDataType::VTYPE_INT32:                                            \
        *aResult = ( Ctype_ ) tempData.u.mInt32Value;                         \
        return rv;

#define CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_)            \
    case nsIDataType::VTYPE_INT32:                                            \
    {                                                                         \
        int32_t value = tempData.u.mInt32Value;                               \
        if (value < min_ || value > max_)                                     \
            return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;                         \
        *aResult = ( Ctype_ ) value;                                          \
        return rv;                                                            \
    }

#define CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(Ctype_)                     \
    case nsIDataType::VTYPE_UINT32:                                           \
        *aResult = ( Ctype_ ) tempData.u.mUint32Value;                        \
        return rv;

#define CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_)                     \
    case nsIDataType::VTYPE_UINT32:                                           \
    {                                                                         \
        uint32_t value = tempData.u.mUint32Value;                             \
        if (value > max_)                                                     \
            return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;                         \
        *aResult = ( Ctype_ ) value;                                          \
        return rv;                                                            \
    }

#define CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(Ctype_)                     \
    case nsIDataType::VTYPE_DOUBLE:                                           \
        *aResult = ( Ctype_ ) tempData.u.mDoubleValue;                        \
        return rv;

#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX(Ctype_, min_, max_)           \
    case nsIDataType::VTYPE_DOUBLE:                                           \
    {                                                                         \
        double value = tempData.u.mDoubleValue;                               \
        if (value < min_ || value > max_)                                     \
            return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;                         \
        *aResult = ( Ctype_ ) value;                                          \
        return rv;                                                            \
    }

#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_)       \
    case nsIDataType::VTYPE_DOUBLE:                                           \
    {                                                                         \
        double value = tempData.u.mDoubleValue;                               \
        if (value < min_ || value > max_)                                     \
            return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;                         \
        *aResult = ( Ctype_ ) value;                                          \
        return (0.0 == fmod(value,1.0)) ?                                     \
            rv : NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;                       \
    }

#define CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_)                  \
    CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_)                \
    CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_)                         \
    CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_)

#define NUMERIC_CONVERSION_METHOD_END                                         \
    default:                                                                  \
        NS_ERROR("bad type returned from ToManageableNumber");                \
        return NS_ERROR_CANNOT_CONVERT_DATA;                                  \
    }                                                                         \
}

#define NUMERIC_CONVERSION_METHOD_NORMAL(type_, Ctype_, name_, min_, max_)    \
    NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_)                     \
        CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_)                  \
    NUMERIC_CONVERSION_METHOD_END

/***************************************************************************/
// These expand into full public methods...

NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT8, uint8_t, Int8, (-127 - 1), 127)
NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT16, int16_t, Int16, (-32767 - 1), 32767)

NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_INT32, int32_t, Int32)
  CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(int32_t)
  CASE__NUMERIC_CONVERSION_UINT32_MAX(int32_t, 2147483647)
  CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(int32_t, (-2147483647 - 1), 2147483647)
NUMERIC_CONVERSION_METHOD_END

NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT8, uint8_t, Uint8, 0, 255)
NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT16, uint16_t, Uint16, 0, 65535)

NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_UINT32, uint32_t, Uint32)
  CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(uint32_t, 0, 2147483647)
  CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(uint32_t)
  CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(uint32_t, 0, 4294967295U)
NUMERIC_CONVERSION_METHOD_END

// XXX toFloat convertions need to be fixed!
NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_FLOAT, float, Float)
  CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(float)
  CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(float)
  CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(float)
NUMERIC_CONVERSION_METHOD_END

NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_DOUBLE, double, Double)
  CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(double)
  CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(double)
  CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(double)
NUMERIC_CONVERSION_METHOD_END

// XXX toChar convertions need to be fixed!
NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_CHAR, char, Char)
  CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char)
  CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char)
  CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char)
NUMERIC_CONVERSION_METHOD_END

// XXX toWChar convertions need to be fixed!
NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_WCHAR, char16_t, WChar)
  CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char16_t)
  CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char16_t)
  CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char16_t)
NUMERIC_CONVERSION_METHOD_END

#undef NUMERIC_CONVERSION_METHOD_BEGIN
#undef CASE__NUMERIC_CONVERSION_INT32_JUST_CAST
#undef CASE__NUMERIC_CONVERSION_INT32_MIN_MAX
#undef CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST
#undef CASE__NUMERIC_CONVERSION_UINT32_MIN_MAX
#undef CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST
#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX
#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT
#undef CASES__NUMERIC_CONVERSION_NORMAL
#undef NUMERIC_CONVERSION_METHOD_END
#undef NUMERIC_CONVERSION_METHOD_NORMAL

/***************************************************************************/

// Just leverage a numeric converter for bool (but restrict the values).
// XXX Is this really what we want to do?

nsresult
nsDiscriminatedUnion::ConvertToBool(bool* aResult) const
{
  TRIVIAL_DATA_CONVERTER(VTYPE_BOOL, mBoolValue, aResult)

  double val;
  nsresult rv = ConvertToDouble(&val);
  if (NS_FAILED(rv)) {
    return rv;
  }
  *aResult = 0.0 != val;
  return rv;
}

/***************************************************************************/

nsresult
nsDiscriminatedUnion::ConvertToInt64(int64_t* aResult) const
{
  TRIVIAL_DATA_CONVERTER(VTYPE_INT64, mInt64Value, aResult)
  TRIVIAL_DATA_CONVERTER(VTYPE_UINT64, mUint64Value, aResult)

  nsDiscriminatedUnion tempData;
  nsresult rv = ToManageableNumber(&tempData);
  if (NS_FAILED(rv)) {
    return rv;
  }
  switch (tempData.mType) {
    case nsIDataType::VTYPE_INT32:
      *aResult = tempData.u.mInt32Value;
      return rv;
    case nsIDataType::VTYPE_UINT32:
      *aResult = tempData.u.mUint32Value;
      return rv;
    case nsIDataType::VTYPE_DOUBLE:
      // XXX should check for data loss here!
      *aResult = tempData.u.mDoubleValue;
      return rv;
    default:
      NS_ERROR("bad type returned from ToManageableNumber");
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }
}

nsresult
nsDiscriminatedUnion::ConvertToUint64(uint64_t* aResult) const
{
  return ConvertToInt64((int64_t*)aResult);
}

/***************************************************************************/

bool
nsDiscriminatedUnion::String2ID(nsID* aPid) const
{
  nsAutoString tempString;
  nsAString* pString;

  switch (mType) {
    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      return aPid->Parse(u.str.mStringValue);
    case nsIDataType::VTYPE_CSTRING:
      return aPid->Parse(PromiseFlatCString(*u.mCStringValue).get());
    case nsIDataType::VTYPE_UTF8STRING:
      return aPid->Parse(PromiseFlatUTF8String(*u.mUTF8StringValue).get());
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      pString = u.mAStringValue;
      break;
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      tempString.Assign(u.wstr.mWStringValue);
      pString = &tempString;
      break;
    default:
      NS_ERROR("bad type in call to String2ID");
      return false;
  }

  char* pChars = ToNewCString(*pString);
  if (!pChars) {
    return false;
  }
  bool result = aPid->Parse(pChars);
  free(pChars);
  return result;
}

nsresult
nsDiscriminatedUnion::ConvertToID(nsID* aResult) const
{
  nsID id;

  switch (mType) {
    case nsIDataType::VTYPE_ID:
      *aResult = u.mIDValue;
      return NS_OK;
    case nsIDataType::VTYPE_INTERFACE:
      *aResult = NS_GET_IID(nsISupports);
      return NS_OK;
    case nsIDataType::VTYPE_INTERFACE_IS:
      *aResult = u.iface.mInterfaceID;
      return NS_OK;
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_UTF8STRING:
    case nsIDataType::VTYPE_CSTRING:
    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      if (!String2ID(&id)) {
        return NS_ERROR_CANNOT_CONVERT_DATA;
      }
      *aResult = id;
      return NS_OK;
    default:
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }
}

/***************************************************************************/

nsresult
nsDiscriminatedUnion::ToString(nsACString& aOutString) const
{
  mozilla::SmprintfPointer pptr;

  switch (mType) {
    // all the stuff we don't handle...
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_UTF8STRING:
    case nsIDataType::VTYPE_CSTRING:
    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
    case nsIDataType::VTYPE_WCHAR:
      NS_ERROR("ToString being called for a string type - screwy logic!");
      MOZ_FALLTHROUGH;

    // XXX We might want stringified versions of these... ???

    case nsIDataType::VTYPE_VOID:
    case nsIDataType::VTYPE_EMPTY:
      aOutString.SetIsVoid(true);
      return NS_OK;

    case nsIDataType::VTYPE_EMPTY_ARRAY:
    case nsIDataType::VTYPE_ARRAY:
    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
    default:
      return NS_ERROR_CANNOT_CONVERT_DATA;

    // nsID has its own text formatter.

    case nsIDataType::VTYPE_ID: {
      char* ptr = u.mIDValue.ToString();
      if (!ptr) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      aOutString.Assign(ptr);
      free(ptr);
      return NS_OK;
    }

    // Can't use Smprintf for floats, since it's locale-dependent
#define CASE__APPENDFLOAT_NUMBER(type_, member_)                        \
    case nsIDataType::type_ :                                           \
    {                                                                   \
        nsAutoCString str;                                              \
        str.AppendFloat(u.member_);                                     \
        aOutString.Assign(str);                                         \
        return NS_OK;                                                   \
    }

    CASE__APPENDFLOAT_NUMBER(VTYPE_FLOAT,  mFloatValue)
    CASE__APPENDFLOAT_NUMBER(VTYPE_DOUBLE, mDoubleValue)

#undef CASE__APPENDFLOAT_NUMBER

    // the rest can be Smprintf'd and use common code.

#define CASE__SMPRINTF_NUMBER(type_, format_, cast_, member_)          \
    case nsIDataType::type_:                                           \
        static_assert(sizeof(cast_) >= sizeof(u.member_),              \
                      "size of type should be at least as big as member"); \
        pptr = mozilla::Smprintf( format_ , (cast_) u.member_);        \
        break;

    CASE__SMPRINTF_NUMBER(VTYPE_INT8,   "%d",   int,      mInt8Value)
    CASE__SMPRINTF_NUMBER(VTYPE_INT16,  "%d",   int,      mInt16Value)
    CASE__SMPRINTF_NUMBER(VTYPE_INT32,  "%d",   int,      mInt32Value)
    CASE__SMPRINTF_NUMBER(VTYPE_INT64,  "%" PRId64, int64_t,  mInt64Value)

    CASE__SMPRINTF_NUMBER(VTYPE_UINT8,  "%u",   unsigned, mUint8Value)
    CASE__SMPRINTF_NUMBER(VTYPE_UINT16, "%u",   unsigned, mUint16Value)
    CASE__SMPRINTF_NUMBER(VTYPE_UINT32, "%u",   unsigned, mUint32Value)
    CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%" PRIu64, int64_t,  mUint64Value)

    // XXX Would we rather print "true" / "false" ?
    CASE__SMPRINTF_NUMBER(VTYPE_BOOL,   "%d",   int,      mBoolValue)

    CASE__SMPRINTF_NUMBER(VTYPE_CHAR,   "%c",   char,     mCharValue)

#undef CASE__SMPRINTF_NUMBER
  }

  if (!pptr) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  aOutString.Assign(pptr.get());
  return NS_OK;
}

nsresult
nsDiscriminatedUnion::ConvertToAString(nsAString& aResult) const
{
  switch (mType) {
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      aResult.Assign(*u.mAStringValue);
      return NS_OK;
    case nsIDataType::VTYPE_CSTRING:
      CopyASCIItoUTF16(*u.mCStringValue, aResult);
      return NS_OK;
    case nsIDataType::VTYPE_UTF8STRING:
      CopyUTF8toUTF16(*u.mUTF8StringValue, aResult);
      return NS_OK;
    case nsIDataType::VTYPE_CHAR_STR:
      CopyASCIItoUTF16(u.str.mStringValue, aResult);
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR_STR:
      aResult.Assign(u.wstr.mWStringValue);
      return NS_OK;
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      CopyASCIItoUTF16(nsDependentCString(u.str.mStringValue,
                                          u.str.mStringLength),
                       aResult);
      return NS_OK;
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      aResult.Assign(u.wstr.mWStringValue, u.wstr.mWStringLength);
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR:
      aResult.Assign(u.mWCharValue);
      return NS_OK;
    default: {
      nsAutoCString tempCString;
      nsresult rv = ToString(tempCString);
      if (NS_FAILED(rv)) {
        return rv;
      }
      CopyASCIItoUTF16(tempCString, aResult);
      return NS_OK;
    }
  }
}

nsresult
nsDiscriminatedUnion::ConvertToACString(nsACString& aResult) const
{
  switch (mType) {
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      LossyCopyUTF16toASCII(*u.mAStringValue, aResult);
      return NS_OK;
    case nsIDataType::VTYPE_CSTRING:
      aResult.Assign(*u.mCStringValue);
      return NS_OK;
    case nsIDataType::VTYPE_UTF8STRING:
      // XXX This is an extra copy that should be avoided
      // once Jag lands support for UTF8String and associated
      // conversion methods.
      LossyCopyUTF16toASCII(NS_ConvertUTF8toUTF16(*u.mUTF8StringValue),
                            aResult);
      return NS_OK;
    case nsIDataType::VTYPE_CHAR_STR:
      aResult.Assign(*u.str.mStringValue);
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR_STR:
      LossyCopyUTF16toASCII(nsDependentString(u.wstr.mWStringValue),
                            aResult);
      return NS_OK;
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      aResult.Assign(u.str.mStringValue, u.str.mStringLength);
      return NS_OK;
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      LossyCopyUTF16toASCII(nsDependentString(u.wstr.mWStringValue,
                                              u.wstr.mWStringLength),
                            aResult);
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR: {
      const char16_t* str = &u.mWCharValue;
      LossyCopyUTF16toASCII(Substring(str, 1), aResult);
      return NS_OK;
    }
    default:
      return ToString(aResult);
  }
}

nsresult
nsDiscriminatedUnion::ConvertToAUTF8String(nsAUTF8String& aResult) const
{
  switch (mType) {
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      CopyUTF16toUTF8(*u.mAStringValue, aResult);
      return NS_OK;
    case nsIDataType::VTYPE_CSTRING:
      // XXX Extra copy, can be removed if we're sure CSTRING can
      //     only contain ASCII.
      CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(*u.mCStringValue),
                      aResult);
      return NS_OK;
    case nsIDataType::VTYPE_UTF8STRING:
      aResult.Assign(*u.mUTF8StringValue);
      return NS_OK;
    case nsIDataType::VTYPE_CHAR_STR:
      // XXX Extra copy, can be removed if we're sure CHAR_STR can
      //     only contain ASCII.
      CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(u.str.mStringValue),
                      aResult);
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR_STR:
      CopyUTF16toUTF8(u.wstr.mWStringValue, aResult);
      return NS_OK;
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      // XXX Extra copy, can be removed if we're sure CHAR_STR can
      //     only contain ASCII.
      CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(
        nsDependentCString(u.str.mStringValue,
                           u.str.mStringLength)), aResult);
      return NS_OK;
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      CopyUTF16toUTF8(nsDependentString(u.wstr.mWStringValue,
                                        u.wstr.mWStringLength),
                      aResult);
      return NS_OK;
    case nsIDataType::VTYPE_WCHAR: {
      const char16_t* str = &u.mWCharValue;
      CopyUTF16toUTF8(Substring(str, 1), aResult);
      return NS_OK;
    }
    default: {
      nsAutoCString tempCString;
      nsresult rv = ToString(tempCString);
      if (NS_FAILED(rv)) {
        return rv;
      }
      // XXX Extra copy, can be removed if we're sure tempCString can
      //     only contain ASCII.
      CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(tempCString), aResult);
      return NS_OK;
    }
  }
}

nsresult
nsDiscriminatedUnion::ConvertToString(char** aResult) const
{
  uint32_t ignored;
  return ConvertToStringWithSize(&ignored, aResult);
}

nsresult
nsDiscriminatedUnion::ConvertToWString(char16_t** aResult) const
{
  uint32_t ignored;
  return ConvertToWStringWithSize(&ignored, aResult);
}

nsresult
nsDiscriminatedUnion::ConvertToStringWithSize(uint32_t* aSize, char** aStr) const
{
  nsAutoString  tempString;
  nsAutoCString tempCString;
  nsresult rv;

  switch (mType) {
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      *aSize = u.mAStringValue->Length();
      *aStr = ToNewCString(*u.mAStringValue);
      break;
    case nsIDataType::VTYPE_CSTRING:
      *aSize = u.mCStringValue->Length();
      *aStr = ToNewCString(*u.mCStringValue);
      break;
    case nsIDataType::VTYPE_UTF8STRING: {
      // XXX This is doing 1 extra copy.  Need to fix this
      // when Jag lands UTF8String
      // we want:
      // *aSize = *mUTF8StringValue->Length();
      // *aStr = ToNewCString(*mUTF8StringValue);
      // But this will have to do for now.
      const NS_ConvertUTF8toUTF16 tempString16(*u.mUTF8StringValue);
      *aSize = tempString16.Length();
      *aStr = ToNewCString(tempString16);
      break;
    }
    case nsIDataType::VTYPE_CHAR_STR: {
      nsDependentCString cString(u.str.mStringValue);
      *aSize = cString.Length();
      *aStr = ToNewCString(cString);
      break;
    }
    case nsIDataType::VTYPE_WCHAR_STR: {
      nsDependentString string(u.wstr.mWStringValue);
      *aSize = string.Length();
      *aStr = ToNewCString(string);
      break;
    }
    case nsIDataType::VTYPE_STRING_SIZE_IS: {
      nsDependentCString cString(u.str.mStringValue,
                                 u.str.mStringLength);
      *aSize = cString.Length();
      *aStr = ToNewCString(cString);
      break;
    }
    case nsIDataType::VTYPE_WSTRING_SIZE_IS: {
      nsDependentString string(u.wstr.mWStringValue,
                               u.wstr.mWStringLength);
      *aSize = string.Length();
      *aStr = ToNewCString(string);
      break;
    }
    case nsIDataType::VTYPE_WCHAR:
      tempString.Assign(u.mWCharValue);
      *aSize = tempString.Length();
      *aStr = ToNewCString(tempString);
      break;
    default:
      rv = ToString(tempCString);
      if (NS_FAILED(rv)) {
        return rv;
      }
      *aSize = tempCString.Length();
      *aStr = ToNewCString(tempCString);
      break;
  }

  return *aStr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsresult
nsDiscriminatedUnion::ConvertToWStringWithSize(uint32_t* aSize, char16_t** aStr) const
{
  nsAutoString  tempString;
  nsAutoCString tempCString;
  nsresult rv;

  switch (mType) {
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      *aSize = u.mAStringValue->Length();
      *aStr = ToNewUnicode(*u.mAStringValue);
      break;
    case nsIDataType::VTYPE_CSTRING:
      *aSize = u.mCStringValue->Length();
      *aStr = ToNewUnicode(*u.mCStringValue);
      break;
    case nsIDataType::VTYPE_UTF8STRING: {
      *aStr = UTF8ToNewUnicode(*u.mUTF8StringValue, aSize);
      break;
    }
    case nsIDataType::VTYPE_CHAR_STR: {
      nsDependentCString cString(u.str.mStringValue);
      *aSize = cString.Length();
      *aStr = ToNewUnicode(cString);
      break;
    }
    case nsIDataType::VTYPE_WCHAR_STR: {
      nsDependentString string(u.wstr.mWStringValue);
      *aSize = string.Length();
      *aStr = ToNewUnicode(string);
      break;
    }
    case nsIDataType::VTYPE_STRING_SIZE_IS: {
      nsDependentCString cString(u.str.mStringValue,
                                 u.str.mStringLength);
      *aSize = cString.Length();
      *aStr = ToNewUnicode(cString);
      break;
    }
    case nsIDataType::VTYPE_WSTRING_SIZE_IS: {
      nsDependentString string(u.wstr.mWStringValue,
                               u.wstr.mWStringLength);
      *aSize = string.Length();
      *aStr = ToNewUnicode(string);
      break;
    }
    case nsIDataType::VTYPE_WCHAR:
      tempString.Assign(u.mWCharValue);
      *aSize = tempString.Length();
      *aStr = ToNewUnicode(tempString);
      break;
    default:
      rv = ToString(tempCString);
      if (NS_FAILED(rv)) {
        return rv;
      }
      *aSize = tempCString.Length();
      *aStr = ToNewUnicode(tempCString);
      break;
  }

  return *aStr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}

nsresult
nsDiscriminatedUnion::ConvertToISupports(nsISupports** aResult) const
{
  switch (mType) {
    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
      if (u.iface.mInterfaceValue) {
        return u.iface.mInterfaceValue->
          QueryInterface(NS_GET_IID(nsISupports), (void**)aResult);
      } else {
        *aResult = nullptr;
        return NS_OK;
      }
    default:
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }
}

nsresult
nsDiscriminatedUnion::ConvertToInterface(nsIID** aIID,
                                         void** aInterface) const
{
  const nsIID* piid;

  switch (mType) {
    case nsIDataType::VTYPE_INTERFACE:
      piid = &NS_GET_IID(nsISupports);
      break;
    case nsIDataType::VTYPE_INTERFACE_IS:
      piid = &u.iface.mInterfaceID;
      break;
    default:
      return NS_ERROR_CANNOT_CONVERT_DATA;
  }

  *aIID = piid->Clone();

  if (u.iface.mInterfaceValue) {
    return u.iface.mInterfaceValue->QueryInterface(*piid, aInterface);
  }

  *aInterface = nullptr;
  return NS_OK;
}

nsresult
nsDiscriminatedUnion::ConvertToArray(uint16_t* aType, nsIID* aIID,
                                     uint32_t* aCount, void** aPtr) const
{
  // XXX perhaps we'd like to add support for converting each of the various
  // types into an array containing one element of that type. We can leverage
  // CloneArray to do this if we want to support this.

  if (mType == nsIDataType::VTYPE_ARRAY) {
    return CloneArray(u.array.mArrayType, &u.array.mArrayInterfaceID,
                      u.array.mArrayCount, u.array.mArrayValue,
                      aType, aIID, aCount, aPtr);
  }
  return NS_ERROR_CANNOT_CONVERT_DATA;
}

/***************************************************************************/
// static setter functions...

#define DATA_SETTER_PROLOGUE                                                  \
    Cleanup()

#define DATA_SETTER_EPILOGUE(type_)                                           \
    mType = nsIDataType::type_;

#define DATA_SETTER(type_, member_, value_)                                   \
    DATA_SETTER_PROLOGUE;                                                     \
    u.member_ = value_;                                                       \
    DATA_SETTER_EPILOGUE(type_)

#define DATA_SETTER_WITH_CAST(type_, member_, cast_, value_)                  \
    DATA_SETTER_PROLOGUE;                                                     \
    u.member_ = cast_ value_;                                                 \
    DATA_SETTER_EPILOGUE(type_)


/********************************************/

#define CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_)                          \
    {                                                                         \

#define CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_)                  \
        rv = aValue->GetAs##name_ (&(u.member_ ));

#define CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_)      \
        rv = aValue->GetAs##name_ ( cast_ &(u.member_ ));

#define CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_)                          \
        if (NS_SUCCEEDED(rv)) {                                               \
          mType  = nsIDataType::type_ ;                                       \
        }                                                                     \
        break;                                                                \
    }

#define CASE__SET_FROM_VARIANT_TYPE(type_, member_, name_)                    \
    case nsIDataType::type_:                                                  \
        CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_)                          \
        CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_)                  \
        CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_)

#define CASE__SET_FROM_VARIANT_VTYPE_CAST(type_, cast_, member_, name_)       \
    case nsIDataType::type_ :                                                 \
        CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_)                          \
        CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_)      \
        CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_)


nsresult
nsDiscriminatedUnion::SetFromVariant(nsIVariant* aValue)
{
  uint16_t type;
  nsresult rv;

  Cleanup();

  rv = aValue->GetDataType(&type);
  if (NS_FAILED(rv)) {
    return rv;
  }

  switch (type) {
    CASE__SET_FROM_VARIANT_VTYPE_CAST(VTYPE_INT8, (uint8_t*), mInt8Value,
                                      Int8)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT16,  mInt16Value,  Int16)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT32,  mInt32Value,  Int32)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT8,  mUint8Value,  Uint8)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT16, mUint16Value, Uint16)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT32, mUint32Value, Uint32)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_FLOAT,  mFloatValue,  Float)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_DOUBLE, mDoubleValue, Double)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_BOOL ,  mBoolValue,   Bool)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_CHAR,   mCharValue,   Char)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_WCHAR,  mWCharValue,  WChar)
    CASE__SET_FROM_VARIANT_TYPE(VTYPE_ID,     mIDValue,     ID)

    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING);
      u.mAStringValue = new nsString();
      if (!u.mAStringValue) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      rv = aValue->GetAsAString(*u.mAStringValue);
      if (NS_FAILED(rv)) {
        delete u.mAStringValue;
      }
      CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ASTRING)

    case nsIDataType::VTYPE_CSTRING:
      CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_CSTRING);
      u.mCStringValue = new nsCString();
      if (!u.mCStringValue) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      rv = aValue->GetAsACString(*u.mCStringValue);
      if (NS_FAILED(rv)) {
        delete u.mCStringValue;
      }
      CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_CSTRING)

    case nsIDataType::VTYPE_UTF8STRING:
      CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_UTF8STRING);
      u.mUTF8StringValue = new nsUTF8String();
      if (!u.mUTF8StringValue) {
        return NS_ERROR_OUT_OF_MEMORY;
      }
      rv = aValue->GetAsAUTF8String(*u.mUTF8StringValue);
      if (NS_FAILED(rv)) {
        delete u.mUTF8StringValue;
      }
      CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_UTF8STRING)

    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_STRING_SIZE_IS);
      rv = aValue->GetAsStringWithSize(&u.str.mStringLength,
                                       &u.str.mStringValue);
      CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_STRING_SIZE_IS)

    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
      CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_INTERFACE_IS);
      // XXX This iid handling is ugly!
      nsIID* iid;
      rv = aValue->GetAsInterface(&iid, (void**)&u.iface.mInterfaceValue);
      if (NS_SUCCEEDED(rv)) {
        u.iface.mInterfaceID = *iid;
        free((char*)iid);
      }
      CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_INTERFACE_IS)

    case nsIDataType::VTYPE_ARRAY:
      CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ARRAY);
      rv = aValue->GetAsArray(&u.array.mArrayType,
                              &u.array.mArrayInterfaceID,
                              &u.array.mArrayCount,
                              &u.array.mArrayValue);
      CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ARRAY)

    case nsIDataType::VTYPE_VOID:
      SetToVoid();
      rv = NS_OK;
      break;
    case nsIDataType::VTYPE_EMPTY_ARRAY:
      SetToEmptyArray();
      rv = NS_OK;
      break;
    case nsIDataType::VTYPE_EMPTY:
      SetToEmpty();
      rv = NS_OK;
      break;
    default:
      NS_ERROR("bad type in variant!");
      rv = NS_ERROR_FAILURE;
      break;
  }
  return rv;
}

void
nsDiscriminatedUnion::SetFromInt8(uint8_t aValue)
{
  DATA_SETTER_WITH_CAST(VTYPE_INT8, mInt8Value, (uint8_t), aValue);
}
void
nsDiscriminatedUnion::SetFromInt16(int16_t aValue)
{
  DATA_SETTER(VTYPE_INT16, mInt16Value, aValue);
}
void
nsDiscriminatedUnion::SetFromInt32(int32_t aValue)
{
  DATA_SETTER(VTYPE_INT32, mInt32Value, aValue);
}
void
nsDiscriminatedUnion::SetFromInt64(int64_t aValue)
{
  DATA_SETTER(VTYPE_INT64, mInt64Value, aValue);
}
void
nsDiscriminatedUnion::SetFromUint8(uint8_t aValue)
{
  DATA_SETTER(VTYPE_UINT8, mUint8Value, aValue);
}
void
nsDiscriminatedUnion::SetFromUint16(uint16_t aValue)
{
  DATA_SETTER(VTYPE_UINT16, mUint16Value, aValue);
}
void
nsDiscriminatedUnion::SetFromUint32(uint32_t aValue)
{
  DATA_SETTER(VTYPE_UINT32, mUint32Value, aValue);
}
void
nsDiscriminatedUnion::SetFromUint64(uint64_t aValue)
{
  DATA_SETTER(VTYPE_UINT64, mUint64Value, aValue);
}
void
nsDiscriminatedUnion::SetFromFloat(float aValue)
{
  DATA_SETTER(VTYPE_FLOAT, mFloatValue, aValue);
}
void
nsDiscriminatedUnion::SetFromDouble(double aValue)
{
  DATA_SETTER(VTYPE_DOUBLE, mDoubleValue, aValue);
}
void
nsDiscriminatedUnion::SetFromBool(bool aValue)
{
  DATA_SETTER(VTYPE_BOOL, mBoolValue, aValue);
}
void
nsDiscriminatedUnion::SetFromChar(char aValue)
{
  DATA_SETTER(VTYPE_CHAR, mCharValue, aValue);
}
void
nsDiscriminatedUnion::SetFromWChar(char16_t aValue)
{
  DATA_SETTER(VTYPE_WCHAR, mWCharValue, aValue);
}
void
nsDiscriminatedUnion::SetFromID(const nsID& aValue)
{
  DATA_SETTER(VTYPE_ID, mIDValue, aValue);
}
void
nsDiscriminatedUnion::SetFromAString(const nsAString& aValue)
{
  DATA_SETTER_PROLOGUE;
  u.mAStringValue = new nsString(aValue);
  DATA_SETTER_EPILOGUE(VTYPE_ASTRING);
}

void
nsDiscriminatedUnion::SetFromDOMString(const nsAString& aValue)
{
  DATA_SETTER_PROLOGUE;
  u.mAStringValue = new nsString(aValue);
  DATA_SETTER_EPILOGUE(VTYPE_DOMSTRING);
}

void
nsDiscriminatedUnion::SetFromACString(const nsACString& aValue)
{
  DATA_SETTER_PROLOGUE;
  u.mCStringValue = new nsCString(aValue);
  DATA_SETTER_EPILOGUE(VTYPE_CSTRING);
}

void
nsDiscriminatedUnion::SetFromAUTF8String(const nsAUTF8String& aValue)
{
  DATA_SETTER_PROLOGUE;
  u.mUTF8StringValue = new nsUTF8String(aValue);
  DATA_SETTER_EPILOGUE(VTYPE_UTF8STRING);
}

nsresult
nsDiscriminatedUnion::SetFromString(const char* aValue)
{
  DATA_SETTER_PROLOGUE;
  if (!aValue) {
    return NS_ERROR_NULL_POINTER;
  }
  return SetFromStringWithSize(strlen(aValue), aValue);
}
nsresult
nsDiscriminatedUnion::SetFromWString(const char16_t* aValue)
{
  DATA_SETTER_PROLOGUE;
  if (!aValue) {
    return NS_ERROR_NULL_POINTER;
  }
  return SetFromWStringWithSize(NS_strlen(aValue), aValue);
}
void
nsDiscriminatedUnion::SetFromISupports(nsISupports* aValue)
{
  return SetFromInterface(NS_GET_IID(nsISupports), aValue);
}
void
nsDiscriminatedUnion::SetFromInterface(const nsIID& aIID, nsISupports* aValue)
{
  DATA_SETTER_PROLOGUE;
  NS_IF_ADDREF(aValue);
  u.iface.mInterfaceValue = aValue;
  u.iface.mInterfaceID = aIID;
  DATA_SETTER_EPILOGUE(VTYPE_INTERFACE_IS);
}
nsresult
nsDiscriminatedUnion::SetFromArray(uint16_t aType, const nsIID* aIID,
                                   uint32_t aCount, void* aValue)
{
  DATA_SETTER_PROLOGUE;
  if (!aValue || !aCount) {
    return NS_ERROR_NULL_POINTER;
  }

  nsresult rv = CloneArray(aType, aIID, aCount, aValue,
                           &u.array.mArrayType,
                           &u.array.mArrayInterfaceID,
                           &u.array.mArrayCount,
                           &u.array.mArrayValue);
  if (NS_FAILED(rv)) {
    return rv;
  }
  DATA_SETTER_EPILOGUE(VTYPE_ARRAY);
  return NS_OK;
}
nsresult
nsDiscriminatedUnion::SetFromStringWithSize(uint32_t aSize,
                                            const char* aValue)
{
  DATA_SETTER_PROLOGUE;
  if (!aValue) {
    return NS_ERROR_NULL_POINTER;
  }
  if (!(u.str.mStringValue =
        (char*)nsMemory::Clone(aValue, (aSize + 1) * sizeof(char)))) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  u.str.mStringLength = aSize;
  DATA_SETTER_EPILOGUE(VTYPE_STRING_SIZE_IS);
  return NS_OK;
}
nsresult
nsDiscriminatedUnion::SetFromWStringWithSize(uint32_t aSize,
                                             const char16_t* aValue)
{
  DATA_SETTER_PROLOGUE;
  if (!aValue) {
    return NS_ERROR_NULL_POINTER;
  }
  if (!(u.wstr.mWStringValue =
        (char16_t*)nsMemory::Clone(aValue, (aSize + 1) * sizeof(char16_t)))) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  u.wstr.mWStringLength = aSize;
  DATA_SETTER_EPILOGUE(VTYPE_WSTRING_SIZE_IS);
  return NS_OK;
}
void
nsDiscriminatedUnion::AllocateWStringWithSize(uint32_t aSize)
{
  DATA_SETTER_PROLOGUE;
  u.wstr.mWStringValue = (char16_t*)moz_xmalloc((aSize + 1) * sizeof(char16_t));
  u.wstr.mWStringValue[aSize] = '\0';
  u.wstr.mWStringLength = aSize;
  DATA_SETTER_EPILOGUE(VTYPE_WSTRING_SIZE_IS);
}
void
nsDiscriminatedUnion::SetToVoid()
{
  DATA_SETTER_PROLOGUE;
  DATA_SETTER_EPILOGUE(VTYPE_VOID);
}
void
nsDiscriminatedUnion::SetToEmpty()
{
  DATA_SETTER_PROLOGUE;
  DATA_SETTER_EPILOGUE(VTYPE_EMPTY);
}
void
nsDiscriminatedUnion::SetToEmptyArray()
{
  DATA_SETTER_PROLOGUE;
  DATA_SETTER_EPILOGUE(VTYPE_EMPTY_ARRAY);
}

/***************************************************************************/

void
nsDiscriminatedUnion::Cleanup()
{
  switch (mType) {
    case nsIDataType::VTYPE_INT8:
    case nsIDataType::VTYPE_INT16:
    case nsIDataType::VTYPE_INT32:
    case nsIDataType::VTYPE_INT64:
    case nsIDataType::VTYPE_UINT8:
    case nsIDataType::VTYPE_UINT16:
    case nsIDataType::VTYPE_UINT32:
    case nsIDataType::VTYPE_UINT64:
    case nsIDataType::VTYPE_FLOAT:
    case nsIDataType::VTYPE_DOUBLE:
    case nsIDataType::VTYPE_BOOL:
    case nsIDataType::VTYPE_CHAR:
    case nsIDataType::VTYPE_WCHAR:
    case nsIDataType::VTYPE_VOID:
    case nsIDataType::VTYPE_ID:
      break;
    case nsIDataType::VTYPE_ASTRING:
    case nsIDataType::VTYPE_DOMSTRING:
      delete u.mAStringValue;
      break;
    case nsIDataType::VTYPE_CSTRING:
      delete u.mCStringValue;
      break;
    case nsIDataType::VTYPE_UTF8STRING:
      delete u.mUTF8StringValue;
      break;
    case nsIDataType::VTYPE_CHAR_STR:
    case nsIDataType::VTYPE_STRING_SIZE_IS:
      free((char*)u.str.mStringValue);
      break;
    case nsIDataType::VTYPE_WCHAR_STR:
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
      free((char*)u.wstr.mWStringValue);
      break;
    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
      NS_IF_RELEASE(u.iface.mInterfaceValue);
      break;
    case nsIDataType::VTYPE_ARRAY:
      FreeArray();
      break;
    case nsIDataType::VTYPE_EMPTY_ARRAY:
    case nsIDataType::VTYPE_EMPTY:
      break;
    default:
      NS_ERROR("bad type in variant!");
      break;
  }

  mType = nsIDataType::VTYPE_EMPTY;
}

void
nsDiscriminatedUnion::Traverse(nsCycleCollectionTraversalCallback& aCb) const
{
  switch (mType) {
    case nsIDataType::VTYPE_INTERFACE:
    case nsIDataType::VTYPE_INTERFACE_IS:
      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mData");
      aCb.NoteXPCOMChild(u.iface.mInterfaceValue);
      break;
    case nsIDataType::VTYPE_ARRAY:
      switch (u.array.mArrayType) {
        case nsIDataType::VTYPE_INTERFACE:
        case nsIDataType::VTYPE_INTERFACE_IS: {
          nsISupports** p = (nsISupports**)u.array.mArrayValue;
          for (uint32_t i = u.array.mArrayCount; i > 0; ++p, --i) {
            NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mData[i]");
            aCb.NoteXPCOMChild(*p);
          }
          break;
        }
        default:
          break;
      }
      break;
    default:
      break;
  }
}

/***************************************************************************/
/***************************************************************************/
// members...

nsVariantBase::nsVariantBase()
  : mWritable(true)
{
#ifdef DEBUG
  {
    // Assert that the nsIDataType consts match the values #defined in
    // xptinfo.h. Bad things happen somewhere if they don't.
    struct THE_TYPES
    {
      uint16_t a;
      uint16_t b;
    };
    static const THE_TYPES array[] = {
      {nsIDataType::VTYPE_INT8              , TD_INT8             },
      {nsIDataType::VTYPE_INT16             , TD_INT16            },
      {nsIDataType::VTYPE_INT32             , TD_INT32            },
      {nsIDataType::VTYPE_INT64             , TD_INT64            },
      {nsIDataType::VTYPE_UINT8             , TD_UINT8            },
      {nsIDataType::VTYPE_UINT16            , TD_UINT16           },
      {nsIDataType::VTYPE_UINT32            , TD_UINT32           },
      {nsIDataType::VTYPE_UINT64            , TD_UINT64           },
      {nsIDataType::VTYPE_FLOAT             , TD_FLOAT            },
      {nsIDataType::VTYPE_DOUBLE            , TD_DOUBLE           },
      {nsIDataType::VTYPE_BOOL              , TD_BOOL             },
      {nsIDataType::VTYPE_CHAR              , TD_CHAR             },
      {nsIDataType::VTYPE_WCHAR             , TD_WCHAR            },
      {nsIDataType::VTYPE_VOID              , TD_VOID             },
      {nsIDataType::VTYPE_ID                , TD_PNSIID           },
      {nsIDataType::VTYPE_DOMSTRING         , TD_DOMSTRING        },
      {nsIDataType::VTYPE_CHAR_STR          , TD_PSTRING          },
      {nsIDataType::VTYPE_WCHAR_STR         , TD_PWSTRING         },
      {nsIDataType::VTYPE_INTERFACE         , TD_INTERFACE_TYPE   },
      {nsIDataType::VTYPE_INTERFACE_IS      , TD_INTERFACE_IS_TYPE},
      {nsIDataType::VTYPE_ARRAY             , TD_ARRAY            },
      {nsIDataType::VTYPE_STRING_SIZE_IS    , TD_PSTRING_SIZE_IS  },
      {nsIDataType::VTYPE_WSTRING_SIZE_IS   , TD_PWSTRING_SIZE_IS },
      {nsIDataType::VTYPE_UTF8STRING        , TD_UTF8STRING       },
      {nsIDataType::VTYPE_CSTRING           , TD_CSTRING          },
      {nsIDataType::VTYPE_ASTRING           , TD_ASTRING          }
    };
    static const int length = sizeof(array) / sizeof(array[0]);
    static bool inited = false;
    if (!inited) {
      for (int i = 0; i < length; ++i) {
        NS_ASSERTION(array[i].a == array[i].b, "bad const declaration");
      }
      inited = true;
    }
  }
#endif
}

// For all the data getters we just forward to the static (and sharable)
// 'ConvertTo' functions.

NS_IMETHODIMP
nsVariantBase::GetDataType(uint16_t* aDataType)
{
  *aDataType = mData.GetType();
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::GetAsInt8(uint8_t* aResult)
{
  return mData.ConvertToInt8(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsInt16(int16_t* aResult)
{
  return mData.ConvertToInt16(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsInt32(int32_t* aResult)
{
  return mData.ConvertToInt32(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsInt64(int64_t* aResult)
{
  return mData.ConvertToInt64(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsUint8(uint8_t* aResult)
{
  return mData.ConvertToUint8(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsUint16(uint16_t* aResult)
{
  return mData.ConvertToUint16(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsUint32(uint32_t* aResult)
{
  return mData.ConvertToUint32(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsUint64(uint64_t* aResult)
{
  return mData.ConvertToUint64(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsFloat(float* aResult)
{
  return mData.ConvertToFloat(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsDouble(double* aResult)
{
  return mData.ConvertToDouble(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsBool(bool* aResult)
{
  return mData.ConvertToBool(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsChar(char* aResult)
{
  return mData.ConvertToChar(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsWChar(char16_t* aResult)
{
  return mData.ConvertToWChar(aResult);
}

NS_IMETHODIMP_(nsresult)
nsVariantBase::GetAsID(nsID* aResult)
{
  return mData.ConvertToID(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsAString(nsAString& aResult)
{
  return mData.ConvertToAString(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsDOMString(nsAString& aResult)
{
  // A DOMString maps to an AString internally, so we can re-use
  // ConvertToAString here.
  return mData.ConvertToAString(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsACString(nsACString& aResult)
{
  return mData.ConvertToACString(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsAUTF8String(nsAUTF8String& aResult)
{
  return mData.ConvertToAUTF8String(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsString(char** aResult)
{
  return mData.ConvertToString(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsWString(char16_t** aResult)
{
  return mData.ConvertToWString(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsISupports(nsISupports** aResult)
{
  return mData.ConvertToISupports(aResult);
}

NS_IMETHODIMP
nsVariantBase::GetAsJSVal(JS::MutableHandleValue)
{
  // Can only get the jsval from an XPCVariant.
  return NS_ERROR_CANNOT_CONVERT_DATA;
}

NS_IMETHODIMP
nsVariantBase::GetAsInterface(nsIID** aIID, void** aInterface)
{
  return mData.ConvertToInterface(aIID, aInterface);
}

NS_IMETHODIMP_(nsresult)
nsVariantBase::GetAsArray(uint16_t* aType, nsIID* aIID,
                      uint32_t* aCount, void** aPtr)
{
  return mData.ConvertToArray(aType, aIID, aCount, aPtr);
}

NS_IMETHODIMP
nsVariantBase::GetAsStringWithSize(uint32_t* aSize, char** aStr)
{
  return mData.ConvertToStringWithSize(aSize, aStr);
}

NS_IMETHODIMP
nsVariantBase::GetAsWStringWithSize(uint32_t* aSize, char16_t** aStr)
{
  return mData.ConvertToWStringWithSize(aSize, aStr);
}

/***************************************************************************/

NS_IMETHODIMP
nsVariantBase::GetWritable(bool* aWritable)
{
  *aWritable = mWritable;
  return NS_OK;
}
NS_IMETHODIMP
nsVariantBase::SetWritable(bool aWritable)
{
  if (!mWritable && aWritable) {
    return NS_ERROR_FAILURE;
  }
  mWritable = aWritable;
  return NS_OK;
}

/***************************************************************************/

// For all the data setters we just forward to the static (and sharable)
// 'SetFrom' functions.

NS_IMETHODIMP
nsVariantBase::SetAsInt8(uint8_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromInt8(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsInt16(int16_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromInt16(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsInt32(int32_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromInt32(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsInt64(int64_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromInt64(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsUint8(uint8_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromUint8(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsUint16(uint16_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromUint16(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsUint32(uint32_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromUint32(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsUint64(uint64_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromUint64(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsFloat(float aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromFloat(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsDouble(double aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromDouble(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsBool(bool aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromBool(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsChar(char aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromChar(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsWChar(char16_t aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromWChar(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsID(const nsID& aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromID(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsAString(const nsAString& aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromAString(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsDOMString(const nsAString& aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }

  mData.SetFromDOMString(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsACString(const nsACString& aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromACString(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsAUTF8String(const nsAUTF8String& aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromAUTF8String(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsString(const char* aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  return mData.SetFromString(aValue);
}

NS_IMETHODIMP
nsVariantBase::SetAsWString(const char16_t* aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  return mData.SetFromWString(aValue);
}

NS_IMETHODIMP
nsVariantBase::SetAsISupports(nsISupports* aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromISupports(aValue);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsInterface(const nsIID& aIID, void* aInterface)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetFromInterface(aIID, (nsISupports*)aInterface);
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsArray(uint16_t aType, const nsIID* aIID,
                      uint32_t aCount, void* aPtr)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  return mData.SetFromArray(aType, aIID, aCount, aPtr);
}

NS_IMETHODIMP
nsVariantBase::SetAsStringWithSize(uint32_t aSize, const char* aStr)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  return mData.SetFromStringWithSize(aSize, aStr);
}

NS_IMETHODIMP
nsVariantBase::SetAsWStringWithSize(uint32_t aSize, const char16_t* aStr)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  return mData.SetFromWStringWithSize(aSize, aStr);
}

NS_IMETHODIMP
nsVariantBase::SetAsVoid()
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetToVoid();
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsEmpty()
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetToEmpty();
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetAsEmptyArray()
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  mData.SetToEmptyArray();
  return NS_OK;
}

NS_IMETHODIMP
nsVariantBase::SetFromVariant(nsIVariant* aValue)
{
  if (!mWritable) {
    return NS_ERROR_OBJECT_IS_IMMUTABLE;
  }
  return mData.SetFromVariant(aValue);
}

/* nsVariant implementation */

NS_IMPL_ISUPPORTS(nsVariant, nsIVariant, nsIWritableVariant)


/* nsVariantCC implementation */
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsVariantCC)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
  NS_INTERFACE_MAP_ENTRY(nsIVariant)
  NS_INTERFACE_MAP_ENTRY(nsIWritableVariant)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION_CLASS(nsVariantCC)

NS_IMPL_CYCLE_COLLECTING_ADDREF(nsVariantCC)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsVariantCC)

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsVariantCC)
  tmp->mData.Traverse(cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsVariantCC)
  tmp->mData.Cleanup();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END