Class: RocketAMF::Ext::FastClassMapping

Inherits:
Object
  • Object
show all
Defined in:
ext/rocketamf_ext/class_mapping.c

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeObject

Initialize class mapping object, setting use_class_mapping to false



264
265
266
267
268
269
270
271
# File 'ext/rocketamf_ext/class_mapping.c', line 264

static VALUE mapping_init(VALUE self) {
    CLASS_MAPPING *map;
    Data_Get_Struct(self, CLASS_MAPPING, map);
    map->mapset = rb_funcall(CLASS_OF(self), id_mappings, 0);
    VALUE use_ac = rb_funcall(CLASS_OF(self), id_use_ac, 0);
    rb_ivar_set(self, id_use_ac_ivar, use_ac);
    return self;
}

Instance Attribute Details

#use_array_collectionObject (readonly)

Class Method Details

.define {|m| ... } ⇒ nil

Define class mappings in the block. Block is passed a MappingSet object as the first parameter. See RocketAMF::ClassMapping for details.

Yields:

  • (m)

Returns:

  • (nil)


244
245
246
247
248
249
250
# File 'ext/rocketamf_ext/class_mapping.c', line 244

static VALUE mapping_s_define(VALUE klass) {
    if (rb_block_given_p()) {
        VALUE mappings = rb_funcall(klass, id_mappings, 0);
        rb_yield(mappings);
    }
    return Qnil;
}

.mappingsObject

Return MappingSet for class mapper, creating if uninitialized



228
229
230
231
232
233
234
235
# File 'ext/rocketamf_ext/class_mapping.c', line 228

static VALUE mapping_s_mappings(VALUE klass) {
    VALUE mappings = rb_ivar_get(klass, id_mappings_ivar);
    if(mappings == Qnil) {
        mappings = rb_class_new_instance(0, NULL, cFastMappingSet);
        rb_ivar_set(klass, id_mappings_ivar, mappings);
    }
    return mappings;
}

.resetObject

Reset class mappings



255
256
257
258
259
# File 'ext/rocketamf_ext/class_mapping.c', line 255

static VALUE mapping_s_reset(VALUE klass) {
    rb_ivar_set(klass, id_use_ac_ivar, Qfalse);
    rb_ivar_set(klass, id_mappings_ivar, Qnil);
    return Qnil;
}

.use_array_collectionObject

Class-level getter for use_array_collection



209
210
211
212
213
214
215
216
# File 'ext/rocketamf_ext/class_mapping.c', line 209

static VALUE mapping_s_array_collection_get(VALUE klass) {
    VALUE use_ac = rb_ivar_get(klass, id_use_ac_ivar);
    if(use_ac == Qnil) {
        use_ac = Qfalse;
        rb_ivar_set(klass, id_use_ac_ivar, use_ac);
    }
    return use_ac;
}

.use_array_collection=(use_ac) ⇒ Object

Class-level setter for use_array_collection



221
222
223
# File 'ext/rocketamf_ext/class_mapping.c', line 221

static VALUE mapping_s_array_collection_set(VALUE klass, VALUE use_ac) {
    return rb_ivar_set(klass, id_use_ac_ivar, use_ac);
}

Instance Method Details

#get_as_class_nameString

Returns the AS class name for the given ruby object. Will also take a string containing the ruby class name.

Returns:

  • (String)


280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'ext/rocketamf_ext/class_mapping.c', line 280

static VALUE mapping_as_class_name(VALUE self, VALUE obj) {
    CLASS_MAPPING *map;
    Data_Get_Struct(self, CLASS_MAPPING, map);

    int type = TYPE(obj);
    const char* class_name;
    if(type == T_STRING) {
        // Use strings as the class name
        class_name = RSTRING_PTR(obj);
    } else {
        // Look up the class name and use that
        VALUE klass = CLASS_OF(obj);
        class_name = rb_class2name(klass);
        if(klass == cTypedHash) {
            VALUE orig_name = rb_funcall(obj, rb_intern("type"), 0);
            class_name = RSTRING_PTR(orig_name);
        } else if(type == T_HASH) {
            // Don't bother looking up hash mapping, but need to check class name first in case it's a typed hash
            return Qnil;
        }
    }

    return mapset_as_lookup(map->mapset, class_name);
}

#get_ruby_obj(name) ⇒ Object

call_seq:

mapper.get_ruby_obj => obj

Instantiates a ruby object using the mapping configuration based on the source AS class name. If there is no mapping defined, it returns a RocketAMF::Types::TypedHash with the serialized class name.



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'ext/rocketamf_ext/class_mapping.c', line 313

static VALUE mapping_get_ruby_obj(VALUE self, VALUE name) {
    CLASS_MAPPING *map;
    Data_Get_Struct(self, CLASS_MAPPING, map);

    VALUE argv[1];
    VALUE ruby_class_name = mapset_rb_lookup(map->mapset, RSTRING_PTR(name));
    if(ruby_class_name == Qnil) {
        argv[0] = name;
        return rb_class_new_instance(1, argv, cTypedHash);
    } else {
        VALUE base_const = rb_mKernel;
        char* endptr;
        char* ptr = RSTRING_PTR(ruby_class_name);
        while((endptr = strstr(ptr,"::"))) {
            endptr[0] = '\0'; // NULL terminate to make string ops work
            base_const = rb_const_get(base_const, rb_intern(ptr));
            endptr[0] = ':'; // Restore correct char
            ptr = endptr + 2;
        }
        return rb_class_new_instance(0, NULL, rb_const_get(base_const, rb_intern(ptr)));
    }
}

#populate_ruby_obj(obj, props, dynamic_props = nil) ⇒ Object

Populates the ruby object using the given properties. Property hashes MUST have symbol keys, or it will raise an exception.

Returns:

  • (Object)


385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'ext/rocketamf_ext/class_mapping.c', line 385

static VALUE mapping_populate(int argc, VALUE *argv, VALUE self) {
    // Check args
    VALUE obj, props, dynamic_props;
    rb_scan_args(argc, argv, "21", &obj, &props, &dynamic_props);

    VALUE args[2] = {self, obj};
    st_foreach(RHASH_TBL(props), mapping_populate_iter, (st_data_t)args);
    if(dynamic_props != Qnil) {
        st_foreach(RHASH_TBL(dynamic_props), mapping_populate_iter, (st_data_t)args);
    }

    return obj;
}

#props_for_serialization(obj) ⇒ Hash

Extracts all exportable properties from the given ruby object and returns them in a hash. For performance purposes, property detection is only performed once for a given class instance, and then cached for all instances of that class. IF YOU’RE ADDING AND REMOVING PROPERTIES FROM CLASS INSTANCES YOU CANNOT USE THE FAST CLASS MAPPER.

Returns:

  • (Hash)


409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'ext/rocketamf_ext/class_mapping.c', line 409

static VALUE mapping_props(VALUE self, VALUE obj) {
    CLASS_MAPPING *map;
    Data_Get_Struct(self, CLASS_MAPPING, map);

    if(TYPE(obj) == T_HASH) {
        return obj;
    }

    // Get "properties"
    VALUE props_ary;
    VALUE klass = CLASS_OF(obj);
    long i, len;
    if(!st_lookup(map->prop_cache, klass, &props_ary)) {
        props_ary = rb_ary_new();

        // Build props array
        VALUE all_methods = rb_class_public_instance_methods(0, NULL, klass);
        VALUE object_methods = rb_class_public_instance_methods(0, NULL, rb_cObject);
        VALUE possible_methods = rb_funcall(all_methods, rb_intern("-"), 1, object_methods);
        len = RARRAY_LEN(possible_methods);
        for(i = 0; i < len; i++) {
            VALUE meth = rb_obj_method(obj, RARRAY_PTR(possible_methods)[i]);
            VALUE arity = rb_funcall(meth, rb_intern("arity"), 0);
            if(FIX2INT(arity) == 0) {
                rb_ary_push(props_ary, RARRAY_PTR(possible_methods)[i]);
            }
        }

        // Store it
        st_add_direct(map->prop_cache, klass, props_ary);
    }

    // Build properties hash using list of properties
    VALUE props = rb_hash_new();
    len = RARRAY_LEN(props_ary);
    for(i = 0; i < len; i++) {
        VALUE key = RARRAY_PTR(props_ary)[i];
        ID getter = (TYPE(key) == T_STRING) ? rb_intern(RSTRING_PTR(key)) : SYM2ID(key);
        rb_hash_aset(props, key, rb_funcall(obj, getter, 0));
    }

    return props;
}