quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

point.c (4781B)


      1 /*
      2  * QuickJS: Example of C module with a class
      3  *
      4  * Copyright (c) 2019 Fabrice Bellard
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 #include "../quickjs.h"
     25 #include <math.h>
     26 
     27 #define countof(x) (sizeof(x) / sizeof((x)[0]))
     28 
     29 /* Point Class */
     30 
     31 typedef struct {
     32     int x;
     33     int y;
     34 } JSPointData;
     35 
     36 static JSClassID js_point_class_id;
     37 
     38 static void js_point_finalizer(JSRuntime *rt, JSValue val)
     39 {
     40     JSPointData *s = JS_GetOpaque(val, js_point_class_id);
     41     /* Note: 's' can be NULL in case JS_SetOpaque() was not called */
     42     js_free_rt(rt, s);
     43 }
     44 
     45 static JSValue js_point_ctor(JSContext *ctx,
     46                              JSValueConst new_target,
     47                              int argc, JSValueConst *argv)
     48 {
     49     JSPointData *s;
     50     JSValue obj = JS_UNDEFINED;
     51     JSValue proto;
     52 
     53     s = js_mallocz(ctx, sizeof(*s));
     54     if (!s)
     55         return JS_EXCEPTION;
     56     if (JS_ToInt32(ctx, &s->x, argv[0]))
     57         goto fail;
     58     if (JS_ToInt32(ctx, &s->y, argv[1]))
     59         goto fail;
     60     /* using new_target to get the prototype is necessary when the
     61        class is extended. */
     62     proto = JS_GetPropertyStr(ctx, new_target, "prototype");
     63     if (JS_IsException(proto))
     64         goto fail;
     65     obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
     66     JS_FreeValue(ctx, proto);
     67     if (JS_IsException(obj))
     68         goto fail;
     69     JS_SetOpaque(obj, s);
     70     return obj;
     71  fail:
     72     js_free(ctx, s);
     73     JS_FreeValue(ctx, obj);
     74     return JS_EXCEPTION;
     75 }
     76 
     77 static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
     78 {
     79     JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
     80     if (!s)
     81         return JS_EXCEPTION;
     82     if (magic == 0)
     83         return JS_NewInt32(ctx, s->x);
     84     else
     85         return JS_NewInt32(ctx, s->y);
     86 }
     87 
     88 static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)
     89 {
     90     JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
     91     int v;
     92     if (!s)
     93         return JS_EXCEPTION;
     94     if (JS_ToInt32(ctx, &v, val))
     95         return JS_EXCEPTION;
     96     if (magic == 0)
     97         s->x = v;
     98     else
     99         s->y = v;
    100     return JS_UNDEFINED;
    101 }
    102 
    103 static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
    104                              int argc, JSValueConst *argv)
    105 {
    106     JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
    107     if (!s)
    108         return JS_EXCEPTION;
    109     return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
    110 }
    111 
    112 static JSClassDef js_point_class = {
    113     "Point",
    114     .finalizer = js_point_finalizer,
    115 };
    116 
    117 static const JSCFunctionListEntry js_point_proto_funcs[] = {
    118     JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
    119     JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
    120     JS_CFUNC_DEF("norm", 0, js_point_norm),
    121 };
    122 
    123 static int js_point_init(JSContext *ctx, JSModuleDef *m)
    124 {
    125     JSValue point_proto, point_class;
    126 
    127     /* create the Point class */
    128     JS_NewClassID(&js_point_class_id);
    129     JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
    130 
    131     point_proto = JS_NewObject(ctx);
    132     JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
    133 
    134     point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
    135     /* set proto.constructor and ctor.prototype */
    136     JS_SetConstructor(ctx, point_class, point_proto);
    137     JS_SetClassProto(ctx, js_point_class_id, point_proto);
    138 
    139     JS_SetModuleExport(ctx, m, "Point", point_class);
    140     return 0;
    141 }
    142 
    143 JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
    144 {
    145     JSModuleDef *m;
    146     m = JS_NewCModule(ctx, module_name, js_point_init);
    147     if (!m)
    148         return NULL;
    149     JS_AddModuleExport(ctx, m, "Point");
    150     return m;
    151 }