view libclient-js/malikania/js-line.cpp @ 37:702e0a2b9e5e

Misc: make JavaScript different libraries, Closes T3
author David Demelier <markand@malikania.fr>
date Thu, 18 Aug 2016 11:07:34 +0200
parents libclient/malikania/js-line.cpp@9af360f34c7d
children
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 <cassert>

#include "js-line.hpp"

namespace malikania {

namespace {

duk_ret_t constructor(duk_context *ctx)
{
    Line line;

    if (duk_get_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_get_top(ctx) == 1)
        line = dukx_require_line(ctx, 0);

    duk_ret_t ret;

    /* Allow both constructor and non constructor calls */
    if (duk_is_constructor_call(ctx)) {
        duk_push_this(ctx);
        dukx_put_line(ctx, line);
        ret = 0;
    } else {
        dukx_push_line(ctx, line);
        ret = 1;
    }

    return ret;
}

} // !namespace

Line dukx_get_line(duk_context *ctx, duk_idx_t index)
{
    auto get = [&] (auto name) {
        StackAssert sa(ctx);

        duk_get_prop_string(ctx, index, name);
        auto v = duk_get_int(ctx, -1);
        duk_pop(ctx);

        return v;
    };

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

Line dukx_require_line(duk_context *ctx, duk_idx_t index)
{
    auto get = [&] (auto prop) {
        if (!duk_has_prop_string(ctx, index, prop))
            duk_error(ctx, DUK_ERR_ERROR, "missing %s property in line description", prop);

        duk_get_prop_string(ctx, index, prop);

        if (!duk_is_number(ctx, -1)) {
            duk_pop(ctx);
            duk_error(ctx, DUK_ERR_TYPE_ERROR, "property %s is not an int", prop);
        }

        auto value = duk_to_int(ctx, -1);

        duk_pop(ctx);

        return value;
    };

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

Line dukx_optional_line(duk_context *ctx, duk_idx_t index, Line def)
{
    return duk_is_object(ctx, index) ? dukx_get_line(ctx, index) : def;
}

void dukx_push_line(duk_context *ctx, const Line &line)
{
    StackAssert sa(ctx, 1);

    duk_push_object(ctx);
    dukx_put_line(ctx, line);
}

void dukx_put_line(duk_context *ctx, const Line &line)
{
    assert(duk_is_object(ctx, -1));

    StackAssert sa(ctx);

    duk_push_int(ctx, line.x1());
    duk_put_prop_string(ctx, -2, "x1");
    duk_push_int(ctx, line.y1());
    duk_put_prop_string(ctx, -2, "y1");
    duk_push_int(ctx, line.x2());
    duk_put_prop_string(ctx, -2, "x2");
    duk_push_int(ctx, line.y2());
    duk_put_prop_string(ctx, -2, "y2");
}

void dukx_load_line(duk_context *ctx)
{
    StackAssert sa(ctx, 0);

    duk_get_global_string(ctx, "Malikania");
    duk_push_c_function(ctx, constructor, DUK_VARARGS);
    duk_put_prop_string(ctx, -2, "Line");
    duk_pop(ctx);
}

} // !malikania