File: packer_ext_registry.h

package info (click to toggle)
ruby-msgpack 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 972 kB
  • sloc: ruby: 4,789; ansic: 4,309; java: 1,809; makefile: 4
file content (140 lines) | stat: -rw-r--r-- 4,846 bytes parent folder | download | duplicates (2)
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * MessagePack for Ruby
 *
 * Copyright (C) 2008-2015 Sadayuki Furuhashi
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
#ifndef MSGPACK_RUBY_PACKER_EXT_REGISTRY_H__
#define MSGPACK_RUBY_PACKER_EXT_REGISTRY_H__

#include "compat.h"
#include "ruby.h"

#define MSGPACK_EXT_RECURSIVE 0b0001

struct msgpack_packer_ext_registry_t;
typedef struct msgpack_packer_ext_registry_t msgpack_packer_ext_registry_t;

struct msgpack_packer_ext_registry_t {
    VALUE hash;
    VALUE cache; // lookup cache for ext types inherited from a super class
};

void msgpack_packer_ext_registry_init(VALUE owner, msgpack_packer_ext_registry_t* pkrg);

static inline void msgpack_packer_ext_registry_destroy(msgpack_packer_ext_registry_t* pkrg)
{ }

void msgpack_packer_ext_registry_mark(msgpack_packer_ext_registry_t* pkrg);

void msgpack_packer_ext_registry_borrow(VALUE owner, msgpack_packer_ext_registry_t* src,
        msgpack_packer_ext_registry_t* dst);

void msgpack_packer_ext_registry_dup(VALUE owner, msgpack_packer_ext_registry_t* src,
        msgpack_packer_ext_registry_t* dst);

void msgpack_packer_ext_registry_put(VALUE owner, msgpack_packer_ext_registry_t* pkrg,
        VALUE ext_module, int ext_type, int flags, VALUE proc);

static int msgpack_packer_ext_find_superclass(VALUE key, VALUE value, VALUE arg)
{
    VALUE *args = (VALUE *) arg;
    if(key == Qundef) {
        return ST_CONTINUE;
    }
    if(rb_class_inherited_p(args[0], key) == Qtrue) {
        args[1] = key;
        return ST_STOP;
    }
    return ST_CONTINUE;
}

static inline VALUE msgpack_packer_ext_registry_fetch(msgpack_packer_ext_registry_t* pkrg,
        VALUE lookup_class, int* ext_type_result, int* ext_flags_result)
{
    // fetch lookup_class from hash, which is a hash to register classes
    VALUE type = rb_hash_lookup(pkrg->hash, lookup_class);
    if(type != Qnil) {
        *ext_type_result = FIX2INT(rb_ary_entry(type, 0));
        *ext_flags_result = FIX2INT(rb_ary_entry(type, 2));
        return rb_ary_entry(type, 1);
    }

    // fetch lookup_class from cache, which stores results of searching ancestors from pkrg->hash
    if (RTEST(pkrg->cache)) {
        VALUE type_inht = rb_hash_lookup(pkrg->cache, lookup_class);
        if(type_inht != Qnil) {
            *ext_type_result = FIX2INT(rb_ary_entry(type_inht, 0));
            *ext_flags_result = FIX2INT(rb_ary_entry(type_inht, 2));
            return rb_ary_entry(type_inht, 1);
        }
    }

    return Qnil;
}

static inline VALUE msgpack_packer_ext_registry_lookup(msgpack_packer_ext_registry_t* pkrg,
        VALUE instance, int* ext_type_result, int* ext_flags_result)
{
    VALUE type;

    if (pkrg->hash == Qnil) { // No extensions registered
        return Qnil;
    }

   /*
    * 1. check whether singleton_class or class of this instance is registered (or resolved in past) or not.
    *
    * Objects of type Integer (Fixnum, Bignum), Float, Symbol and frozen
    * `rb_class_of` returns the singleton_class if the object has one, or the "real class" otherwise.
    */
    VALUE lookup_class = rb_class_of(instance);
    type = msgpack_packer_ext_registry_fetch(pkrg, lookup_class, ext_type_result, ext_flags_result);
    if(type != Qnil) {
        return type;
    }

    /*
     * 2. If the object had a singleton_class check if the real class of instance is registered
     * (or resolved in past) or not.
     */
    VALUE real_class = rb_obj_class(instance);
    if(lookup_class != real_class) {
        type = msgpack_packer_ext_registry_fetch(pkrg, real_class, ext_type_result, ext_flags_result);
        if(type != Qnil) {
            return type;
        }
    }

    /*
     * 3. check all keys whether it is an ancestor of lookup_class, or not
     */
    VALUE args[2];
    args[0] = lookup_class;
    args[1] = Qnil;
    rb_hash_foreach(pkrg->hash, msgpack_packer_ext_find_superclass, (VALUE) args);

    VALUE superclass = args[1];
    if(superclass != Qnil) {
        VALUE superclass_type = rb_hash_lookup(pkrg->hash, superclass);
        rb_hash_aset(pkrg->cache, lookup_class, superclass_type);
        *ext_type_result = FIX2INT(rb_ary_entry(superclass_type, 0));
        *ext_flags_result = FIX2INT(rb_ary_entry(superclass_type, 2));
        return rb_ary_entry(superclass_type, 1);
    }

    return Qnil;
}

#endif