Skip to content

Commit

Permalink
Add TYPE_CONST_STRING and SIZEOF_CONST_STRING for "const char *"
Browse files Browse the repository at this point in the history
Add rb_fiddle_ prefix to conversion functions.h to keep backward
compatibility but value_to_generic() isn't safe for TYPE_CONST_STRING
and not String src. Use rb_fiddle_value_to_generic() instead.
  • Loading branch information
kou committed Jul 9, 2020
1 parent d00c167 commit 0ffcaa3
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 29 deletions.
69 changes: 53 additions & 16 deletions ext/fiddle/conversions.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <fiddle.h>

ffi_type *
int_to_ffi_type(int type)
rb_fiddle_int_to_ffi_type(int type)
{
int signed_p = 1;

Expand Down Expand Up @@ -33,66 +33,90 @@ int_to_ffi_type(int type)
return &ffi_type_float;
case TYPE_DOUBLE:
return &ffi_type_double;
case TYPE_CONST_STRING:
return &ffi_type_pointer;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
return &ffi_type_pointer;
}

ffi_type *
int_to_ffi_type(int type)
{
return rb_fiddle_int_to_ffi_type(type);
}

void
value_to_generic(int type, VALUE src, fiddle_generic * dst)
rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
{
switch (type) {
case TYPE_VOID:
break;
case TYPE_VOIDP:
dst->pointer = NUM2PTR(rb_Integer(src));
dst->pointer = NUM2PTR(rb_Integer(*src));
break;
case TYPE_CHAR:
dst->schar = (signed char)NUM2INT(src);
dst->schar = (signed char)NUM2INT(*src);
break;
case -TYPE_CHAR:
dst->uchar = (unsigned char)NUM2UINT(src);
dst->uchar = (unsigned char)NUM2UINT(*src);
break;
case TYPE_SHORT:
dst->sshort = (unsigned short)NUM2INT(src);
dst->sshort = (unsigned short)NUM2INT(*src);
break;
case -TYPE_SHORT:
dst->sshort = (signed short)NUM2UINT(src);
dst->sshort = (signed short)NUM2UINT(*src);
break;
case TYPE_INT:
dst->sint = NUM2INT(src);
dst->sint = NUM2INT(*src);
break;
case -TYPE_INT:
dst->uint = NUM2UINT(src);
dst->uint = NUM2UINT(*src);
break;
case TYPE_LONG:
dst->slong = NUM2LONG(src);
dst->slong = NUM2LONG(*src);
break;
case -TYPE_LONG:
dst->ulong = NUM2ULONG(src);
dst->ulong = NUM2ULONG(*src);
break;
#if HAVE_LONG_LONG
case TYPE_LONG_LONG:
dst->slong_long = NUM2LL(src);
dst->slong_long = NUM2LL(*src);
break;
case -TYPE_LONG_LONG:
dst->ulong_long = NUM2ULL(src);
dst->ulong_long = NUM2ULL(*src);
break;
#endif
case TYPE_FLOAT:
dst->ffloat = (float)NUM2DBL(src);
dst->ffloat = (float)NUM2DBL(*src);
break;
case TYPE_DOUBLE:
dst->ddouble = NUM2DBL(src);
dst->ddouble = NUM2DBL(*src);
break;
case TYPE_CONST_STRING:
if (NIL_P(*src)) {
dst->pointer = NULL;
}
else {
dst->pointer = rb_string_value_cstr(src);
}
break;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
}

void
value_to_generic(int type, VALUE src, fiddle_generic *dst)
{
/* src isn't safe from GC when type is TYPE_CONST_STRING and src
* isn't String. */
return rb_fiddle_value_to_generic(type, &src, dst);
}

VALUE
generic_to_value(VALUE rettype, fiddle_generic retval)
rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
{
int type = NUM2INT(rettype);
VALUE cPointer;
Expand Down Expand Up @@ -131,11 +155,24 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
return rb_float_new(retval.ffloat);
case TYPE_DOUBLE:
return rb_float_new(retval.ddouble);
case TYPE_CONST_STRING:
if (retval.pointer) {
return rb_str_new_cstr(retval.pointer);
}
else {
return Qnil;
}
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}

UNREACHABLE;
}

VALUE
generic_to_value(VALUE rettype, fiddle_generic retval)
{
return rb_fiddle_generic_to_value(rettype, retval);
}

/* vim: set noet sw=4 sts=4 */
17 changes: 13 additions & 4 deletions ext/fiddle/conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,22 @@ typedef union
void * pointer; /* ffi_type_pointer */
} fiddle_generic;

/* Deprecated. Use rb_fiddle_*() version. */
ffi_type * rb_fiddle_int_to_ffi_type(int type);
void rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst);
VALUE rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval);

/* Deprecated. Use rb_fiddle_*() version. */
ffi_type * int_to_ffi_type(int type);
void value_to_generic(int type, VALUE src, fiddle_generic * dst);
void value_to_generic(int type, VALUE src, fiddle_generic *dst);
VALUE generic_to_value(VALUE rettype, fiddle_generic retval);

#define VALUE2GENERIC(_type, _src, _dst) value_to_generic((_type), (_src), (_dst))
#define INT2FFI_TYPE(_type) int_to_ffi_type(_type)
#define GENERIC2VALUE(_type, _retval) generic_to_value((_type), (_retval))
#define VALUE2GENERIC(_type, _src, _dst) \
rb_fiddle_value_to_generic((_type), &(_src), (_dst))
#define INT2FFI_TYPE(_type) \
rb_fiddle_int_to_ffi_type(_type)
#define GENERIC2VALUE(_type, _retval) \
rb_fiddle_generic_to_value((_type), (_retval))

#if SIZEOF_VOIDP == SIZEOF_LONG
# define PTR2NUM(x) (LONG2NUM((long)(x)))
Expand Down
12 changes: 12 additions & 0 deletions ext/fiddle/fiddle.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ Init_fiddle(void)
rb_define_const(mFiddle, "TYPE_VARIADIC", INT2NUM(TYPE_VARIADIC));
#endif

/* Document-const: TYPE_CONST_STRING
*
* C type - const char* ('\0' terminated const char*)
*/
rb_define_const(mFiddle, "TYPE_CONST_STRING", INT2NUM(TYPE_CONST_STRING));

/* Document-const: TYPE_SIZE_T
*
* C type - size_t
Expand Down Expand Up @@ -435,6 +441,12 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t)));

/* Document-const: SIZEOF_CONST_STRING
*
* size of a const char*
*/
rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*)));

/* Document-const: RUBY_FREE
*
* Address of the ruby_xfree() function
Expand Down
1 change: 1 addition & 0 deletions ext/fiddle/fiddle.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
#define TYPE_FLOAT 7
#define TYPE_DOUBLE 8
#define TYPE_VARIADIC 9
#define TYPE_CONST_STRING 10

#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)

Expand Down
13 changes: 13 additions & 0 deletions ext/fiddle/function.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ function_call(int argc, VALUE argv[], VALUE self)
int n_call_args = 0;
int i;
int i_call;
VALUE converted_args = Qnil;
VALUE alloc_buffer = 0;

cfunc = rb_iv_get(self, "@ptr");
Expand Down Expand Up @@ -313,6 +314,7 @@ function_call(int argc, VALUE argv[], VALUE self)
i++, i_call++) {
VALUE arg_type;
int c_arg_type;
VALUE original_src;
VALUE src;
arg_type = RARRAY_AREF(arg_types, i_call);
c_arg_type = FIX2INT(arg_type);
Expand All @@ -327,11 +329,22 @@ function_call(int argc, VALUE argv[], VALUE self)
}
else if (cPointer != CLASS_OF(src)) {
src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
if (NIL_P(converted_args)) {
converted_args = rb_ary_new();
}
rb_ary_push(converted_args, src);
}
src = rb_Integer(src);
}

original_src = src;
VALUE2GENERIC(c_arg_type, src, &generic_args[i_call]);
if (src != original_src) {
if (NIL_P(converted_args)) {
converted_args = rb_ary_new();
}
rb_ary_push(converted_args, src);
}
args.values[i_call] = (void *)&generic_args[i_call];
}
args.values[i_call] = NULL;
Expand Down
2 changes: 2 additions & 0 deletions lib/fiddle/import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ def sizeof(ty)
return SIZEOF_DOUBLE
when TYPE_VOIDP
return SIZEOF_VOIDP
when TYPE_CONST_STRING
return SIZEOF_CONST_STRING
else
if defined?(TYPE_LONG_LONG) and
ty == TYPE_LONG_LONG
Expand Down
23 changes: 17 additions & 6 deletions test/fiddle/test_func.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_snprintf
[
TYPE_VOIDP,
TYPE_SIZE_T,
TYPE_VOIDP,
TYPE_CONST_STRING,
TYPE_VARIADIC,
],
TYPE_INT)
Expand All @@ -107,20 +107,31 @@ def test_snprintf

written = snprintf.call(output,
output.size,
"int: %d, string: %.*s\n",
"int: %d, string: %.*s, const string: %s\n",
TYPE_INT, -29,
TYPE_INT, 4,
TYPE_VOIDP, "Hello")
assert_equal("int: -29, string: Hell\n",
TYPE_VOIDP, "Hello",
TYPE_CONST_STRING, "World")
assert_equal("int: -29, string: Hell, const string: World\n",
output_buffer[0, written])

string_like_class = Class.new do
def initialize(string)
@string = string
end

def to_str
@string
end
end
written = snprintf.call(output,
output.size,
"string: %.*s, uint: %u\n",
"string: %.*s, const string: %s, uint: %u\n",
TYPE_INT, 2,
TYPE_VOIDP, "Hello",
TYPE_CONST_STRING, string_like_class.new("World"),
TYPE_INT, 29)
assert_equal("string: He, uint: 29\n",
assert_equal("string: He, const string: World, uint: 29\n",
output_buffer[0, written])
end
end
Expand Down
13 changes: 10 additions & 3 deletions test/fiddle/test_import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,17 @@ def test_sizeof()

Fiddle.constants.grep(/\ATYPE_(?!VOID|VARIADIC\z)(.*)/) do
type = $&
size = Fiddle.const_get("SIZEOF_#{$1}")
name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase
const_type_name = $1
size = Fiddle.const_get("SIZEOF_#{const_type_name}")
if const_type_name == "CONST_STRING"
name = "const_string"
type_name = "const char*"
else
name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase
type_name = name
end
define_method("test_sizeof_#{name}") do
assert_equal(size, Fiddle::Importer.sizeof(name), type)
assert_equal(size, Fiddle::Importer.sizeof(type_name), type)
end
end

Expand Down

0 comments on commit 0ffcaa3

Please sign in to comment.