dom/future/FutureCallback.cpp
author Ehsan Akhgari <ehsan@mozilla.com>
Wed, 19 Jun 2013 21:57:57 -0400
changeset 135755 6208332c8b0430bddea134948d8068f235806f42
parent 135745 dom/promise/PromiseCallback.cpp@c1596bee956c700875d972f4d20bb462603cfb76
child 135786 ac7663828c8823ccadc73614671309eb7e9f9d06
permissions -rw-r--r--
Backed out changeset c1596bee956c (bug 884279) because of build bustage

/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=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 "FutureCallback.h"
#include "mozilla/dom/Future.h"
#include "mozilla/dom/FutureResolver.h"

namespace mozilla {
namespace dom {

NS_IMPL_CYCLE_COLLECTING_ADDREF(FutureCallback)
NS_IMPL_CYCLE_COLLECTING_RELEASE(FutureCallback)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FutureCallback)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FutureCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FutureCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

FutureCallback::FutureCallback()
{
  MOZ_COUNT_CTOR(FutureCallback);
}

FutureCallback::~FutureCallback()
{
  MOZ_COUNT_DTOR(FutureCallback);
}

// ResolveFutureCallback

NS_IMPL_CYCLE_COLLECTION_INHERITED_1(ResolveFutureCallback,
                                     FutureCallback,
                                     mResolver)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ResolveFutureCallback)
NS_INTERFACE_MAP_END_INHERITING(FutureCallback)

NS_IMPL_ADDREF_INHERITED(ResolveFutureCallback, FutureCallback)
NS_IMPL_RELEASE_INHERITED(ResolveFutureCallback, FutureCallback)

ResolveFutureCallback::ResolveFutureCallback(FutureResolver* aResolver)
  : mResolver(aResolver)
{
  MOZ_ASSERT(aResolver);
  MOZ_COUNT_CTOR(ResolveFutureCallback);
}

ResolveFutureCallback::~ResolveFutureCallback()
{
  MOZ_COUNT_DTOR(ResolveFutureCallback);
}

void
ResolveFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{
  // Run resolver's algorithm with value and the synchronous flag set.
  AutoJSContext cx;
  // FIXME Bug 878849
  Maybe<JSAutoCompartment> ac;
  if (aValue.WasPassed() && aValue.Value().isObject()) {
    JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
    ac.construct(cx, rooted);
  }

  mResolver->ResolveInternal(cx, aValue, FutureResolver::SyncTask);
}

// RejectFutureCallback

NS_IMPL_CYCLE_COLLECTION_INHERITED_1(RejectFutureCallback,
                                     FutureCallback,
                                     mResolver)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(RejectFutureCallback)
NS_INTERFACE_MAP_END_INHERITING(FutureCallback)

NS_IMPL_ADDREF_INHERITED(RejectFutureCallback, FutureCallback)
NS_IMPL_RELEASE_INHERITED(RejectFutureCallback, FutureCallback)

RejectFutureCallback::RejectFutureCallback(FutureResolver* aResolver)
  : mResolver(aResolver)
{
  MOZ_ASSERT(aResolver);
  MOZ_COUNT_CTOR(RejectFutureCallback);
}

RejectFutureCallback::~RejectFutureCallback()
{
  MOZ_COUNT_DTOR(RejectFutureCallback);
}

void
RejectFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{
  // Run resolver's algorithm with value and the synchronous flag set.
  AutoJSContext cx;
  // FIXME Bug 878849
  Maybe<JSAutoCompartment> ac;
  if (aValue.WasPassed() && aValue.Value().isObject()) {
    JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
    ac.construct(cx, rooted);
  }

  mResolver->RejectInternal(cx, aValue, FutureResolver::SyncTask);
}

// WrapperFutureCallback

NS_IMPL_CYCLE_COLLECTION_INHERITED_2(WrapperFutureCallback,
                                     FutureCallback,
                                     mNextResolver, mCallback)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WrapperFutureCallback)
NS_INTERFACE_MAP_END_INHERITING(FutureCallback)

NS_IMPL_ADDREF_INHERITED(WrapperFutureCallback, FutureCallback)
NS_IMPL_RELEASE_INHERITED(WrapperFutureCallback, FutureCallback)

WrapperFutureCallback::WrapperFutureCallback(FutureResolver* aNextResolver,
                                             AnyCallback* aCallback)
  : mNextResolver(aNextResolver)
  , mCallback(aCallback)
{
  MOZ_ASSERT(aNextResolver);
  MOZ_COUNT_CTOR(WrapperFutureCallback);
}

WrapperFutureCallback::~WrapperFutureCallback()
{
  MOZ_COUNT_DTOR(WrapperFutureCallback);
}

void
WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{
  AutoJSContext cx;
  // FIXME Bug 878849
  Maybe<JSAutoCompartment> ac;
  if (aValue.WasPassed() && aValue.Value().isObject()) {
    JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
    ac.construct(cx, rooted);
  }

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  Optional<JS::Handle<JS::Value> > value(cx,
    mCallback->Call(mNextResolver->GetParentObject(), aValue, rv,
                    CallbackObject::eRethrowExceptions));

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    Optional<JS::Handle<JS::Value> > value(cx);
    rv.StealJSException(cx, &value.Value());
    mNextResolver->RejectInternal(cx, value, FutureResolver::SyncTask);
    return;
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  mNextResolver->ResolveInternal(cx, value, FutureResolver::SyncTask);
}

// SimpleWrapperFutureCallback

NS_IMPL_CYCLE_COLLECTION_INHERITED_2(SimpleWrapperFutureCallback,
                                     FutureCallback,
                                     mFuture, mCallback)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SimpleWrapperFutureCallback)
NS_INTERFACE_MAP_END_INHERITING(FutureCallback)

NS_IMPL_ADDREF_INHERITED(SimpleWrapperFutureCallback, FutureCallback)
NS_IMPL_RELEASE_INHERITED(SimpleWrapperFutureCallback, FutureCallback)

SimpleWrapperFutureCallback::SimpleWrapperFutureCallback(Future* aFuture,
                                                         AnyCallback* aCallback)
  : mFuture(aFuture)
  , mCallback(aCallback)
{
  MOZ_ASSERT(aFuture);
  MOZ_COUNT_CTOR(SimpleWrapperFutureCallback);
}

SimpleWrapperFutureCallback::~SimpleWrapperFutureCallback()
{
  MOZ_COUNT_DTOR(SimpleWrapperFutureCallback);
}

void
SimpleWrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{
  ErrorResult rv;
  mCallback->Call(mFuture, aValue, rv);
}

/* static */ FutureCallback*
FutureCallback::Factory(FutureResolver* aNextResolver,
                        AnyCallback* aCallback, Task aTask)
{
  MOZ_ASSERT(aNextResolver);

  // If we have a callback and a next resolver, we have to exec the callback and
  // then propagate the return value to the next resolver->resolve().
  if (aCallback) {
    return new WrapperFutureCallback(aNextResolver, aCallback);
  }

  if (aTask == Resolve) {
    return new ResolveFutureCallback(aNextResolver);
  }

  if (aTask == Reject) {
    return new RejectFutureCallback(aNextResolver);
  }

  MOZ_ASSERT(false, "This should not happen");
  return nullptr;
}

} // namespace dom
} // namespace mozilla