# class NIO::ByteBuffer

Efficient byte buffers for performant I/O operations

### Constants

MarkUnsetError

  Mark has not been set

OverflowError

  Insufficient capacity in buffer

UnderflowError

  Not enough data remaining in buffer

### Public Class Methods

new(p1) click to toggle source

    static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE capacity)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        buffer->capacity = NUM2INT(capacity);
        buffer->buffer = xmalloc(buffer->capacity);

        NIO_ByteBuffer_clear(self);

        return self;
    }

new(capacity) click to toggle source

Create a new ByteBuffer, either with a specified capacity or populating it from a given string

@param capacity [Integer] size of buffer in bytes

@return [NIO::ByteBuffer]

    # File lib/nio/bytebuffer.rb, line 24
    def initialize(capacity)
      raise TypeError, "no implicit conversion of #{capacity.class} to Integer" unless capacity.is_a?(Integer)
      @capacity = capacity
      clear
    end

### Public Instance Methods

<<(p1) click to toggle source

    static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        long length = RSTRING_LEN(string);

        if(length > buffer->limit - buffer->position) {
            rb_raise(cNIO_ByteBuffer_OverflowError, "buffer is full");
        }

        memcpy(buffer->buffer + buffer->position, StringValuePtr(string), length);
        buffer->position += length;

        return self;
    }

[](p1) click to toggle source

    static VALUE NIO_ByteBuffer_fetch(VALUE self, VALUE index)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        int i = NUM2INT(index);

        if(i < 0) {
            rb_raise(rb_eArgError, "negative index given");
        }

        if(i >= buffer->limit) {
            rb_raise(rb_eArgError, "specified index exceeds limit");
        }

        return INT2NUM(buffer->buffer[i]);
    }

capacity() click to toggle source

    static VALUE NIO_ByteBuffer_capacity(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return INT2NUM(buffer->capacity);
    }

clear() click to toggle source

    static VALUE NIO_ByteBuffer_clear(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        memset(buffer->buffer, 0, buffer->capacity);

        buffer->position = 0;
        buffer->limit = buffer->capacity;
        buffer->mark = MARK_UNSET;

        return self;
    }

compact() click to toggle source

    static VALUE NIO_ByteBuffer_compact(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        memmove(buffer->buffer, buffer->buffer + buffer->position, buffer->limit - buffer->position);
        buffer->position = buffer->limit - buffer->position;
        buffer->limit = buffer->capacity;

        return self;
    }

each() click to toggle source

    static VALUE NIO_ByteBuffer_each(VALUE self)
    {
        int i;
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        if(rb_block_given_p()) {
            for(i = 0; i < buffer->limit; i++) {
                rb_yield(INT2NUM(buffer->buffer[i]));
            }
        } else {
            rb_raise(rb_eArgError, "no block given");
        }

        return self;
    }

flip() click to toggle source

    static VALUE NIO_ByteBuffer_flip(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        buffer->limit = buffer->position;
        buffer->position = 0;
        buffer->mark = MARK_UNSET;

        return self;
    }

full?() click to toggle source

    static VALUE NIO_ByteBuffer_full(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return buffer->position == buffer->limit ? Qtrue : Qfalse;
    }

get(p1 = v1) click to toggle source

    static VALUE NIO_ByteBuffer_get(int argc, VALUE *argv, VALUE self)
    {
        int len;
        VALUE length, result;
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        rb_scan_args(argc, argv, "01", &length);

        if(length == Qnil) {
            len = buffer->limit - buffer->position;
        } else {
            len = NUM2INT(length);
        }

        if(len < 0) {
            rb_raise(rb_eArgError, "negative length given");
        }

        if(len > buffer->limit - buffer->position) {
            rb_raise(cNIO_ByteBuffer_UnderflowError, "not enough data in buffer");
        }

        result = rb_str_new(buffer->buffer + buffer->position, len);
        buffer->position += len;

        return result;
    }

inspect() click to toggle source

    static VALUE NIO_ByteBuffer_inspect(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return rb_sprintf(
            "#<%s:%p @position=%d @limit=%d @capacity=%d>",
            rb_class2name(CLASS_OF(self)),
            (void*)self,
            buffer->position,
            buffer->limit,
            buffer->capacity
        );
    }

limit() click to toggle source

    static VALUE NIO_ByteBuffer_get_limit(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return INT2NUM(buffer->limit);
    }

limit=(p1) click to toggle source

    static VALUE NIO_ByteBuffer_set_limit(VALUE self, VALUE new_limit)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        int lim = NUM2INT(new_limit);

        if(lim < 0) {
            rb_raise(rb_eArgError, "negative limit given");
        }

        if(lim > buffer->capacity) {
            rb_raise(rb_eArgError, "specified limit exceeds capacity");
        }

        buffer->limit = lim;

        if(buffer->position > lim) {
            buffer->position = lim;
        }

        if(buffer->mark > lim) {
            buffer->mark = MARK_UNSET;
        }

        return new_limit;
    }

mark() click to toggle source

    static VALUE NIO_ByteBuffer_mark(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        buffer->mark = buffer->position;
        return self;
    }

position() click to toggle source

    static VALUE NIO_ByteBuffer_get_position(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return INT2NUM(buffer->position);
    }

position=(p1) click to toggle source

    static VALUE NIO_ByteBuffer_set_position(VALUE self, VALUE new_position)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        int pos = NUM2INT(new_position);

        if(pos < 0) {
            rb_raise(rb_eArgError, "negative position given");
        }

        if(pos > buffer->limit) {
            rb_raise(rb_eArgError, "specified position exceeds limit");
        }

        buffer->position = pos;

        if(buffer->mark > buffer->position) {
            buffer->mark = MARK_UNSET;
        }

        return new_position;
    }

read_from(p1) click to toggle source

    static VALUE NIO_ByteBuffer_read_from(VALUE self, VALUE io)
    {
        struct NIO_ByteBuffer *buffer;
        rb_io_t *fptr;
        ssize_t nbytes, bytes_read;

        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
        GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
        rb_io_set_nonblock(fptr);

        nbytes = buffer->limit - buffer->position;
        if(nbytes == 0) {
            rb_raise(cNIO_ByteBuffer_OverflowError, "buffer is full");
        }

        bytes_read = read(FPTR_TO_FD(fptr), buffer->buffer + buffer->position, nbytes);

        if(bytes_read < 0) {
            if(errno == EAGAIN) {
                return INT2NUM(0);
            } else {
                rb_sys_fail("write");
            }
        }

        buffer->position += bytes_read;

        return INT2NUM(bytes_read);
    }

remaining() click to toggle source

    static VALUE NIO_ByteBuffer_remaining(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return INT2NUM(buffer->limit - buffer->position);
    }

reset() click to toggle source

    static VALUE NIO_ByteBuffer_reset(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        if(buffer->mark < 0) {
            rb_raise(cNIO_ByteBuffer_MarkUnsetError, "mark has not been set");
        } else {
            buffer->position = buffer->mark;
        }

        return self;
    }

rewind() click to toggle source

    static VALUE NIO_ByteBuffer_rewind(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        buffer->position = 0;
        buffer->mark = MARK_UNSET;

        return self;
    }

size() click to toggle source

    static VALUE NIO_ByteBuffer_capacity(VALUE self)
    {
        struct NIO_ByteBuffer *buffer;
        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);

        return INT2NUM(buffer->capacity);
    }

write_to(p1) click to toggle source

    static VALUE NIO_ByteBuffer_write_to(VALUE self, VALUE io)
    {
        struct NIO_ByteBuffer *buffer;
        rb_io_t *fptr;
        ssize_t nbytes, bytes_written;

        Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
        GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
        rb_io_set_nonblock(fptr);

        nbytes = buffer->limit - buffer->position;
        if(nbytes == 0) {
            rb_raise(cNIO_ByteBuffer_UnderflowError, "no data remaining in buffer");
        }

        bytes_written = write(FPTR_TO_FD(fptr), buffer->buffer + buffer->position, nbytes);

        if(bytes_written < 0) {
            if(errno == EAGAIN) {
                return INT2NUM(0);
            } else {
                rb_sys_fail("write");
            }
        }

        buffer->position += bytes_written;

        return INT2NUM(bytes_written);
    }