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



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

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)


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

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



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

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



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

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



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

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



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

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:



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

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.



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

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)


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

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)


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
452
# File 'ext/rocketamf_ext/class_mapping.c', line 410

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;
}