-
-
Save y8/b5c2c4e1fccacffc3bbaa0a93a1c3964 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: | |
# | |
# file = File.tmpfile('test') | |
# chunk_size_bytes = BufferedReader.new(sizeof(UInt32), file) | |
# file.write_byte 0xBE | |
# file.write_byte 0xEF | |
# file.write_byte 0xFE | |
# file.pos -= 3 | |
# chunk_size_bytes.consume? => false | |
# file.write_byte 0xFE | |
# # file.pos -= 1 | |
# chunk_size_bytes.consume? => true | |
# Int32.from_io(chunk_size_bytes.to_memory, IO::ByteFormat::LittleEndian) | |
struct BufferedReader | |
property start_pos : UInt64, | |
end_pos : UInt64, | |
current_pos : UInt64 | |
# FIXME: Workaround for type mismatch between arches | |
# https://github.com/crystal-lang/crystal/issues/10645 | |
def initialize(@requested_size : Int32, @io : File) | |
size = requested_size.to_u64 | |
@start_pos = position | |
@end_pos = @start_pos + size | |
@current_pos = @start_pos | |
@memory = IO::Memory.new(size) | |
end | |
def initialize(@requested_size : UInt64, @io : File) | |
@start_pos = position | |
@end_pos = @start_pos + @requested_size | |
@current_pos = @start_pos | |
@memory = IO::Memory.new(@requested_size) | |
end | |
# Read from IO until @requested_size is fully read. Returns true when buffer | |
# fully read from IO and false otherwise. | |
def consume? | |
return true if ready? | |
# Make a snapshot of current position | |
available = available_bytes | |
waiting = waiting_bytes | |
read_bytes(waiting) | |
# Return true, if there was more bytes that we needed to complete the buffer | |
return available >= waiting | |
end | |
def ready? | |
@current_pos >= @end_pos | |
end | |
def waiting? | |
available_bytes <= 0 | |
end | |
def to_slice | |
@memory.to_slice if ready? | |
end | |
def to_memory | |
return unless ready? | |
@memory.rewind | |
@memory | |
end | |
# 100 bytes availabe, but we are waiting for 10. We'll allocate slice of | |
# 10 bytes, read 10 bytes form file to slice and then append slice to memory | |
# buffer. Then buffer is complete and can be returned to | |
private def read_bytes(waiting) | |
slice = Bytes.new(waiting) | |
@io.read(slice) | |
@current_pos = position | |
@memory.write(slice) | |
end | |
# Ex: file size = 100 bytes, size = 200, current_pos = 90 | |
# start_pos = 50, end_pos = 50 + 200 = 250, hence 250 - 90 = 160 bytes | |
# we are waiting for | |
private def waiting_bytes | |
@end_pos - @current_pos | |
end | |
# Ex: file size is 100 bytes, we are on 20th byte, hence 100 - 20 = 80 bytes | |
# available in file | |
# FIXME: Force UInt64 value (#10645) | |
private def available_bytes | |
(@io.size - @io.pos).to_u64 | |
end | |
# FIXME: Force UInt64 value (#10645) | |
private def position | |
@io.pos.to_u64 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment