14#include "internal/array.h"
15#include "internal/bits.h"
16#include "internal/error.h"
17#include "internal/numeric.h"
18#include "internal/string.h"
19#include "internal/thread.h"
22VALUE rb_eIOBufferLockedError;
23VALUE rb_eIOBufferAllocationError;
24VALUE rb_eIOBufferAccessError;
25VALUE rb_eIOBufferInvalidatedError;
26VALUE rb_eIOBufferMaskError;
28size_t RUBY_IO_BUFFER_PAGE_SIZE;
29size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
40 enum rb_io_buffer_flags flags;
50io_buffer_map_memory(
size_t size,
int flags)
53 void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
59 int mmap_flags = MAP_ANONYMOUS;
60 if (flags & RB_IO_BUFFER_SHARED) {
61 mmap_flags |= MAP_SHARED;
63 mmap_flags |= MAP_PRIVATE;
66 void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
68 if (base == MAP_FAILED) {
77io_buffer_map_file(
struct rb_io_buffer *data,
int descriptor,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
80 HANDLE file = (HANDLE)_get_osfhandle(descriptor);
81 if (!file)
rb_sys_fail(
"io_buffer_map_descriptor:_get_osfhandle");
83 DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
85 if (flags & RB_IO_BUFFER_READONLY) {
86 data->flags |= RB_IO_BUFFER_READONLY;
89 protect = PAGE_READWRITE;
90 access = FILE_MAP_WRITE;
93 HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
94 if (!mapping)
rb_sys_fail(
"io_buffer_map_descriptor:CreateFileMapping");
96 if (flags & RB_IO_BUFFER_PRIVATE) {
97 access |= FILE_MAP_COPY;
98 data->flags |= RB_IO_BUFFER_PRIVATE;
102 data->flags |= RB_IO_BUFFER_EXTERNAL;
103 data->flags |= RB_IO_BUFFER_SHARED;
106 void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
109 CloseHandle(mapping);
113 data->mapping = mapping;
115 int protect = PROT_READ, access = 0;
117 if (flags & RB_IO_BUFFER_READONLY) {
118 data->flags |= RB_IO_BUFFER_READONLY;
121 protect |= PROT_WRITE;
124 if (flags & RB_IO_BUFFER_PRIVATE) {
125 data->flags |= RB_IO_BUFFER_PRIVATE;
129 data->flags |= RB_IO_BUFFER_EXTERNAL;
130 data->flags |= RB_IO_BUFFER_SHARED;
131 access |= MAP_SHARED;
134 void *base = mmap(NULL, size, protect, access, descriptor, offset);
136 if (base == MAP_FAILED) {
144 data->flags |= RB_IO_BUFFER_MAPPED;
148io_buffer_unmap(
void* base,
size_t size)
151 VirtualFree(base, 0, MEM_RELEASE);
158io_buffer_experimental(
void)
160 static int warned = 0;
168 "IO::Buffer is experimental and both the Ruby and C interface may change in the future!"
179 data->mapping = NULL;
185io_buffer_initialize(
struct rb_io_buffer *data,
void *base,
size_t size,
enum rb_io_buffer_flags flags,
VALUE source)
192 if (flags & RB_IO_BUFFER_INTERNAL) {
193 base = calloc(size, 1);
195 else if (flags & RB_IO_BUFFER_MAPPED) {
196 base = io_buffer_map_memory(size, flags);
200 rb_raise(rb_eIOBufferAllocationError,
"Could not allocate buffer!");
211 data->source = source;
218 if (data->flags & RB_IO_BUFFER_INTERNAL) {
222 if (data->flags & RB_IO_BUFFER_MAPPED) {
223 io_buffer_unmap(data->base, data->size);
236 CloseHandle(data->mapping);
237 data->mapping = NULL;
251rb_io_buffer_type_mark(
void *_data)
254 rb_gc_mark(data->source);
258rb_io_buffer_type_free(
void *_data)
262 io_buffer_free(data);
268rb_io_buffer_type_size(
const void *_data)
283 .dmark = rb_io_buffer_type_mark,
284 .dfree = rb_io_buffer_type_free,
285 .dsize = rb_io_buffer_type_size,
288 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
292rb_io_buffer_type_allocate(
VALUE self)
297 io_buffer_zero(data);
303io_buffer_for_make_instance(
VALUE klass,
VALUE string)
305 VALUE instance = rb_io_buffer_type_allocate(klass);
310 enum rb_io_buffer_flags flags = RB_IO_BUFFER_EXTERNAL;
312 if (RB_OBJ_FROZEN(
string))
313 flags |= RB_IO_BUFFER_READONLY;
315 io_buffer_initialize(data, RSTRING_PTR(
string), RSTRING_LEN(
string), flags,
string);
327io_buffer_for_yield_instance(
VALUE _arguments)
333 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string);
335 return rb_yield(arguments->instance);
339io_buffer_for_yield_instance_ensure(
VALUE _arguments)
343 if (arguments->instance !=
Qnil) {
344 rb_io_buffer_free(arguments->instance);
388rb_io_buffer_type_for(
VALUE klass,
VALUE string)
401 return rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
405 string = rb_str_tmp_frozen_acquire(
string);
406 return io_buffer_for_make_instance(klass,
string);
411rb_io_buffer_new(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
413 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
418 io_buffer_initialize(data, base, size, flags,
Qnil);
424rb_io_buffer_map(
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
426 io_buffer_experimental();
428 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
435 io_buffer_map_file(data, descriptor, size, offset, flags);
480io_buffer_map(
int argc,
VALUE *argv,
VALUE klass)
482 rb_check_arity(argc, 1, 4);
488 if (argc >= 2 && !RB_NIL_P(argv[1])) {
492 rb_off_t file_size = rb_file_size(io);
499 else if ((uintmax_t)file_size > SIZE_MAX) {
504 size = (size_t)file_size;
513 enum rb_io_buffer_flags flags = 0;
515 flags = RB_NUM2UINT(argv[3]);
518 return rb_io_buffer_map(io, size, offset, flags);
522static inline enum rb_io_buffer_flags
523io_flags_for_size(
size_t size)
525 if (size >= RUBY_IO_BUFFER_PAGE_SIZE) {
526 return RB_IO_BUFFER_MAPPED;
529 return RB_IO_BUFFER_INTERNAL;
559rb_io_buffer_initialize(
int argc,
VALUE *argv,
VALUE self)
561 io_buffer_experimental();
563 rb_check_arity(argc, 0, 2);
574 size = RUBY_IO_BUFFER_DEFAULT_SIZE;
577 enum rb_io_buffer_flags flags = 0;
579 flags = RB_NUM2UINT(argv[1]);
582 flags |= io_flags_for_size(size);
585 io_buffer_initialize(data, NULL, size, flags,
Qnil);
591io_buffer_validate_slice(
VALUE source,
void *base,
size_t size)
593 void *source_base = NULL;
594 size_t source_size = 0;
600 rb_io_buffer_get_bytes(source, &source_base, &source_size);
604 if (source_base == NULL)
return 0;
607 if (base < source_base)
return 0;
609 const void *source_end = (
char*)source_base + source_size;
610 const void *end = (
char*)base + size;
613 if (end > source_end)
return 0;
622 if (data->source !=
Qnil) {
624 return io_buffer_validate_slice(data->source, data->base, data->size);
641rb_io_buffer_to_s(
VALUE self)
649 rb_str_catf(result,
" %p+%"PRIdSIZE, data->base, data->size);
651 if (data->base == NULL) {
655 if (data->flags & RB_IO_BUFFER_EXTERNAL) {
659 if (data->flags & RB_IO_BUFFER_INTERNAL) {
663 if (data->flags & RB_IO_BUFFER_MAPPED) {
667 if (data->flags & RB_IO_BUFFER_SHARED) {
671 if (data->flags & RB_IO_BUFFER_LOCKED) {
675 if (data->flags & RB_IO_BUFFER_READONLY) {
679 if (data->source !=
Qnil) {
683 if (!io_buffer_validate(data)) {
691io_buffer_hexdump(
VALUE string,
size_t width,
char *base,
size_t size,
int first)
693 char *text = alloca(width+1);
696 for (
size_t offset = 0; offset < size; offset += width) {
697 memset(text,
'\0', width);
703 rb_str_catf(
string,
"\n0x%08" PRIxSIZE
" ", offset);
706 for (
size_t i = 0; i < width; i += 1) {
707 if (offset+i < size) {
708 unsigned char value = ((
unsigned char*)base)[offset+i];
710 if (value < 127 && isprint(value)) {
711 text[i] = (char)value;
731rb_io_buffer_hexdump(
VALUE self)
738 if (io_buffer_validate(data) && data->base) {
741 io_buffer_hexdump(result, 16, data->base, data->size, 1);
748rb_io_buffer_inspect(
VALUE self)
753 VALUE result = rb_io_buffer_to_s(self);
755 if (io_buffer_validate(data)) {
757 if (data->size <= 256) {
758 io_buffer_hexdump(result, 16, data->base, data->size, 0);
772rb_io_buffer_size(
VALUE self)
789rb_io_buffer_valid_p(
VALUE self)
794 return RBOOL(io_buffer_validate(data));
804rb_io_buffer_null_p(
VALUE self)
809 return RBOOL(data->base == NULL);
820rb_io_buffer_empty_p(
VALUE self)
825 return RBOOL(data->size == 0);
840rb_io_buffer_external_p(
VALUE self)
845 return RBOOL(data->flags & RB_IO_BUFFER_EXTERNAL);
865rb_io_buffer_internal_p(
VALUE self)
870 return RBOOL(data->flags & RB_IO_BUFFER_INTERNAL);
887rb_io_buffer_mapped_p(
VALUE self)
892 return RBOOL(data->flags & RB_IO_BUFFER_MAPPED);
903rb_io_buffer_shared_p(
VALUE self)
908 return RBOOL(data->flags & RB_IO_BUFFER_SHARED);
928rb_io_buffer_locked_p(
VALUE self)
933 return RBOOL(data->flags & RB_IO_BUFFER_LOCKED);
937rb_io_buffer_readonly_p(
VALUE self)
942 return data->flags & RB_IO_BUFFER_READONLY;
954io_buffer_readonly_p(
VALUE self)
956 return RBOOL(rb_io_buffer_readonly_p(self));
960rb_io_buffer_lock(
VALUE self)
965 if (data->flags & RB_IO_BUFFER_LOCKED) {
966 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
969 data->flags |= RB_IO_BUFFER_LOCKED;
975rb_io_buffer_unlock(
VALUE self)
980 if (!(data->flags & RB_IO_BUFFER_LOCKED)) {
981 rb_raise(rb_eIOBufferLockedError,
"Buffer not locked!");
984 data->flags &= ~RB_IO_BUFFER_LOCKED;
990rb_io_buffer_try_unlock(
VALUE self)
995 if (data->flags & RB_IO_BUFFER_LOCKED) {
996 data->flags &= ~RB_IO_BUFFER_LOCKED;
1036rb_io_buffer_locked(
VALUE self)
1041 if (data->flags & RB_IO_BUFFER_LOCKED) {
1042 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1045 data->flags |= RB_IO_BUFFER_LOCKED;
1049 data->flags &= ~RB_IO_BUFFER_LOCKED;
1082rb_io_buffer_free(
VALUE self)
1087 if (data->flags & RB_IO_BUFFER_LOCKED) {
1088 rb_raise(rb_eIOBufferLockedError,
"Buffer is locked!");
1091 io_buffer_free(data);
1099io_buffer_validate_range(
struct rb_io_buffer *data,
size_t offset,
size_t length)
1101 if (offset + length > data->size) {
1107rb_io_buffer_slice(
struct rb_io_buffer *data,
VALUE self,
size_t offset,
size_t length)
1109 io_buffer_validate_range(data, offset, length);
1115 slice->base = (
char*)data->base + offset;
1116 slice->size = length;
1119 if (data->source !=
Qnil)
1120 slice->source = data->source;
1122 slice->source = self;
1184io_buffer_slice(
int argc,
VALUE *argv,
VALUE self)
1186 rb_check_arity(argc, 0, 2);
1191 size_t offset = 0, length = 0;
1194 if (rb_int_negative_p(argv[0])) {
1202 if (rb_int_negative_p(argv[1])) {
1208 length = data->size - offset;
1211 return rb_io_buffer_slice(data, self, offset, length);
1215rb_io_buffer_get_bytes(
VALUE self,
void **base,
size_t *size)
1220 if (io_buffer_validate(data)) {
1236io_buffer_get_bytes_for_writing(
struct rb_io_buffer *data,
void **base,
size_t *size)
1238 if (data->flags & RB_IO_BUFFER_READONLY) {
1239 rb_raise(rb_eIOBufferAccessError,
"Buffer is not writable!");
1242 if (!io_buffer_validate(data)) {
1243 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
1253 rb_raise(rb_eIOBufferAllocationError,
"The buffer is not allocated!");
1257rb_io_buffer_get_bytes_for_writing(
VALUE self,
void **base,
size_t *size)
1262 io_buffer_get_bytes_for_writing(data, base, size);
1266io_buffer_get_bytes_for_reading(
struct rb_io_buffer *data,
const void **base,
size_t *size)
1268 if (!io_buffer_validate(data)) {
1269 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
1279 rb_raise(rb_eIOBufferAllocationError,
"The buffer is not allocated!");
1283rb_io_buffer_get_bytes_for_reading(
VALUE self,
const void **base,
size_t *size)
1288 io_buffer_get_bytes_for_reading(data, base, size);
1311rb_io_buffer_transfer(
VALUE self)
1316 if (data->flags & RB_IO_BUFFER_LOCKED) {
1317 rb_raise(rb_eIOBufferLockedError,
"Cannot transfer ownership of locked buffer!");
1324 *transferred = *data;
1325 io_buffer_zero(data);
1331io_buffer_resize_clear(
struct rb_io_buffer *data,
void* base,
size_t size)
1333 if (size > data->size) {
1334 memset((
unsigned char*)base+data->size, 0, size - data->size);
1339io_buffer_resize_copy(
struct rb_io_buffer *data,
size_t size)
1343 io_buffer_initialize(&resized, NULL, size, io_flags_for_size(size),
Qnil);
1346 size_t preserve = data->size;
1347 if (preserve > size) preserve = size;
1348 memcpy(resized.base, data->base, preserve);
1350 io_buffer_resize_clear(data, resized.base, size);
1353 io_buffer_free(data);
1358rb_io_buffer_resize(
VALUE self,
size_t size)
1363 if (data->flags & RB_IO_BUFFER_LOCKED) {
1364 rb_raise(rb_eIOBufferLockedError,
"Cannot resize locked buffer!");
1367 if (data->base == NULL) {
1368 io_buffer_initialize(data, NULL, size, io_flags_for_size(size),
Qnil);
1372 if (data->flags & RB_IO_BUFFER_EXTERNAL) {
1373 rb_raise(rb_eIOBufferAccessError,
"Cannot resize external buffer!");
1376#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
1377 if (data->flags & RB_IO_BUFFER_MAPPED) {
1378 void *base = mremap(data->base, data->size, size, MREMAP_MAYMOVE);
1380 if (base == MAP_FAILED) {
1384 io_buffer_resize_clear(data, base, size);
1393 if (data->flags & RB_IO_BUFFER_INTERNAL) {
1394 void *base = realloc(data->base, size);
1400 io_buffer_resize_clear(data, base, size);
1408 io_buffer_resize_copy(data, size);
1432 rb_io_buffer_resize(self,
NUM2SIZET(size));
1446 const void *ptr1, *ptr2;
1447 size_t size1, size2;
1449 rb_io_buffer_get_bytes_for_reading(self, &ptr1, &size1);
1450 rb_io_buffer_get_bytes_for_reading(other, &ptr2, &size2);
1452 if (size1 < size2) {
1456 if (size1 > size2) {
1460 return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
1464io_buffer_validate_type(
size_t size,
size_t offset)
1466 if (offset > size) {
1467 rb_raise(
rb_eArgError,
"Type extends beyond end of buffer! (offset=%"PRIdSIZE
" > size=%"PRIdSIZE
")", offset, size);
1489#define ruby_swap8(value) value
1497ruby_swapf32(
float value)
1499 union swapf32 swap = {.value = value};
1500 swap.integral = ruby_swap32(swap.integral);
1510ruby_swapf64(
double value)
1512 union swapf64 swap = {.value = value};
1513 swap.integral = ruby_swap64(swap.integral);
1517#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
1518static ID RB_IO_BUFFER_DATA_TYPE_##name; \
1521io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
1523 io_buffer_validate_type(size, *offset + sizeof(type)); \
1525 memcpy(&value, (char*)base + *offset, sizeof(type)); \
1526 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
1527 *offset += sizeof(type); \
1528 return wrap(value); \
1532io_buffer_write_##name(const void* base, size_t size, size_t *offset, VALUE _value) \
1534 io_buffer_validate_type(size, *offset + sizeof(type)); \
1535 type value = unwrap(_value); \
1536 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
1537 memcpy((char*)base + *offset, &value, sizeof(type)); \
1538 *offset += sizeof(type); \
1542 RB_IO_BUFFER_DATA_TYPE_##name##_SIZE = sizeof(type) \
1545IO_BUFFER_DECLARE_TYPE(U8, uint8_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_UINT2NUM, RB_NUM2UINT, ruby_swap8)
1548IO_BUFFER_DECLARE_TYPE(u16, uint16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_UINT2NUM, RB_NUM2UINT, ruby_swap16)
1549IO_BUFFER_DECLARE_TYPE(U16, uint16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_UINT2NUM, RB_NUM2UINT, ruby_swap16)
1550IO_BUFFER_DECLARE_TYPE(s16, int16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
1551IO_BUFFER_DECLARE_TYPE(S16, int16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
1553IO_BUFFER_DECLARE_TYPE(u32, uint32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_UINT2NUM, RB_NUM2UINT, ruby_swap32)
1554IO_BUFFER_DECLARE_TYPE(U32, uint32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_UINT2NUM, RB_NUM2UINT, ruby_swap32)
1555IO_BUFFER_DECLARE_TYPE(s32, int32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
1556IO_BUFFER_DECLARE_TYPE(S32, int32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
1558IO_BUFFER_DECLARE_TYPE(u64, uint64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
1559IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
1560IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
1561IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
1563IO_BUFFER_DECLARE_TYPE(f32,
float, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
1564IO_BUFFER_DECLARE_TYPE(F32,
float, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
1565IO_BUFFER_DECLARE_TYPE(f64,
double, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
1566IO_BUFFER_DECLARE_TYPE(F64,
double, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
1567#undef IO_BUFFER_DECLARE_TYPE
1570io_buffer_data_type_size(
ID data_type)
1572#define IO_BUFFER_DATA_TYPE_SIZE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
1573 IO_BUFFER_DATA_TYPE_SIZE(U8)
1574 IO_BUFFER_DATA_TYPE_SIZE(S8)
1575 IO_BUFFER_DATA_TYPE_SIZE(u16)
1576 IO_BUFFER_DATA_TYPE_SIZE(U16)
1577 IO_BUFFER_DATA_TYPE_SIZE(s16)
1578 IO_BUFFER_DATA_TYPE_SIZE(S16)
1579 IO_BUFFER_DATA_TYPE_SIZE(u32)
1580 IO_BUFFER_DATA_TYPE_SIZE(U32)
1581 IO_BUFFER_DATA_TYPE_SIZE(s32)
1582 IO_BUFFER_DATA_TYPE_SIZE(S32)
1583 IO_BUFFER_DATA_TYPE_SIZE(u64)
1584 IO_BUFFER_DATA_TYPE_SIZE(U64)
1585 IO_BUFFER_DATA_TYPE_SIZE(s64)
1586 IO_BUFFER_DATA_TYPE_SIZE(S64)
1587 IO_BUFFER_DATA_TYPE_SIZE(f32)
1588 IO_BUFFER_DATA_TYPE_SIZE(F32)
1589 IO_BUFFER_DATA_TYPE_SIZE(f64)
1590 IO_BUFFER_DATA_TYPE_SIZE(F64)
1591#undef IO_BUFFER_DATA_TYPE_SIZE
1609io_buffer_size_of(
VALUE klass,
VALUE data_type)
1611 if (RB_TYPE_P(data_type,
T_ARRAY)) {
1613 for (
long i = 0; i <
RARRAY_LEN(data_type); i++) {
1623rb_io_buffer_get_value(
const void* base,
size_t size,
ID data_type,
size_t *offset)
1625#define IO_BUFFER_GET_VALUE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
1626 IO_BUFFER_GET_VALUE(U8)
1627 IO_BUFFER_GET_VALUE(S8)
1629 IO_BUFFER_GET_VALUE(u16)
1630 IO_BUFFER_GET_VALUE(U16)
1631 IO_BUFFER_GET_VALUE(s16)
1632 IO_BUFFER_GET_VALUE(S16)
1634 IO_BUFFER_GET_VALUE(u32)
1635 IO_BUFFER_GET_VALUE(U32)
1636 IO_BUFFER_GET_VALUE(s32)
1637 IO_BUFFER_GET_VALUE(S32)
1639 IO_BUFFER_GET_VALUE(u64)
1640 IO_BUFFER_GET_VALUE(U64)
1641 IO_BUFFER_GET_VALUE(s64)
1642 IO_BUFFER_GET_VALUE(S64)
1644 IO_BUFFER_GET_VALUE(f32)
1645 IO_BUFFER_GET_VALUE(F32)
1646 IO_BUFFER_GET_VALUE(f64)
1647 IO_BUFFER_GET_VALUE(F64)
1648#undef IO_BUFFER_GET_VALUE
1696 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
1698 return rb_io_buffer_get_value(base, size,
RB_SYM2ID(
type), &offset);
1720 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
1722 if (!RB_TYPE_P(data_types,
T_ARRAY)) {
1728 for (
long i = 0; i <
RARRAY_LEN(data_types); i++) {
1729 VALUE type = rb_ary_entry(data_types, i);
1731 rb_ary_push(array, value);
1756io_buffer_each(
int argc,
VALUE *argv,
VALUE self)
1763 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
1769 data_type = RB_IO_BUFFER_DATA_TYPE_U8;
1783 count = (size - offset) / io_buffer_data_type_size(data_type);
1786 for (
size_t i = 0; i < count; i++) {
1787 size_t current_offset = offset;
1788 VALUE value = rb_io_buffer_get_value(base, size, data_type, &offset);
1789 rb_yield_values(2,
SIZET2NUM(current_offset), value);
1808io_buffer_values(
int argc,
VALUE *argv,
VALUE self)
1813 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
1819 data_type = RB_IO_BUFFER_DATA_TYPE_U8;
1833 count = (size - offset) / io_buffer_data_type_size(data_type);
1836 VALUE array = rb_ary_new_capa(count);
1838 for (
size_t i = 0; i < count; i++) {
1839 VALUE value = rb_io_buffer_get_value(base, size, data_type, &offset);
1840 rb_ary_push(array, value);
1864io_buffer_each_byte(
int argc,
VALUE *argv,
VALUE self)
1871 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
1884 count = (size - offset);
1887 for (
size_t i = 0; i < count; i++) {
1888 unsigned char *value = (
unsigned char *)base + i + offset;
1896rb_io_buffer_set_value(
const void* base,
size_t size,
ID data_type,
size_t *offset,
VALUE value)
1898#define IO_BUFFER_SET_VALUE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(base, size, offset, value); return;}
1899 IO_BUFFER_SET_VALUE(U8);
1900 IO_BUFFER_SET_VALUE(S8);
1902 IO_BUFFER_SET_VALUE(u16);
1903 IO_BUFFER_SET_VALUE(U16);
1904 IO_BUFFER_SET_VALUE(s16);
1905 IO_BUFFER_SET_VALUE(S16);
1907 IO_BUFFER_SET_VALUE(u32);
1908 IO_BUFFER_SET_VALUE(U32);
1909 IO_BUFFER_SET_VALUE(s32);
1910 IO_BUFFER_SET_VALUE(S32);
1912 IO_BUFFER_SET_VALUE(u64);
1913 IO_BUFFER_SET_VALUE(U64);
1914 IO_BUFFER_SET_VALUE(s64);
1915 IO_BUFFER_SET_VALUE(S64);
1917 IO_BUFFER_SET_VALUE(f32);
1918 IO_BUFFER_SET_VALUE(F32);
1919 IO_BUFFER_SET_VALUE(f64);
1920 IO_BUFFER_SET_VALUE(F64);
1921#undef IO_BUFFER_SET_VALUE
1963 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
1965 rb_io_buffer_set_value(base, size,
RB_SYM2ID(
type), &offset, value);
1989 if (!RB_TYPE_P(data_types,
T_ARRAY)) {
1993 if (!RB_TYPE_P(values,
T_ARRAY)) {
2005 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
2007 for (
long i = 0; i <
RARRAY_LEN(data_types); i++) {
2008 VALUE type = rb_ary_entry(data_types, i);
2009 VALUE value = rb_ary_entry(values, i);
2010 rb_io_buffer_set_value(base, size,
RB_SYM2ID(
type), &offset, value);
2017io_buffer_memcpy(
struct rb_io_buffer *data,
size_t offset,
const void *source_base,
size_t source_offset,
size_t source_size,
size_t length)
2021 io_buffer_get_bytes_for_writing(data, &base, &size);
2023 io_buffer_validate_range(data, offset, length);
2025 if (source_offset + length > source_size) {
2029 memcpy((
unsigned char*)base+offset, (
unsigned char*)source_base+source_offset, length);
2034io_buffer_copy_from(
struct rb_io_buffer *data,
const void *source_base,
size_t source_size,
int argc,
VALUE *argv)
2038 size_t source_offset;
2052 if (source_offset > source_size) {
2061 if (argc >= 2 && !RB_NIL_P(argv[1])) {
2066 length = source_size - source_offset;
2069 io_buffer_memcpy(data, offset, source_base, source_offset, source_size, length);
2092rb_io_buffer_initialize_copy(
VALUE self,
VALUE source)
2097 const void *source_base;
2100 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2102 io_buffer_initialize(data, NULL, source_size, io_flags_for_size(source_size),
Qnil);
2104 return io_buffer_copy_from(data, source_base, source_size, 0, NULL);
2162io_buffer_copy(
int argc,
VALUE *argv,
VALUE self)
2164 rb_check_arity(argc, 1, 4);
2169 VALUE source = argv[0];
2170 const void *source_base;
2173 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2175 return io_buffer_copy_from(data, source_base, source_size, argc-1, argv+1);
2193io_buffer_get_string(
int argc,
VALUE *argv,
VALUE self)
2195 rb_check_arity(argc, 0, 3);
2202 io_buffer_get_bytes_for_reading(data, &base, &size);
2205 size_t length = size;
2212 if (argc >= 2 && !RB_NIL_P(argv[1])) {
2216 length = size - offset;
2220 encoding = rb_find_encoding(argv[2]);
2223 io_buffer_validate_range(data, offset, length);
2225 return rb_enc_str_new((
const char*)base + offset, length, encoding);
2252io_buffer_set_string(
int argc,
VALUE *argv,
VALUE self)
2254 rb_check_arity(argc, 1, 4);
2261 const void *source_base = RSTRING_PTR(
string);
2262 size_t source_size = RSTRING_LEN(
string);
2264 return io_buffer_copy_from(data, source_base, source_size, argc-1, argv+1);
2268rb_io_buffer_clear(
VALUE self, uint8_t value,
size_t offset,
size_t length)
2273 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
2275 if (offset + length > size) {
2279 memset((
char*)base + offset, value, length);
2314io_buffer_clear(
int argc,
VALUE *argv,
VALUE self)
2316 rb_check_arity(argc, 0, 3);
2336 length = data->size - offset;
2339 rb_io_buffer_clear(self, value, offset, length);
2345io_buffer_default_size(
size_t page_size)
2348 const size_t platform_agnostic_default_size = 64*1024;
2351 const char *default_size = getenv(
"RUBY_IO_BUFFER_DEFAULT_SIZE");
2354 int value = atoi(default_size);
2362 if (platform_agnostic_default_size < page_size) {
2366 return platform_agnostic_default_size;
2376io_buffer_read_internal(
void *_argument)
2379 ssize_t result = read(argument->descriptor, argument->base, argument->size);
2384rb_io_buffer_read(
VALUE self,
VALUE io,
size_t length,
size_t offset)
2387 if (scheduler !=
Qnil) {
2390 if (!UNDEF_P(result)) {
2398 io_buffer_validate_range(data, offset, length);
2404 io_buffer_get_bytes_for_writing(data, &base, &size);
2406 base = (
unsigned char*)base + offset;
2409 .descriptor = descriptor,
2414 return rb_thread_io_blocking_region(io_buffer_read_internal, &argument, descriptor);
2444io_buffer_read(
int argc,
VALUE *argv,
VALUE self)
2446 rb_check_arity(argc, 2, 3);
2452 if (rb_int_negative_p(argv[1])) {
2461 if (rb_int_negative_p(argv[2])) {
2468 return rb_io_buffer_read(self, io, length, offset);
2479io_buffer_pread_internal(
void *_argument)
2483#if defined(HAVE_PREAD)
2484 ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
2487 rb_off_t offset = lseek(argument->descriptor, 0, SEEK_CUR);
2488 if (offset == (rb_off_t)-1)
2491 if (lseek(argument->descriptor, argument->offset, SEEK_SET) == (rb_off_t)-1)
2494 ssize_t result = read(argument->descriptor, argument->base, argument->size);
2496 if (lseek(argument->descriptor, offset, SEEK_SET) == (rb_off_t)-1)
2504rb_io_buffer_pread(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
2507 if (scheduler !=
Qnil) {
2510 if (!UNDEF_P(result)) {
2518 io_buffer_validate_range(data, offset, length);
2524 io_buffer_get_bytes_for_writing(data, &base, &size);
2527 .descriptor = descriptor,
2530 .base = (
unsigned char*)base + offset,
2539 return rb_thread_io_blocking_region(io_buffer_pread_internal, &argument, descriptor);
2569io_buffer_pread(
int argc,
VALUE *argv,
VALUE self)
2571 rb_check_arity(argc, 3, 4);
2577 if (rb_int_negative_p(argv[2])) {
2584 if (rb_int_negative_p(argv[3])) {
2591 return rb_io_buffer_pread(self, io, from, length, offset);
2601io_buffer_write_internal(
void *_argument)
2604 ssize_t result = write(argument->descriptor, argument->base, argument->size);
2609rb_io_buffer_write(
VALUE self,
VALUE io,
size_t length,
size_t offset)
2612 if (scheduler !=
Qnil) {
2615 if (!UNDEF_P(result)) {
2623 io_buffer_validate_range(data, offset, length);
2629 io_buffer_get_bytes_for_reading(data, &base, &size);
2631 base = (
unsigned char *)base + offset;
2634 .descriptor = descriptor,
2639 return rb_thread_io_blocking_region(io_buffer_write_internal, &argument, descriptor);
2657io_buffer_write(
int argc,
VALUE *argv,
VALUE self)
2659 rb_check_arity(argc, 2, 3);
2665 if (rb_int_negative_p(argv[1])) {
2674 if (rb_int_negative_p(argv[2])) {
2681 return rb_io_buffer_write(self, io, length, offset);
2692io_buffer_pwrite_internal(
void *_argument)
2696#if defined(HAVE_PWRITE)
2697 ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
2700 rb_off_t offset = lseek(argument->descriptor, 0, SEEK_CUR);
2701 if (offset == (rb_off_t)-1)
2704 if (lseek(argument->descriptor, argument->offset, SEEK_SET) == (rb_off_t)-1)
2707 ssize_t result = write(argument->descriptor, argument->base, argument->size);
2709 if (lseek(argument->descriptor, offset, SEEK_SET) == (rb_off_t)-1)
2717rb_io_buffer_pwrite(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
2720 if (scheduler !=
Qnil) {
2723 if (!UNDEF_P(result)) {
2731 io_buffer_validate_range(data, offset, length);
2737 io_buffer_get_bytes_for_reading(data, &base, &size);
2740 .descriptor = descriptor,
2743 .base = (
unsigned char *)base + offset,
2752 return rb_thread_io_blocking_region(io_buffer_pwrite_internal, &argument, descriptor);
2772io_buffer_pwrite(
int argc,
VALUE *argv,
VALUE self)
2774 rb_check_arity(argc, 3, 4);
2780 if (rb_int_negative_p(argv[2])) {
2787 if (rb_int_negative_p(argv[3])) {
2794 return rb_io_buffer_pwrite(self, io, from, length, offset);
2800 if (buffer->size == 0)
2801 rb_raise(rb_eIOBufferMaskError,
"Zero-length mask given!");
2805memory_and(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
2807 for (
size_t offset = 0; offset < size; offset += 1) {
2808 output[offset] = base[offset] & mask[offset % mask_size];
2833 io_buffer_check_mask(mask_data);
2835 VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
2839 memory_and(output_data->base, data->base, data->size, mask_data->base, mask_data->size);
2845memory_or(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
2847 for (
size_t offset = 0; offset < size; offset += 1) {
2848 output[offset] = base[offset] | mask[offset % mask_size];
2873 io_buffer_check_mask(mask_data);
2875 VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
2879 memory_or(output_data->base, data->base, data->size, mask_data->base, mask_data->size);
2885memory_xor(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
2887 for (
size_t offset = 0; offset < size; offset += 1) {
2888 output[offset] = base[offset] ^ mask[offset % mask_size];
2913 io_buffer_check_mask(mask_data);
2915 VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
2919 memory_xor(output_data->base, data->base, data->size, mask_data->base, mask_data->size);
2925memory_not(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size)
2927 for (
size_t offset = 0; offset < size; offset += 1) {
2928 output[offset] = ~base[offset];
2945io_buffer_not(
VALUE self)
2950 VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
2954 memory_not(output_data->base, data->base, data->size);
2962 if (a->base > b->base) {
2963 return io_buffer_overlaps(b, a);
2966 return (b->base >= a->base) && (b->base <= (
void*)((
unsigned char *)a->base + a->size));
2972 if (io_buffer_overlaps(a, b))
2973 rb_raise(rb_eIOBufferMaskError,
"Mask overlaps source data!");
2977memory_and_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
2979 for (
size_t offset = 0; offset < size; offset += 1) {
2980 base[offset] &= mask[offset % mask_size];
3010 io_buffer_check_mask(mask_data);
3011 io_buffer_check_overlaps(data, mask_data);
3015 io_buffer_get_bytes_for_writing(data, &base, &size);
3017 memory_and_inplace(base, size, mask_data->base, mask_data->size);
3023memory_or_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3025 for (
size_t offset = 0; offset < size; offset += 1) {
3026 base[offset] |= mask[offset % mask_size];
3056 io_buffer_check_mask(mask_data);
3057 io_buffer_check_overlaps(data, mask_data);
3061 io_buffer_get_bytes_for_writing(data, &base, &size);
3063 memory_or_inplace(base, size, mask_data->base, mask_data->size);
3069memory_xor_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3071 for (
size_t offset = 0; offset < size; offset += 1) {
3072 base[offset] ^= mask[offset % mask_size];
3102 io_buffer_check_mask(mask_data);
3103 io_buffer_check_overlaps(data, mask_data);
3107 io_buffer_get_bytes_for_writing(data, &base, &size);
3109 memory_xor_inplace(base, size, mask_data->base, mask_data->size);
3115memory_not_inplace(
unsigned char * restrict base,
size_t size)
3117 for (
size_t offset = 0; offset < size; offset += 1) {
3118 base[offset] = ~base[offset];
3140io_buffer_not_inplace(
VALUE self)
3147 io_buffer_get_bytes_for_writing(data, &base, &size);
3149 memory_not_inplace(base, size);
3252 GetSystemInfo(&info);
3253 RUBY_IO_BUFFER_PAGE_SIZE = info.dwPageSize;
3255 RUBY_IO_BUFFER_PAGE_SIZE = sysconf(_SC_PAGESIZE);
3258 RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
3268 rb_define_method(rb_cIOBuffer,
"initialize_copy", rb_io_buffer_initialize_copy, 1);
3316#define IO_BUFFER_DEFINE_DATA_TYPE(name) RB_IO_BUFFER_DATA_TYPE_##name = rb_intern_const(#name)
3317 IO_BUFFER_DEFINE_DATA_TYPE(U8);
3318 IO_BUFFER_DEFINE_DATA_TYPE(S8);
3320 IO_BUFFER_DEFINE_DATA_TYPE(u16);
3321 IO_BUFFER_DEFINE_DATA_TYPE(U16);
3322 IO_BUFFER_DEFINE_DATA_TYPE(s16);
3323 IO_BUFFER_DEFINE_DATA_TYPE(S16);
3325 IO_BUFFER_DEFINE_DATA_TYPE(u32);
3326 IO_BUFFER_DEFINE_DATA_TYPE(U32);
3327 IO_BUFFER_DEFINE_DATA_TYPE(s32);
3328 IO_BUFFER_DEFINE_DATA_TYPE(S32);
3330 IO_BUFFER_DEFINE_DATA_TYPE(u64);
3331 IO_BUFFER_DEFINE_DATA_TYPE(U64);
3332 IO_BUFFER_DEFINE_DATA_TYPE(s64);
3333 IO_BUFFER_DEFINE_DATA_TYPE(S64);
3335 IO_BUFFER_DEFINE_DATA_TYPE(f32);
3336 IO_BUFFER_DEFINE_DATA_TYPE(F32);
3337 IO_BUFFER_DEFINE_DATA_TYPE(f64);
3338 IO_BUFFER_DEFINE_DATA_TYPE(F64);
3339#undef IO_BUFFER_DEFINE_DATA_TYPE
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
int rb_block_given_p(void)
Determines if the current method is given a block.
#define T_STRING
Old name of RUBY_T_STRING.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define CLASS_OF
Old name of rb_class_of.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define NUM2DBL
Old name of rb_num2dbl.
#define Qnil
Old name of RUBY_Qnil.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define DBL2NUM
Old name of rb_float_new.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eArgError
ArgumentError exception.
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
static VALUE rb_class_of(VALUE obj)
Object to class mapping function.
VALUE rb_mComparable
Comparable module.
#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat)
Identical to RETURN_SIZED_ENUMERATOR_KW(), except its size is unknown.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
#define RB_SYM2ID
Just another name of rb_sym2id.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_UINT2NUM
Just another name of rb_uint2num_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define RB_LL2NUM
Just another name of rb_ll2num_inline.
#define RB_ULL2NUM
Just another name of rb_ull2num_inline.
#define RB_NUM2ULL
Just another name of rb_num2ull_inline.
#define RB_NUM2LL
Just another name of rb_num2ll_inline.
VALUE rb_yield(VALUE val)
Yields the block.
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define StringValue(v)
Ensures that the parameter object is a String.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
#define RB_NO_KEYWORDS
Do not pass keywords.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
Non-blocking write to the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
Non-blocking read from the passed IO.
static VALUE rb_fiber_scheduler_io_result(ssize_t result, int error)
Wrap a ssize_t and int errno into a single VALUE.
VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
Non-blocking read from the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
Non-blocking write to the passed IO.
#define RB_NUM2SIZE
Converts an instance of rb_cInteger into C's size_t.
const char * wrap_struct_name
Name of structs of this kind.
uintptr_t VALUE
Type that represents a Ruby object.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.