blob: 0915492e811cd915805ba47ce3396c461d5b21a7 [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_SCRIPT_MOZJS_45_NATIVE_PROMISE_H_
#define COBALT_SCRIPT_MOZJS_45_NATIVE_PROMISE_H_
#include "base/logging.h"
#include "cobalt/script/mozjs-45/conversion_helpers.h"
#include "cobalt/script/mozjs-45/mozjs_exception_state.h"
#include "cobalt/script/mozjs-45/mozjs_user_object_holder.h"
#include "cobalt/script/mozjs-45/promise_wrapper.h"
#include "cobalt/script/mozjs-45/type_traits.h"
#include "cobalt/script/mozjs-45/weak_heap_object.h"
#include "cobalt/script/promise.h"
#include "third_party/mozjs-45/js/src/jsapi.h"
namespace cobalt {
namespace script {
namespace mozjs {
// TODO: This lives here instead of conversion_helpers.h because right now
// |PromiseResultUndefined| is specific to promises. In the long run, we plan
// on abstracting all JavaScript value types, and should just use however that
// abstraction exposes "undefined" here instead.
inline void ToJSValue(JSContext* context,
const PromiseResultUndefined& in_undefined,
JS::MutableHandleValue out_value) {
out_value.setUndefined();
}
template <typename T>
class NativePromise : public Promise<T> {
public:
// ScriptObject boilerplate.
typedef Promise<T> BaseType;
// Handle special case T=void, by swapping the input parameter |T| for
// |PromiseResultUndefined|. Combined with how |Promise| handles this
// special case, we're left with something like:
//
// NativePromise<T> -> Promise<T>
// ^
// | (T=PromiseResultUndefined)
// /
// NativePromise<void> -> Promise<void>
//
using ResolveType =
typename std::conditional<std::is_same<T, void>::value,
PromiseResultUndefined, T>::type;
NativePromise(JSContext* context, JS::HandleValue resolver_value)
: context_(context) {
DCHECK(resolver_value.isObject());
promise_resolver_.emplace(context, resolver_value);
}
JSObject* handle() const { return promise_resolver_->get().GetObject(); }
const JS::Value& value() const { return promise_resolver_->get().GetValue(); }
bool WasCollected() const { return promise_resolver_->get().WasCollected(); }
void Trace(JSTracer* js_tracer) { promise_resolver_->get().Trace(js_tracer); }
// The Promise JS object (not the resolver).
JSObject* promise() const { return promise_resolver_->GetPromise(); }
void Resolve(const ResolveType& value) const override {
JS::RootedObject promise_resolver(context_,
promise_resolver_->get().GetObject());
DCHECK(promise_resolver);
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, promise_resolver);
JS::RootedValue converted_value(context_);
ToJSValue(context_, value, &converted_value);
promise_resolver_->Resolve(converted_value);
}
void Reject() const override {
JS::RootedObject promise_resolver(context_,
promise_resolver_->get().GetObject());
DCHECK(promise_resolver);
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, promise_resolver);
promise_resolver_->Reject(JS::UndefinedHandleValue);
}
void Reject(SimpleExceptionType exception) const override {
JS::RootedObject promise_resolver(context_,
promise_resolver_->get().GetObject());
DCHECK(promise_resolver);
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, promise_resolver);
JS::RootedValue error_result(context_);
error_result.setObject(
*MozjsExceptionState::CreateErrorObject(context_, exception));
promise_resolver_->Reject(error_result);
}
void Reject(const scoped_refptr<ScriptException>& result) const override {
JS::RootedObject promise_resolver(context_,
promise_resolver_->get().GetObject());
DCHECK(promise_resolver);
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, promise_resolver);
JS::RootedValue converted_result(context_);
ToJSValue(context_, result, &converted_result);
promise_resolver_->Reject(converted_result);
}
PromiseState State() const {
JS::RootedObject promise_resolver(context_,
promise_resolver_->get().GetObject());
DCHECK(promise_resolver);
JSAutoRequest auto_request(context_);
JSAutoCompartment auto_compartment(context_, promise_resolver);
return promise_resolver_->State();
}
private:
JSContext* context_;
base::Optional<PromiseWrapper> promise_resolver_;
};
template <typename T>
struct TypeTraits<NativePromise<T>> {
typedef MozjsUserObjectHolder<NativePromise<T>> ConversionType;
typedef const ScriptValue<Promise<T>>* ReturnType;
};
// Promise<T> -> JSValue
// Note that JSValue -> Promise<T> is not yet supported.
template <typename T>
inline void ToJSValue(JSContext* context,
const ScriptValue<Promise<T>>* promise_holder,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
if (!promise_holder) {
out_value.set(JS::NullValue());
return;
}
const MozjsUserObjectHolder<NativePromise<T>>* user_object_holder =
base::polymorphic_downcast<
const MozjsUserObjectHolder<NativePromise<T>>*>(promise_holder);
const NativePromise<T>* native_promise =
base::polymorphic_downcast<const NativePromise<T>*>(
user_object_holder->GetValue());
DCHECK(native_promise);
out_value.setObjectOrNull(native_promise->promise());
}
// Explicitly defer to the const version here so that a more generic non-const
// version of this function does not get called instead, in the case that
// |promise_holder| is not const.
template <typename T>
inline void ToJSValue(JSContext* context,
ScriptValue<Promise<T>>* promise_holder,
JS::MutableHandleValue out_value) {
TRACK_MEMORY_SCOPE("Javascript");
ToJSValue(context, const_cast<const ScriptValue<Promise<T>>*>(promise_holder),
out_value);
}
} // namespace mozjs
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_MOZJS_45_NATIVE_PROMISE_H_