/*
* Copyright (c) 2010, Wayne Meissner
*
* All rights reserved.
*
* This file is part of ruby-ffi.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work. If not, see .
*/
#include
#include
#include "rbffi.h"
#include "Type.h"
#include "MappedType.h"
static VALUE mapped_allocate(VALUE);
static VALUE mapped_initialize(VALUE, VALUE);
static void mapped_mark(MappedType *);
static ID id_native_type, id_to_native, id_from_native;
VALUE rbffi_MappedTypeClass = Qnil;
static VALUE
mapped_allocate(VALUE klass)
{
MappedType* m;
VALUE obj = Data_Make_Struct(klass, MappedType, mapped_mark, -1, m);
m->rbConverter = Qnil;
m->rbType = Qnil;
m->type = NULL;
m->base.nativeType = NATIVE_MAPPED;
m->base.ffiType = &ffi_type_void;
return obj;
}
/*
* call-seq: initialize(converter)
* @param [#native_type, #to_native, #from_native] converter +converter+ must respond to
* all these methods
* @return [self]
*/
static VALUE
mapped_initialize(VALUE self, VALUE rbConverter)
{
MappedType* m = NULL;
if (!rb_respond_to(rbConverter, id_native_type)) {
rb_raise(rb_eNoMethodError, "native_type method not implemented");
}
if (!rb_respond_to(rbConverter, id_to_native)) {
rb_raise(rb_eNoMethodError, "to_native method not implemented");
}
if (!rb_respond_to(rbConverter, id_from_native)) {
rb_raise(rb_eNoMethodError, "from_native method not implemented");
}
Data_Get_Struct(self, MappedType, m);
m->rbType = rb_funcall2(rbConverter, id_native_type, 0, NULL);
if (!(rb_obj_is_kind_of(m->rbType, rbffi_TypeClass))) {
rb_raise(rb_eTypeError, "native_type did not return instance of FFI::Type");
}
m->rbConverter = rbConverter;
Data_Get_Struct(m->rbType, Type, m->type);
m->base.ffiType = m->type->ffiType;
return self;
}
static void
mapped_mark(MappedType* m)
{
rb_gc_mark(m->rbType);
rb_gc_mark(m->rbConverter);
}
/*
* call-seq: mapped_type.native_type
* @return [Type]
* Get native type of mapped type.
*/
static VALUE
mapped_native_type(VALUE self)
{
MappedType*m = NULL;
Data_Get_Struct(self, MappedType, m);
return m->rbType;
}
/*
* call-seq: mapped_type.to_native(*args)
* @param args depends on {FFI::DataConverter} used to initialize +self+
*/
static VALUE
mapped_to_native(int argc, VALUE* argv, VALUE self)
{
MappedType*m = NULL;
Data_Get_Struct(self, MappedType, m);
return rb_funcall2(m->rbConverter, id_to_native, argc, argv);
}
/*
* call-seq: mapped_type.from_native(*args)
* @param args depends on {FFI::DataConverter} used to initialize +self+
*/
static VALUE
mapped_from_native(int argc, VALUE* argv, VALUE self)
{
MappedType*m = NULL;
Data_Get_Struct(self, MappedType, m);
return rb_funcall2(m->rbConverter, id_from_native, argc, argv);
}
void
rbffi_MappedType_Init(VALUE moduleFFI)
{
/*
* Document-class: FFI::Type::Mapped
*/
rbffi_MappedTypeClass = rb_define_class_under(rbffi_TypeClass, "Mapped", rbffi_TypeClass);
rb_global_variable(&rbffi_MappedTypeClass);
id_native_type = rb_intern("native_type");
id_to_native = rb_intern("to_native");
id_from_native = rb_intern("from_native");
rb_define_alloc_func(rbffi_MappedTypeClass, mapped_allocate);
rb_define_method(rbffi_MappedTypeClass, "initialize", mapped_initialize, 1);
rb_define_method(rbffi_MappedTypeClass, "type", mapped_native_type, 0);
rb_define_method(rbffi_MappedTypeClass, "native_type", mapped_native_type, 0);
rb_define_method(rbffi_MappedTypeClass, "to_native", mapped_to_native, -1);
rb_define_method(rbffi_MappedTypeClass, "from_native", mapped_from_native, -1);
}