Skip to content

Commit 22e6ed6

Browse files
authored
Merge pull request #46 from sue445/feature/num_round
Add RbFuncallv, RbFuncall2
2 parents 93d80ca + c2813e7 commit 22e6ed6

File tree

7 files changed

+77
-1
lines changed

7 files changed

+77
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ ref. https://docs.ruby-lang.org/ja/latest/function/index.html
216216
* [ ] `rb_free_generic_ivar`
217217
* [ ] `rb_frozen_class_p`
218218
* [ ] `rb_funcall`
219-
* [ ] `rb_funcall2`
219+
* [x] `rb_funcall2`
220220
* [ ] `rb_funcall3`
221221
* [ ] `rb_gc`
222222
* [ ] `rb_gc_call_finalizer_at_exit`

_scripts/dump_ruby_c_functions.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def snake_to_camel(str)
175175
str.split("_").map(&:capitalize).join
176176
end
177177

178+
# Cast C type to cgo type. (Used in wrapper function)
178179
# @param typename [String]
179180
# @return [String]
180181
def cast_to_cgo_type(typename)
@@ -185,13 +186,16 @@ def cast_to_cgo_type(typename)
185186
return "C.uint"
186187
when "char*"
187188
return "string2Char"
189+
when "VALUE*"
190+
return "toCValueArray"
188191
when /^VALUE\s*\(\*func\)\s*\(ANYARGS\)$/
189192
return "toFunctionPointer"
190193
end
191194

192195
"C.#{typename}"
193196
end
194197

198+
# Convert C type to Go type. (used in wrapper function args and return type)
195199
# @param typename [String]
196200
# @return [String]
197201
def ruby_c_type_to_go_type(typename)
@@ -200,6 +204,8 @@ def ruby_c_type_to_go_type(typename)
200204
return "uint"
201205
when "char*", "const char*"
202206
return "string"
207+
when "VALUE*"
208+
return "[]VALUE"
203209
when /^VALUE\s*\(\*func\)\s*\(ANYARGS\)$/
204210
return "unsafe.Pointer"
205211
when /^[A-Z]+$/, "int"

ruby-internal-eval.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package ruby
2+
3+
/*
4+
#include "ruby.h"
5+
*/
6+
import "C"
7+
8+
// c.f. https://github.com/ruby/ruby/blob/master/include/ruby/internal/eval.h
9+
10+
// RbFuncallv calls `rb_funcallv` in C
11+
//
12+
// Original definition is following
13+
//
14+
// VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
15+
func RbFuncallv(recv VALUE, mid ID, argc int, argv []VALUE) VALUE {
16+
return VALUE(C.rb_funcallv(C.VALUE(recv), C.ID(mid), C.int(argc), toCValueArray(argv)))
17+
}
18+
19+
// RbFuncall2 is alias to [RbFuncallv]
20+
func RbFuncall2(recv VALUE, mid ID, argc int, argv []VALUE) VALUE {
21+
return RbFuncallv(recv, mid, argc, argv)
22+
}

testdata/dummy/ext/dummy/dummy.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ package main
66
VALUE rb_dummy_sum(VALUE self, VALUE a, VALUE b);
77
VALUE rb_dummy_with_block(VALUE self, VALUE arg);
88
VALUE rb_dummy_hello(VALUE self, VALUE name);
9+
VALUE rb_dummy_round_num(VALUE self, VALUE num, VALUE ndigits);
10+
VALUE rb_dummy_to_string(VALUE self, VALUE source);
11+
912
VALUE rb_dummy_unit_kilobyte(VALUE self);
1013
*/
1114
import "C"
@@ -41,6 +44,22 @@ func rb_dummy_hello(_ C.VALUE, name C.VALUE) C.VALUE {
4144
return C.VALUE(ruby.String2Value(result))
4245
}
4346

47+
//export rb_dummy_round_num
48+
func rb_dummy_round_num(_ C.VALUE, num C.VALUE, ndigits C.VALUE) C.VALUE {
49+
// Call Integer#round
50+
result := ruby.RbFuncall2(ruby.VALUE(num), ruby.RbIntern("round"), 1, []ruby.VALUE{ruby.VALUE(ndigits)})
51+
52+
return C.VALUE(result)
53+
}
54+
55+
//export rb_dummy_to_string
56+
func rb_dummy_to_string(_ C.VALUE, source C.VALUE) C.VALUE {
57+
// Call Object#to_s
58+
result := ruby.RbFuncall2(ruby.VALUE(source), ruby.RbIntern("to_s"), 0, []ruby.VALUE{})
59+
60+
return C.VALUE(result)
61+
}
62+
4463
//export rb_dummy_unit_kilobyte
4564
func rb_dummy_unit_kilobyte(self C.VALUE) C.VALUE {
4665
sourceID := ruby.RbIntern("@source")
@@ -60,6 +79,8 @@ func Init_dummy() {
6079
ruby.RbDefineSingletonMethod(rb_mDummy, "sum", C.rb_dummy_sum, 2)
6180
ruby.RbDefineSingletonMethod(rb_mDummy, "with_block", C.rb_dummy_with_block, 1)
6281
ruby.RbDefineSingletonMethod(rb_mDummy, "hello", C.rb_dummy_hello, 1)
82+
ruby.RbDefineSingletonMethod(rb_mDummy, "round_num", C.rb_dummy_round_num, 2)
83+
ruby.RbDefineSingletonMethod(rb_mDummy, "to_string", C.rb_dummy_to_string, 1)
6384

6485
// Create Dummy::InnerClass class
6586
ruby.RbDefineClassUnder(rb_mDummy, "InnerClass", ruby.VALUE(C.rb_cObject))

testdata/dummy/sig/dummy.rbs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ module Dummy
1010

1111
def self.hello: (String name) -> String
1212

13+
def self.round_num: (Integer num, Integer ndigits) -> Integer
14+
15+
def self.to_string: (untyped source) -> String
16+
1317
class InnerClass
1418
end
1519

testdata/dummy/spec/dummy_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,18 @@
3333
expect(actual).to eq "Hello, sue445"
3434
end
3535
end
36+
37+
describe ".round_num" do
38+
it "works" do
39+
actual = Dummy.round_num(15, -1)
40+
expect(actual).to eq 20
41+
end
42+
end
43+
44+
describe ".to_string" do
45+
it "works" do
46+
actual = Dummy.to_string(123)
47+
expect(actual).to eq "123"
48+
end
49+
end
3650
end

wrapper.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,12 @@ func string2Value(str string) C.VALUE {
6363
func toFunctionPointer(fun unsafe.Pointer) *[0]byte {
6464
return (*[0]byte)(fun)
6565
}
66+
67+
// toCValueArray convert from `[]ruby.VALUE` to `*C.VALUE`. (for internal use within package)
68+
func toCValueArray(values []VALUE) *C.VALUE {
69+
if len(values) == 0 {
70+
return (*C.VALUE)(unsafe.Pointer(nil))
71+
}
72+
73+
return (*C.VALUE)(unsafe.Pointer(&values[0]))
74+
}

0 commit comments

Comments
 (0)