/*
    This file is part of the WebKit open source project.
    This file has been generated by generate-bindings.pl. DO NOT MODIFY!

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "config.h"

#if ENABLE(READABLE_STREAM_API)

#include "JSReadableStreamDefaultReader.h"

#include "JSDOMBinding.h"
#include "JSDOMConstructor.h"
#include "ReadableStreamDefaultReaderBuiltins.h"
#include <runtime/FunctionPrototype.h>
#include <wtf/GetPtr.h>

using namespace JSC;

namespace WebCore {

// Functions


// Attributes

JSC::EncodedJSValue jsReadableStreamDefaultReaderConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
bool setJSReadableStreamDefaultReaderConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);

class JSReadableStreamDefaultReaderPrototype : public JSC::JSNonFinalObject {
public:
    typedef JSC::JSNonFinalObject Base;
    static JSReadableStreamDefaultReaderPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
    {
        JSReadableStreamDefaultReaderPrototype* ptr = new (NotNull, JSC::allocateCell<JSReadableStreamDefaultReaderPrototype>(vm.heap)) JSReadableStreamDefaultReaderPrototype(vm, globalObject, structure);
        ptr->finishCreation(vm);
        return ptr;
    }

    DECLARE_INFO;
    static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
    {
        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
    }

private:
    JSReadableStreamDefaultReaderPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
        : JSC::JSNonFinalObject(vm, structure)
    {
    }

    void finishCreation(JSC::VM&);
};

typedef JSDOMConstructor<JSReadableStreamDefaultReader> JSReadableStreamDefaultReaderConstructor;

template<> JSC::EncodedJSValue JSC_HOST_CALL JSReadableStreamDefaultReaderConstructor::construct(JSC::ExecState* exec)
{
    ASSERT(exec);
    return constructJSReadableStreamDefaultReader(*exec);
}

template<> JSValue JSReadableStreamDefaultReaderConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
{
    UNUSED_PARAM(vm);
    return globalObject.functionPrototype();
}

template<> void JSReadableStreamDefaultReaderConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
{
    putDirect(vm, vm.propertyNames->prototype, JSReadableStreamDefaultReader::prototype(vm, &globalObject), DontDelete | ReadOnly | DontEnum);
    putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral("ReadableStreamDefaultReader"))), ReadOnly | DontEnum);
    putDirect(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum);
}

template<> const ClassInfo JSReadableStreamDefaultReaderConstructor::s_info = { "ReadableStreamDefaultReader", &Base::s_info, 0, CREATE_METHOD_TABLE(JSReadableStreamDefaultReaderConstructor) };

/* Hash table for prototype */

static const HashTableValue JSReadableStreamDefaultReaderPrototypeTableValues[] =
{
    { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsReadableStreamDefaultReaderConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSReadableStreamDefaultReaderConstructor) } },
    { "closed", DontEnum | ReadOnly | Accessor | Builtin, NoIntrinsic, { (intptr_t)static_cast<BuiltinGenerator>(readableStreamDefaultReaderClosedCodeGenerator), (intptr_t) (0) } },
    { "read", DontEnum | JSC::Builtin, NoIntrinsic, { (intptr_t)static_cast<BuiltinGenerator>(readableStreamDefaultReaderReadCodeGenerator), (intptr_t) (0) } },
    { "cancel", DontEnum | JSC::Builtin, NoIntrinsic, { (intptr_t)static_cast<BuiltinGenerator>(readableStreamDefaultReaderCancelCodeGenerator), (intptr_t) (0) } },
    { "releaseLock", DontEnum | JSC::Builtin, NoIntrinsic, { (intptr_t)static_cast<BuiltinGenerator>(readableStreamDefaultReaderReleaseLockCodeGenerator), (intptr_t) (0) } },
};

const ClassInfo JSReadableStreamDefaultReaderPrototype::s_info = { "ReadableStreamDefaultReaderPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSReadableStreamDefaultReaderPrototype) };

void JSReadableStreamDefaultReaderPrototype::finishCreation(VM& vm)
{
    Base::finishCreation(vm);
    reifyStaticProperties(vm, JSReadableStreamDefaultReaderPrototypeTableValues, *this);
}

const ClassInfo JSReadableStreamDefaultReader::s_info = { "ReadableStreamDefaultReader", &Base::s_info, 0, CREATE_METHOD_TABLE(JSReadableStreamDefaultReader) };

JSReadableStreamDefaultReader::JSReadableStreamDefaultReader(Structure* structure, JSDOMGlobalObject& globalObject)
    : JSDOMObject(structure, globalObject) { }

JSObject* JSReadableStreamDefaultReader::createPrototype(VM& vm, JSGlobalObject* globalObject)
{
    return JSReadableStreamDefaultReaderPrototype::create(vm, globalObject, JSReadableStreamDefaultReaderPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
}

JSObject* JSReadableStreamDefaultReader::prototype(VM& vm, JSGlobalObject* globalObject)
{
    return getDOMPrototype<JSReadableStreamDefaultReader>(vm, globalObject);
}

void JSReadableStreamDefaultReader::destroy(JSC::JSCell* cell)
{
    JSReadableStreamDefaultReader* thisObject = static_cast<JSReadableStreamDefaultReader*>(cell);
    thisObject->JSReadableStreamDefaultReader::~JSReadableStreamDefaultReader();
}

EncodedJSValue jsReadableStreamDefaultReaderConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    JSReadableStreamDefaultReaderPrototype* domObject = jsDynamicCast<JSReadableStreamDefaultReaderPrototype*>(JSValue::decode(thisValue));
    if (UNLIKELY(!domObject))
        return throwVMTypeError(state, throwScope);
    JSValue constructor = JSReadableStreamDefaultReaderConstructor::create(state->vm(), JSReadableStreamDefaultReaderConstructor::createStructure(state->vm(), *domObject->globalObject(), domObject->globalObject()->objectPrototype()), *jsCast<JSDOMGlobalObject*>(domObject->globalObject()));
    // Shadowing constructor property to ensure reusing the same constructor object
    domObject->putDirect(state->vm(), state->propertyNames().constructor, constructor, DontEnum | ReadOnly);
    return JSValue::encode(constructor);
}

bool setJSReadableStreamDefaultReaderConstructor(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
{
    VM& vm = state->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    JSValue value = JSValue::decode(encodedValue);
    JSReadableStreamDefaultReaderPrototype* domObject = jsDynamicCast<JSReadableStreamDefaultReaderPrototype*>(JSValue::decode(thisValue));
    if (UNLIKELY(!domObject)) {
        throwVMTypeError(state, throwScope);
        return false;
    }
    // Shadowing a built-in constructor
    return domObject->putDirect(state->vm(), state->propertyNames().constructor, value);
}


}

#endif // ENABLE(READABLE_STREAM_API)
