File: //usr/lib/ruby/gems/3.2.0/gems/rbs-2.8.2/core/io/buffer.rbs
%a{annotate:rdoc:skip}
class IO
# <!-- rdoc-file=io_buffer.c -->
# IO::Buffer is a low-level efficient buffer for input/output. There are three
# ways of using buffer:
#
# * Create an empty buffer with ::new, fill it with data using #copy or
# #set_value, #set_string, get data with #get_string;
# * Create a buffer mapped to some string with ::for, then it could be used
# both for reading with #get_string or #get_value, and writing (writing will
# change the source string, too);
# * Create a buffer mapped to some file with ::map, then it could be used for
# reading and writing the underlying file.
#
#
# Interaction with string and file memory is performed by efficient low-level C
# mechanisms like `memcpy`.
#
# The class is meant to be an utility for implementing more high-level
# mechanisms like Fiber::SchedulerInterface#io_read and
# Fiber::SchedulerInterface#io_write.
#
# **Examples of usage:**
#
# Empty buffer:
#
# buffer = IO::Buffer.new(8) # create empty 8-byte buffer
# # =>
# # #<IO::Buffer 0x0000555f5d1a5c50+8 INTERNAL>
# # ...
# buffer
# # =>
# # <IO::Buffer 0x0000555f5d156ab0+8 INTERNAL>
# # 0x00000000 00 00 00 00 00 00 00 00
# buffer.set_string('test', 2) # put there bytes of the "test" string, starting from offset 2
# # => 4
# buffer.get_string # get the result
# # => "\x00\x00test\x00\x00"
#
# Buffer from string:
#
# string = 'data'
# buffer = IO::Buffer.for(str)
# # =>
# # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
# # ...
# buffer
# # =>
# # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
# # 0x00000000 64 61 74 61 data
#
# buffer.get_string(2) # read content starting from offset 2
# # => "ta"
# buffer.set_string('---', 1) # write content, starting from offset 1
# # => 3
# buffer
# # =>
# # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
# # 0x00000000 64 2d 2d 2d d---
# string # original string changed, too
# # => "d---"
#
# Buffer from file:
#
# File.write('test.txt', 'test data')
# # => 9
# buffer = IO::Buffer.map(File.open('test.txt'))
# # =>
# # #<IO::Buffer 0x00007f3f0768c000+9 MAPPED IMMUTABLE>
# # ...
# buffer.get_string(5, 2) # read 2 bytes, starting from offset 5
# # => "da"
# buffer.set_string('---', 1) # attempt to write
# # in `set_string': Buffer is not writable! (IO::Buffer::AccessError)
#
# # To create writable file-mapped buffer
# # Open file for read-write, pass size, offset, and flags=0
# buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 9, 0, 0)
# buffer.set_string('---', 1)
# # => 3 -- bytes written
# File.read('test.txt')
# # => "t--- data"
#
# **The class is experimental and the interface is subject to change.**
#
class Buffer
include Comparable
# <!--
# rdoc-file=io_buffer.c
# - IO::Buffer.for(string) -> readonly io_buffer
# - IO::Buffer.for(string) {|io_buffer| ... read/write io_buffer ...}
# -->
# Creates a IO::Buffer from the given string's memory. Without a block a frozen
# internal copy of the string is created efficiently and used as the buffer
# source. When a block is provided, the buffer is associated directly with the
# string's internal data and updating the buffer will update the string.
#
# Until #free is invoked on the buffer, either explicitly or via the garbage
# collector, the source string will be locked and cannot be modified.
#
# If the string is frozen, it will create a read-only buffer which cannot be
# modified.
#
# string = 'test'
# buffer = IO::Buffer.for(string)
# buffer.external? #=> true
#
# buffer.get_string(0, 1)
# # => "t"
# string
# # => "best"
#
# buffer.resize(100)
# # in `resize': Cannot resize external buffer! (IO::Buffer::AccessError)
#
# IO::Buffer.for(string) do |buffer|
# buffer.set_string("T")
# string
# # => "Test"
# end
#
def self.for: (String) -> Buffer
# <!--
# rdoc-file=io_buffer.c
# - IO::Buffer.map(file, [size, [offset, [flags]]]) -> io_buffer
# -->
# Create an IO::Buffer for reading from `file` by memory-mapping the file.
# `file_io` should be a `File` instance, opened for reading.
#
# Optional `size` and `offset` of mapping can be specified.
#
# By default, the buffer would be immutable (read only); to create a writable
# mapping, you need to open a file in read-write mode, and explicitly pass
# `flags` argument without IO::Buffer::IMMUTABLE.
#
# File.write('test.txt', 'test')
#
# buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
# # => #<IO::Buffer 0x00000001014a0000+4 MAPPED READONLY>
#
# buffer.readonly? # => true
#
# buffer.get_string
# # => "test"
#
# buffer.set_string('b', 0)
# # `set_string': Buffer is not writable! (IO::Buffer::AccessError)
#
# # create read/write mapping: length 4 bytes, offset 0, flags 0
# buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 4, 0)
# buffer.set_string('b', 0)
# # => 1
#
# # Check it
# File.read('test.txt')
# # => "best"
#
# Note that some operating systems may not have cache coherency between mapped
# buffers and file reads.
#
def self.map: (File file, ?Integer? size, ?Integer offset, ?Integer flags) -> Buffer
public
# <!--
# rdoc-file=io_buffer.c
# - <=>(other) -> true or false
# -->
# Buffers are compared by size and exact contents of the memory they are
# referencing using `memcmp`.
#
def <=>: (Buffer) -> Integer
# <!--
# rdoc-file=io_buffer.c
# - clear(value = 0, [offset, [length]]) -> self
# -->
# Fill buffer with `value`, starting with `offset` and going for `length` bytes.
#
# buffer = IO::Buffer.for('test')
# # =>
# # <IO::Buffer 0x00007fca40087c38+4 SLICE>
# # 0x00000000 74 65 73 74 test
#
# buffer.clear
# # =>
# # <IO::Buffer 0x00007fca40087c38+4 SLICE>
# # 0x00000000 00 00 00 00 ....
#
# buf.clear(1) # fill with 1
# # =>
# # <IO::Buffer 0x00007fca40087c38+4 SLICE>
# # 0x00000000 01 01 01 01 ....
#
# buffer.clear(2, 1, 2) # fill with 2, starting from offset 1, for 2 bytes
# # =>
# # <IO::Buffer 0x00007fca40087c38+4 SLICE>
# # 0x00000000 01 02 02 01 ....
#
# buffer.clear(2, 1) # fill with 2, starting from offset 1
# # =>
# # <IO::Buffer 0x00007fca40087c38+4 SLICE>
# # 0x00000000 01 02 02 02 ....
#
def clear: (?Integer value, ?Integer offset, ?Integer length) -> self
# <!--
# rdoc-file=io_buffer.c
# - copy(source, [offset, [length, [source_offset]]]) -> size
# -->
# Efficiently copy data from a source IO::Buffer into the buffer, at `offset`
# using `memcpy`. For copying String instances, see #set_string.
#
# buffer = IO::Buffer.new(32)
# # =>
# # #<IO::Buffer 0x0000555f5ca22520+32 INTERNAL>
# # 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
# # 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ *
#
# buffer.copy(IO::Buffer.for("test"), 8)
# # => 4 -- size of data copied
# buffer
# # =>
# # #<IO::Buffer 0x0000555f5cf8fe40+32 INTERNAL>
# # 0x00000000 00 00 00 00 00 00 00 00 74 65 73 74 00 00 00 00 ........test....
# # 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ *
#
# #copy can be used to put data into strings associated with buffer:
#
# string= "data: "
# # => "data: "
# buffer = IO::Buffer.for(str)
# buffer.copy(IO::Buffer.for("test"), 5)
# # => 4
# string
# # => "data:test"
#
# Attempt to copy into a read-only buffer will fail:
#
# File.write('test.txt', 'test')
# buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
# buffer.copy(IO::Buffer.for("test"), 8)
# # in `copy': Buffer is not writable! (IO::Buffer::AccessError)
#
# See ::map for details of creation of mutable file mappings, this will work:
#
# buffer = IO::Buffer.map(File.open('test.txt', 'r+'))
# buffer.copy("boom", 0)
# # => 4
# File.read('test.txt')
# # => "boom"
#
# Attempt to copy the data which will need place outside of buffer's bounds will
# fail:
#
# buffer = IO::Buffer.new(2)
# buffer.copy('test', 0)
# # in `copy': Specified offset+length exceeds source size! (ArgumentError)
#
def copy: (Buffer source, ?Integer offset, ?Integer length, ?Integer source_offset) -> Integer
# <!--
# rdoc-file=io_buffer.c
# - external? -> true or false
# -->
# If the buffer is _external_, meaning it references from memory which is not
# allocated or mapped by the buffer itself.
#
# A buffer created using ::for has an external reference to the string's
# memory.
#
# External buffer can't be resized.
#
def empty?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - external?()
# -->
#
def external?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - free -> self
# -->
# If the buffer references memory, release it back to the operating system.
# * for a *mapped* buffer (e.g. from file): unmap.
# * for a buffer created from scratch: free memory.
# * for a buffer created from string: undo the association.
#
#
# After the buffer is freed, no further operations can't be performed on it.
#
# buffer = IO::Buffer.for('test')
# buffer.free
# # => #<IO::Buffer 0x0000000000000000+0 NULL>
#
# buffer.get_value(:U8, 0)
# # in `get_value': The buffer is not allocated! (IO::Buffer::AllocationError)
#
# buffer.get_string
# # in `get_string': The buffer is not allocated! (IO::Buffer::AllocationError)
#
# buffer.null?
# # => true
#
# You can resize a freed buffer to re-allocate it.
#
def free: () -> self
# <!--
# rdoc-file=io_buffer.c
# - get_string([offset, [length, [encoding]]]) -> string
# -->
# Read a chunk or all of the buffer into a string, in the specified `encoding`.
# If no encoding is provided `Encoding::BINARY` is used.
#
# buffer = IO::Buffer.for('test')
# buffer.get_string
# # => "test"
# buffer.get_string(2)
# # => "st"
# buffer.get_string(2, 1)
# # => "s"
#
def get_string: (?Integer offset, ?Integer length, ?Encoding encoding) -> String
# <!--
# rdoc-file=io_buffer.c
# - get_value(type, offset) -> numeric
# -->
# Read from buffer a value of `type` at `offset`. `type` should be one of
# symbols:
#
# * `:U8`: unsigned integer, 1 byte
# * `:S8`: signed integer, 1 byte
# * `:u16`: unsigned integer, 2 bytes, little-endian
# * `:U16`: unsigned integer, 2 bytes, big-endian
# * `:s16`: signed integer, 2 bytes, little-endian
# * `:S16`: signed integer, 2 bytes, big-endian
# * `:u32`: unsigned integer, 4 bytes, little-endian
# * `:U32`: unsigned integer, 4 bytes, big-endian
# * `:s32`: signed integer, 4 bytes, little-endian
# * `:S32`: signed integer, 4 bytes, big-endian
# * `:u64`: unsigned integer, 8 bytes, little-endian
# * `:U64`: unsigned integer, 8 bytes, big-endian
# * `:s64`: signed integer, 8 bytes, little-endian
# * `:S64`: signed integer, 8 bytes, big-endian
# * `:f32`: float, 4 bytes, little-endian
# * `:F32`: float, 4 bytes, big-endian
# * `:f64`: double, 8 bytes, little-endian
# * `:F64`: double, 8 bytes, big-endian
#
#
# Example:
#
# string = [1.5].pack('f')
# # => "\x00\x00\xC0?"
# IO::Buffer.for(string).get_value(:f32, 0)
# # => 1.5
#
def get_value: (int_get_type, Integer offset) -> Integer
| (float_get_type, Integer offset) -> Float
type int_get_type = :U8 | :S8
| :u16 | :U16 | :s16 | :S16
| :u32 | :U32 | :s32 | :S32
| :u64 | :U64 | :s64 | :S64
type float_get_type = :f32 | :F32 | :f64 | :F64
# <!--
# rdoc-file=io_buffer.c
# - hexdump()
# -->
#
def hexdump: () -> String
# <!--
# rdoc-file=io_buffer.c
# - inspect()
# -->
#
def inspect: () -> String
# <!--
# rdoc-file=io_buffer.c
# - internal? -> true or false
# -->
# If the buffer is *internal*, meaning it references memory allocated by the
# buffer itself.
#
# An internal buffer is not associated with any external memory (e.g. string) or
# file mapping.
#
# Internal buffers are created using ::new and is the default when the requested
# size is less than the IO::Buffer::PAGE_SIZE and it was not requested to be
# mapped on creation.
#
# Internal buffers can be resized, and such an operation will typically
# invalidate all slices, but not always.
#
def internal?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - locked { ... }
# -->
# Allows to process a buffer in exclusive way, for concurrency-safety. While the
# block is performed, the buffer is considered locked, and no other code can
# enter the lock. Also, locked buffer can't be changed with #resize or #free.
#
# buffer = IO::Buffer.new(4)
# buffer.locked? #=> false
#
# Fiber.schedule do
# buffer.locked do
# buffer.write(io) # theoretical system call interface
# end
# end
#
# Fiber.schedule do
# # in `locked': Buffer already locked! (IO::Buffer::LockedError)
# buffer.locked do
# buffer.set_string(...)
# end
# end
#
# The following operations acquire a lock: #resize, #free.
#
# Locking is not thread safe. It is designed as a safety net around non-blocking
# system calls. You can only share a buffer between threads with appropriate
# synchronisation techniques.
#
def locked: [A] () { (IO::Buffer) -> A } -> A
# <!--
# rdoc-file=io_buffer.c
# - locked? -> true or false
# -->
# If the buffer is *locked*, meaning it is inside #locked block execution.
# Locked buffer can't be resized or freed, and another lock can't be acquired on
# it.
#
# Locking is not thread safe, but is a semantic used to ensure buffers don't
# move while being used by a system call.
#
# buffer.locked do
# buffer.write(io) # theoretical system call interface
# end
#
def locked?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - mapped? -> true or false
# -->
# If the buffer is *mapped*, meaning it references memory mapped by the buffer.
#
# Mapped buffers are either anonymous, if created by ::new with the
# IO::Buffer::MAPPED flag or if the size was at least IO::Buffer::PAGE_SIZE, or
# backed by a file if created with ::map.
#
# Mapped buffers can usually be resized, and such an operation will typically
# invalidate all slices, but not always.
#
def mapped?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - null? -> true or false
# -->
# If the buffer was freed with #free or was never allocated in the first place.
#
def null?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - pread(p1, p2, p3)
# -->
#
def pread: (untyped, untyped, untyped) -> untyped
# <!--
# rdoc-file=io_buffer.c
# - pwrite(p1, p2, p3)
# -->
#
def pwrite: (untyped, untyped, untyped) -> untyped
# <!--
# rdoc-file=io_buffer.c
# - read(p1, p2)
# -->
#
def read: (untyped, untyped) -> untyped
# <!--
# rdoc-file=io_buffer.c
# - readonly?()
# -->
#
def readonly?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - resize(new_size) -> self
# -->
# Resizes a buffer to a `new_size` bytes, preserving its content. Depending on
# the old and new size, the memory area associated with the buffer might be
# either extended, or rellocated at different address with content being copied.
#
# buffer = IO::Buffer.new(4)
# buffer.set_string("test", 0)
# buffer.resize(8) # resize to 8 bytes
# # =>
# # #<IO::Buffer 0x0000555f5d1a1630+8 INTERNAL>
# # 0x00000000 74 65 73 74 00 00 00 00 test....
#
# External buffer (created with ::for), and locked buffer can not be resized.
#
def resize: (Integer) -> self
# <!--
# rdoc-file=io_buffer.c
# - set_string(*args)
# -->
#
def set_string: (*untyped) -> untyped
# <!--
# rdoc-file=io_buffer.c
# - set_value(type, offset, value) -> offset
# -->
# Write to a buffer a `value` of `type` at `offset`. `type` should be one of
# symbols described in #get_value.
#
# buffer = IO::Buffer.new(8)
# # =>
# # #<IO::Buffer 0x0000555f5c9a2d50+8 INTERNAL>
# # 0x00000000 00 00 00 00 00 00 00 00
# buffer.set_value(:U8, 1, 111)
# # => 1
# buffer
# # =>
# # #<IO::Buffer 0x0000555f5c9a2d50+8 INTERNAL>
# # 0x00000000 00 6f 00 00 00 00 00 00 .o......
#
# Note that if the `type` is integer and `value` is Float, the implicit
# truncation is performed:
#
# buffer = IO::Buffer.new(8)
# buffer.set_value(:U32, 0, 2.5)
# buffer
# # =>
# # #<IO::Buffer 0x0000555f5c9a2d50+8 INTERNAL>
# # 0x00000000 00 00 00 02 00 00 00 00
# # ^^ the same as if we'd pass just integer 2
#
def set_value: (int_get_type | float_get_type, Integer offset, Float | Integer value) -> Integer
# <!--
# rdoc-file=io_buffer.c
# - size -> integer
# -->
# Returns the size of the buffer that was explicitly set (on creation with ::new
# or on #resize), or deduced on buffer's creation from string or file.
#
def size: () -> Integer
# <!--
# rdoc-file=io_buffer.c
# - slice(offset, length) -> io_buffer
# -->
# Produce another IO::Buffer which is a slice (or view into) the current one
# starting at `offset` bytes and going for `length` bytes.
#
# The slicing happens without copying of memory, and the slice keeps being
# associated with the original buffer's source (string, or file), if any.
#
# Raises RuntimeError if the <tt>offset+length<tt> is out of the current
# buffer's bounds.
#
# string = 'test'
# buffer = IO::Buffer.for(string)
#
# slice = buffer.slice(1, 2)
# # =>
# # #<IO::Buffer 0x00007fc3d34ebc49+2 SLICE>
# # 0x00000000 65 73 es
#
# # Put "o" into 0s position of the slice
# slice.set_string('o', 0)
# slice
# # =>
# # #<IO::Buffer 0x00007fc3d34ebc49+2 SLICE>
# # 0x00000000 6f 73 os
#
# # it is also visible at position 1 of the original buffer
# buffer
# # =>
# # #<IO::Buffer 0x00007fc3d31e2d80+4 SLICE>
# # 0x00000000 74 6f 73 74 tost
#
# # ...and original string
# string
# # => tost
#
def slice: (Integer offset, Integer length) -> Buffer
# <!--
# rdoc-file=io_buffer.c
# - to_s -> string
# -->
# Short representation of the buffer. It includes the address, size and symbolic
# flags. This format is subject to change.
#
# puts IO::Buffer.new(4) # uses to_s internally
# # #<IO::Buffer 0x000055769f41b1a0+4 INTERNAL>
#
def to_s: () -> String
# <!--
# rdoc-file=io_buffer.c
# - transfer -> new_io_buffer
# -->
# Transfers ownership to a new buffer, deallocating the current one.
#
# buffer = IO::Buffer.new('test')
# other = buffer.transfer
# other
# # =>
# # #<IO::Buffer 0x00007f136a15f7b0+4 SLICE>
# # 0x00000000 74 65 73 74 test
# buffer
# # =>
# # #<IO::Buffer 0x0000000000000000+0 NULL>
# buffer.null?
# # => true
#
def transfer: () -> Buffer
# <!--
# rdoc-file=io_buffer.c
# - valid? -> true or false
# -->
# Returns whether the buffer data is accessible.
#
# A buffer becomes invalid if it is a slice of another buffer which has been
# freed.
#
def valid?: () -> bool
# <!--
# rdoc-file=io_buffer.c
# - write(p1, p2)
# -->
#
def write: (untyped, untyped) -> untyped
private
# <!--
# rdoc-file=io_buffer.c
# - IO::Buffer.new([size = DEFAULT_SIZE, [flags = 0]]) -> io_buffer
# -->
# Create a new zero-filled IO::Buffer of `size` bytes. By default, the buffer
# will be *internal*: directly allocated chunk of the memory. But if the
# requested `size` is more than OS-specific IO::Bufer::PAGE_SIZE, the buffer
# would be allocated using the virtual memory mechanism (anonymous `mmap` on
# Unix, `VirtualAlloc` on Windows). The behavior can be forced by passing
# IO::Buffer::MAPPED as a second parameter.
#
# Examples
#
# buffer = IO::Buffer.new(4)
# # =>
# # #<IO::Buffer 0x000055b34497ea10+4 INTERNAL>
# # 0x00000000 00 00 00 00 ....
#
# buffer.get_string(0, 1) # => "\x00"
#
# buffer.set_string("test")
# buffer
# # =>
# # #<IO::Buffer 0x000055b34497ea10+4 INTERNAL>
# # 0x00000000 74 65 73 74 test
#
def initialize: (?Integer size, ?Integer flags) -> void
BIG_ENDIAN: Integer
DEFAULT_SIZE: Integer
EXTERNAL: Integer
HOST_ENDIAN: Integer
INTERNAL: Integer
LITTLE_ENDIAN: Integer
LOCKED: Integer
MAPPED: Integer
NETWORK_ENDIAN: Integer
PAGE_SIZE: Integer
PRIVATE: Integer
READONLY: Integer
class LockedError < RuntimeError
end
class AllocationError < RuntimeError
end
class AccessError < RuntimeError
end
class InvalidatedError < RuntimeError
end
class MaskError < ArgumentError
end
end
end