summaryrefslogtreecommitdiffstats
path: root/src/point.cpp
blob: 70a48883c0e23fe8134f838cdee932665ec9ce55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "point.h"

#include <sstream>

extern "C" Janet geom_point_get(void *p, Janet key);

extern "C" void geom_point_tostring(void *p, JanetBuffer *buffer) {
    std::stringstream stream;
    stream << "<2geom/point " << *static_cast<Geom::Point *>(p) << ">";
    janet_buffer_push_cstring(buffer, stream.str().c_str());
}


const JanetAbstractType geom_point_type = {
    "2geom/point",
    NULL,
    NULL,
    geom_point_get,
    NULL,
    NULL,
    NULL,
    geom_point_tostring
};


Janet janet_wrap_point(Geom::Point const &x) {
    Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point));
    *box = (Geom::Point)x;
    return janet_wrap_abstract(box);
}


Geom::Point janet_unwrap_point(Janet x) {
    if (janet_checktype(x, JANET_ABSTRACT)) {
        void *abst = janet_unwrap_abstract(x);
        if (janet_abstract_type(abst) == &geom_point_type)
              return *(Geom::Point *)abst;
    }

    janet_panic("not a point");
    return Geom::Point();
}


extern "C" Janet cfun_geom_point_new(int32_t argc, Janet *argv) {
    janet_fixarity(argc, 2);
    double x = janet_getnumber(argv, 0);
    double y = janet_getnumber(argv, 1);
    return janet_wrap_point(Geom::Point(x, y));
}

const JanetReg it_cfuns[] = {
    {
        "point", cfun_geom_point_new,
        "(geom/point x y)\n\nCreate a Point from x/y coordinate values."
    },
    {NULL, NULL, NULL}
};


#define OPMETHOD(name, oper) \
static Janet cfun_geom_point_##name(int32_t argc, Janet *argv) { \
    janet_arity(argc, 2, -1); \
    Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); \
    *box = janet_unwrap_point(argv[0]); \
    for (int i = 1; i < argc; i++) \
        *box oper##= janet_unwrap_point(argv[i]); \
    return janet_wrap_abstract(box); \
} \
 \
static Janet cfun_geom_point_##name##_mut(int32_t argc, Janet *argv) { \
    janet_arity(argc, 2, -1); \
    Geom::Point *box = (Geom::Point *)janet_abstract(&geom_point_type, sizeof(Geom::Point)); \
    for (int i = 1; i < argc; i++) \
        *box oper##= janet_unwrap_point(argv[i]); \
    return janet_wrap_abstract(box); \
}

OPMETHOD(add, +)
OPMETHOD(sub, -)

static JanetMethod geom_point_methods[] = {
    {"+", cfun_geom_point_add},
    {"-", cfun_geom_point_sub},
    {NULL, NULL}
};

extern "C" Janet geom_point_get(void *p, Janet key) {
    Geom::Point *box = (Geom::Point *)p;
    if (!janet_checktype(key, JANET_KEYWORD))
        janet_panicf("expected keyword, got %v", key);

    uint8_t const *keystr = janet_unwrap_keyword(key);
    if (janet_string_equal(keystr, janet_cstring("x"))) {
        return janet_wrap_number(box->x());
    } else if (janet_string_equal(keystr, janet_cstring("y"))) {
        return janet_wrap_number(box->y());
    } else {
        return janet_getmethod(keystr, geom_point_methods);
    }
}

extern "C" void janet_lib_geom_point(JanetTable *env) {
    janet_cfuns(env, NULL, it_cfuns);
    janet_register_abstract_type(&geom_point_type);
}