#lang scheme/base
(define (absolutely-write-bytes bytes output start end)
(let loop ((cur start))
(if (>= cur end) (- end start)
(let ((num (write-bytes bytes output cur end)))
(when (not (number? num))
(error "Hit end of file while writing!" output))
(loop (+ cur num))))))
(define (absolutely-read-bytes num input)
(let loop ((left num) (result null))
(if (<= left 0) (apply bytes-append (reverse result))
(let ((bytes (read-bytes left input)))
(when (eof-object? bytes)
(error "Hit end of file while reading" input))
(let ((left (- left (bytes-length bytes))))
(loop left (cons bytes result)))))))
(define-struct slice (bytes start end) #:transparent)
(define (create (num 0))
(make-slice (make-bytes num) 0 num))
(define (from-bytes bytes)
(make-slice bytes 0 (bytes-length bytes)))
(define (subslice slice start end)
(make-slice (slice-bytes slice) start end))
(define (to-bytes slice)
(subbytes (slice-bytes slice) (slice-start slice) (slice-end slice)))
(define (write-slice slice (output (current-output-port)))
(absolutely-write-bytes
(slice-bytes slice) output
(slice-start slice)
(slice-end slice)))
(define (read-slice num (input (current-input-port)))
(from-bytes (absolutely-read-bytes num input)))
(define (read-slice! slice (input (current-input-port)))
(read-bytes! (slice-bytes slice) input
(slice-start slice)
(slice-end slice)))
(define (slice-length slice)
(- (slice-end slice) (slice-start slice)))
(define (slice-append slices)
(define bytes (make-bytes
(foldl (λ (slice length) (+ length (slice-length slice))) 0 slices)))
(let loop ((offset 0) (slices slices))
(if (null? slices) (from-bytes bytes)
(let ((slice (car slices)))
(bytes-copy! bytes offset
(slice-bytes slice) (slice-start slice) (slice-end slice))
(loop
(+ offset (slice-length slice))
(cdr slices))))))
(provide
(rename-out
(read-slice read)
(read-slice! read!)
(write-slice write)
(slice-length length)
(slice-append append)
(subslice sub)
(slice-start start)
(slice-bytes bytes)
(slice-end end))
create
from-bytes
to-bytes
slice?)