Skip to content

Commit

Permalink
Add rb_io_open_descriptor function
Browse files Browse the repository at this point in the history
  • Loading branch information
andrykonchin committed Nov 20, 2024
1 parent b5abbdc commit 6043f13
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Compatibility:
* Implement `rb_str_format()` (#3716, @andrykonchin).
* Add `IO#{pread, pwrite}` methods (#3718, @andrykonchin).
* Add `rb_io_closed_p()` (#3681, @andrykonchin).
* Add `rb_io_open_descriptor()` (#3681, @andrykonchin).

Performance:

Expand Down
2 changes: 1 addition & 1 deletion lib/cext/include/truffleruby/truffleruby-abi-version.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
// $RUBY_VERSION must be the same as TruffleRuby.LANGUAGE_VERSION.
// $ABI_NUMBER starts at 1 and is incremented for every ABI-incompatible change.

#define TRUFFLERUBY_ABI_VERSION "3.3.5.5"
#define TRUFFLERUBY_ABI_VERSION "3.3.5.6"

#endif
6 changes: 6 additions & 0 deletions lib/truffle/truffle/cext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2367,6 +2367,12 @@ def rb_io_path(io)
io.instance_variable_get(:@path)
end

def rb_io_open_descriptor(klass, fd, mode, path, timeout, internal_encoding, external_encoding, flags, options)
return klass.allocate if klass != IO and klass != File

klass.for_fd(fd, mode, **options, internal_encoding: internal_encoding, external_encoding: external_encoding, path: path, flags: flags)
end

def rb_io_closed_p(io)
io.closed?
end
Expand Down
14 changes: 14 additions & 0 deletions spec/ruby/optional/capi/ext/io_spec.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,19 @@ static VALUE io_spec_rb_io_path(VALUE self, VALUE io) {
static VALUE io_spec_rb_io_closed_p(VALUE self, VALUE io) {
return rb_io_closed_p(io);
}

static VALUE io_spec_rb_io_open_descriptor(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout, VALUE internal_encoding, VALUE external_encoding, VALUE ecflags, VALUE ecopts) {
struct rb_io_encoding *io_encoding;

io_encoding = (struct rb_io_encoding *) malloc(sizeof(struct rb_io_encoding));

io_encoding->enc = rb_to_encoding(internal_encoding);
io_encoding->enc2 = rb_to_encoding(external_encoding);
io_encoding->ecflags = FIX2INT(ecflags);
io_encoding->ecopts = ecopts;

return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, io_encoding);
}
#endif

void Init_io_spec(void) {
Expand Down Expand Up @@ -414,6 +427,7 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
rb_define_method(cls, "rb_io_closed_p", io_spec_rb_io_closed_p, 1);
rb_define_method(cls, "rb_io_open_descriptor", io_spec_rb_io_open_descriptor, 9);
#endif
}

Expand Down
64 changes: 64 additions & 0 deletions spec/ruby/optional/capi/io_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,70 @@
@r_io.closed?.should == true
end
end

describe "rb_io_open_descriptor" do
it "creates a new IO instance" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.should.is_a?(IO)
end

it "return an instance of the specified class" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.class.should == File

io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.class.should == IO
end

it "sets the specified file descriptor" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.fileno.should == @r_io.fileno
end

it "sets the specified path" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.path.should == "a.txt"
end

it "sets the specified timeout" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.timeout.should == 60
end

it "sets the specified internal encoding" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.internal_encoding.should == Encoding::US_ASCII
end

it "sets the specified external encoding" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
io.external_encoding.should == Encoding::UTF_8
end

it "ignores the IO open options" do
io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"})
io.external_encoding.should == Encoding::UTF_8

io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"})
io.internal_encoding.should == Encoding::US_ASCII

io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"})
io.external_encoding.should == Encoding::UTF_8
io.internal_encoding.should == Encoding::US_ASCII

io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false})
io.should_not.binmode?

io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true})
io.should_not.binmode?

io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false})
io.should.autoclose?

io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"})
io.path.should == "a.txt"
end
end
end

ruby_version_is "3.4" do
Expand Down
2 changes: 2 additions & 0 deletions spec/tags/optional/capi/io_tags.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
fails:C-API IO function rb_io_maybe_wait_writable raises an IOError if the IO is not initialized
fails:C-API IO function rb_io_maybe_wait_readable raises an IOError if the IO is not initialized
fails:C-API IO function rb_io_maybe_wait raises an IOError if the IO is not initialized
fails:C-API IO function rb_io_open_descriptor sets the specified timeout
fails:C-API IO function rb_io_open_descriptor ignores the IO open options
13 changes: 13 additions & 0 deletions src/main/c/cext/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ VALUE rb_io_path(VALUE io) {
return RUBY_CEXT_INVOKE("rb_io_path", io);
}

VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding) {
return RUBY_CEXT_INVOKE("rb_io_open_descriptor",
klass,
INT2FIX(descriptor),
INT2FIX(mode),
path,
timeout,
rb_enc_from_encoding(encoding->enc),
rb_enc_from_encoding(encoding->enc2),
INT2FIX(encoding->ecflags),
encoding->ecopts);
}

VALUE rb_io_closed_p(VALUE io) {
return RUBY_CEXT_INVOKE("rb_io_closed_p", io);
}
Expand Down

0 comments on commit 6043f13

Please sign in to comment.