/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */ /********************************************************************** rbgobj_value.c - $Author: ggc $ $Date: 2007/07/13 16:07:28 $ Copyright (C) 2002,2003 Masahiro Sakai **********************************************************************/ #include "rbgprivate.h" /**********************************************************************/ static ID id_to_s; static GQuark qRValueToGValueFunc; static GQuark qGValueToRValueFunc; void rbgobj_register_r2g_func(GType gtype, RValueToGValueFunc func) { g_type_set_qdata(gtype, qRValueToGValueFunc, func); } void rbgobj_register_g2r_func(GType gtype, GValueToRValueFunc func) { g_type_set_qdata(gtype, qGValueToRValueFunc, func); } /**********************************************************************/ VALUE rbgobj_gvalue_to_rvalue(const GValue* value) { GType type, fundamental_type; VALUE rvalue; if (!value) return Qnil; type = G_VALUE_TYPE(value); if (rbgobj_convert_gvalue2rvalue(type, value, &rvalue)) return rvalue; fundamental_type = G_TYPE_FUNDAMENTAL(type); switch (fundamental_type) { case G_TYPE_NONE: return Qnil; case G_TYPE_CHAR: return CHR2FIX(g_value_get_char(value)); case G_TYPE_UCHAR: return INT2FIX(g_value_get_uchar(value)); case G_TYPE_BOOLEAN: return CBOOL2RVAL(g_value_get_boolean(value)); case G_TYPE_INT: return INT2NUM(g_value_get_int(value)); case G_TYPE_UINT: return UINT2NUM(g_value_get_uint(value)); case G_TYPE_LONG: return LONG2NUM(g_value_get_long(value)); case G_TYPE_ULONG: return ULONG2NUM(g_value_get_ulong(value)); case G_TYPE_INT64: return rbglib_int64_to_num(g_value_get_int64(value)); case G_TYPE_UINT64: return rbglib_uint64_to_num(g_value_get_uint64(value)); case G_TYPE_FLOAT: return rb_float_new(g_value_get_float(value)); case G_TYPE_DOUBLE: return rb_float_new(g_value_get_double(value)); case G_TYPE_STRING: { const char* str = g_value_get_string(value); return str ? rb_str_new2(str) : Qnil; } case G_TYPE_ENUM: return rbgobj_make_enum(g_value_get_enum(value), type); case G_TYPE_FLAGS: return rbgobj_make_flags(g_value_get_flags(value), type); case G_TYPE_OBJECT: case G_TYPE_INTERFACE: { GObject* gobj = g_value_get_object(value); return gobj ? GOBJ2RVAL(gobj) : Qnil; } case G_TYPE_PARAM: { GParamSpec* pspec = g_value_get_param(value); return pspec ? rbgobj_ruby_object_from_instance(pspec) : Qnil; } case G_TYPE_POINTER: { gpointer ptr = g_value_get_pointer(value); if (!ptr) return Qnil; else return rbgobj_ptr_new(type, ptr); } case G_TYPE_BOXED: { GType gtype; for (gtype = type; gtype != G_TYPE_INVALID; gtype = g_type_parent(gtype)) { GValueToRValueFunc func = g_type_get_qdata(gtype, qGValueToRValueFunc); if (!func) continue; return func(value); } } default: if (!rbgobj_convert_gvalue2rvalue(fundamental_type, value, &rvalue)) { GValueToRValueFunc func; func = g_type_get_qdata(type, qGValueToRValueFunc); if (!func) { g_warning("rbgobj_gvalue_to_rvalue: unsupported type: %s\n", g_type_name(type)); } else { rvalue = func(value); } } return rvalue; } } void rbgobj_initialize_gvalue(GValue *result, VALUE value) { GType type; type = rbgobj_convert_rvalue2gtype(value); if (type == 0) { switch (TYPE(value)) { case T_NONE: case T_NIL: type = G_TYPE_NONE; break; case T_FLOAT: type = G_TYPE_DOUBLE; break; case T_STRING: case T_SYMBOL: type = G_TYPE_STRING; break; case T_FIXNUM: type = G_TYPE_INT; break; case T_BIGNUM: type = G_TYPE_INT64; break; case T_TRUE: case T_FALSE: type = G_TYPE_BOOLEAN; break; default: if (RVAL2CBOOL(rb_obj_is_kind_of(value, rbgobj_cEnum))) { type = G_TYPE_ENUM; } else if (RVAL2CBOOL(rb_obj_is_kind_of(value, rbgobj_cFlags))) { type = G_TYPE_FLAGS; } else if (RVAL2CBOOL(rb_obj_is_kind_of(value, rbgobj_cBoxed))) { type = G_TYPE_BOXED; } else if (RVAL2CBOOL(rb_obj_is_kind_of(value, rbgobj_cParam))) { type = G_TYPE_PARAM; } else if (RVAL2CBOOL(rb_obj_is_kind_of(value, rbgobj_cObject))) { type = G_TYPE_OBJECT; } else if (RVAL2CBOOL(rb_obj_is_kind_of(value, rbgobj_mInterface))) { /* should use rbgobj_mMetaInterface? */ type = G_TYPE_INTERFACE; } else { VALUE inspected_value; inspected_value = rb_funcall(value, rb_intern("inspect"), 0); rb_raise(rb_eArgError, "unsupported value type: %s", RSTRING_PTR(inspected_value)); } break; } } g_value_init(result, type); rbgobj_rvalue_to_gvalue(value, result); } void rbgobj_rvalue_to_gvalue(VALUE val, GValue* result) { GType type, fundamental_type; type = G_VALUE_TYPE(result); if (rbgobj_convert_rvalue2gvalue(type, val, result)) return; fundamental_type = G_TYPE_FUNDAMENTAL(type); switch (fundamental_type) { case G_TYPE_NONE: return; case G_TYPE_CHAR: g_value_set_char(result, NUM2INT(val)); return; case G_TYPE_UCHAR: g_value_set_uchar(result, NUM2UINT(val)); return; case G_TYPE_BOOLEAN: g_value_set_boolean(result, RVAL2CBOOL(val)); return; case G_TYPE_INT: g_value_set_int(result, NUM2INT(val)); return; case G_TYPE_UINT: g_value_set_uint(result, NUM2UINT(val)); return; case G_TYPE_LONG: g_value_set_long(result, NUM2LONG(val)); return; case G_TYPE_ULONG: g_value_set_ulong(result, NUM2ULONG(val)); return; case G_TYPE_INT64: g_value_set_int64(result, rbglib_num_to_int64(val)); return; case G_TYPE_UINT64: g_value_set_uint64(result, rbglib_num_to_uint64(val)); return; case G_TYPE_ENUM: g_value_set_enum(result, rbgobj_get_enum(val, G_VALUE_TYPE(result))); return; case G_TYPE_FLAGS: g_value_set_flags(result, rbgobj_get_flags(val, G_VALUE_TYPE(result))); return; case G_TYPE_FLOAT: g_value_set_float(result, NUM2DBL(val)); return; case G_TYPE_DOUBLE: g_value_set_double(result, NUM2DBL(val)); return; case G_TYPE_STRING: { if (SYMBOL_P(val)) val = rb_funcall(val, id_to_s, 0); g_value_set_string(result, NIL_P(val) ? NULL : StringValuePtr(val)); return; } case G_TYPE_OBJECT: case G_TYPE_INTERFACE: g_value_set_object(result, NIL_P(val) ? NULL : RVAL2GOBJ(val)); return; case G_TYPE_PARAM: g_value_set_param(result, NIL_P(val) ? NULL : RVAL2GOBJ(val)); return; case G_TYPE_POINTER: g_value_set_pointer(result, NIL_P(val) ? NULL : rbgobj_ptr2cptr(val)); return; case G_TYPE_BOXED: { GType gtype; for (gtype = type; gtype != G_TYPE_INVALID; gtype = g_type_parent(gtype)) { RValueToGValueFunc func = g_type_get_qdata(gtype, qRValueToGValueFunc); if (!func) continue; func(val, result); return; } } default: if (!rbgobj_convert_rvalue2gvalue(fundamental_type, val, result)) { RValueToGValueFunc func = g_type_get_qdata(type, qRValueToGValueFunc); if (!func){ g_warning("rbgobj_rvalue_to_gvalue: unsupported type: %s\n", g_type_name(type)); } else { func(val, result); } } } } /**********************************************************************/ void rbgobj_gc_mark_gvalue(GValue* value) { GType gtype = G_VALUE_TYPE(value); /* FIXME */ if (G_TYPE_FUNDAMENTAL(gtype) == G_TYPE_OBJECT) rbgobj_gc_mark_instance(g_value_get_object(value)); } /**********************************************************************/ void Init_gobject_gvalue() { id_to_s = rb_intern("to_s"); qRValueToGValueFunc = g_quark_from_static_string("__ruby_r2g_func__"); qGValueToRValueFunc = g_quark_from_static_string("__ruby_g2r_func__"); }