view libclient/malikania/js-line.cpp @ 17:63ba461b7f84

Client: add JavaScript bindings for Line, #465
author David Demelier <markand@malikania.fr>
date Sun, 03 Apr 2016 14:50:03 +0200
parents
children a1e80d991968
line wrap: on
line source

/*
 * js-line.cpp -- line description (JavaScript binding)
 *
 * Copyright (c) 2013-2016 Malikania Authors
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "js-line.h"

namespace malikania {

namespace {

duk::Ret constructor(duk::ContextPtr ctx)
{
	Line line;

	if (duk::top(ctx) == 4) {
		line = Line(
			duk::get<int>(ctx, 0),
			duk::get<int>(ctx, 1),
			duk::get<int>(ctx, 2),
			duk::get<int>(ctx, 3)
		);
	} else if (duk::top(ctx) == 1) {
		line = duk::require<Line>(ctx, 0);
	}

	duk::Ret ret;

	/* Allow both constructor and non constructor calls */
	if (duk_is_constructor_call(ctx)) {
		duk::push(ctx, duk::This());
		/* TODO: use duk::put when available */
		duk::TypeTraits<Line>::put(ctx, line);
		duk::pop(ctx);
		ret = 0;
	} else {
		duk::push(ctx, line);
		ret = 1;
	}

	return ret;
}

} // !namespace

namespace duk {

Line TypeTraits<Line>::get(ContextPtr ctx, Index index)
{
	duk::StackAssert sa(ctx);

	return Line(
		duk::getProperty<int>(ctx, index, "x1"),
		duk::getProperty<int>(ctx, index, "y1"),
		duk::getProperty<int>(ctx, index, "x2"),
		duk::getProperty<int>(ctx, index, "y2")
	);
}

Line TypeTraits<Line>::require(ContextPtr ctx, Index index)
{
	duk::StackAssert sa(ctx);

	auto get = [&] (const std::string &property) -> int {
		if (!duk::hasProperty(ctx, index, property)) {
			duk::raise(ctx, DUK_ERR_ERROR, "missing %s property in line description", property.c_str());
		}

		duk::getProperty<void>(ctx, index, property);

		if (!duk::is<int>(ctx, -1)) {
			duk::pop(ctx);
			duk::raise(ctx, DUK_ERR_TYPE_ERROR, "property %s is not an int", property.c_str());
		}

		int value = duk::get<int>(ctx, -1);

		duk::pop(ctx);

		return value;
	};

	return Line(get("x1"), get("y1"), get("x2"), get("y2"));
}

Line TypeTraits<Line>::optional(ContextPtr ctx, Index index, Line def)
{
	return duk::is<duk::Object>(ctx, index) ? get(ctx, index) : def;
}

void TypeTraits<Line>::push(ContextPtr ctx, const Line &line)
{
	duk::StackAssert sa(ctx, 1);

	duk::push(ctx, duk::Object());
	duk::TypeTraits<Line>::put(ctx, line);
}

void TypeTraits<Line>::put(ContextPtr ctx, const Line &line)
{
	assert(duk::is<duk::Object>(ctx, -1));

	duk::StackAssert sa(ctx);

	duk::putProperty(ctx, -1, "x1", line.x1());
	duk::putProperty(ctx, -1, "y1", line.y1());
	duk::putProperty(ctx, -1, "x2", line.x2());
	duk::putProperty(ctx, -1, "y2", line.y2());
}

} // !duk

void loadMalikaniaLine(duk::ContextPtr ctx)
{
	duk::StackAssert sa(ctx, 0);

	duk::getGlobal<void>(ctx, "Malikania");
	duk::putProperty(ctx, -1, "Line", duk::Function{constructor, DUK_VARARGS});
	duk::pop(ctx);
}

} // !malikania