(require <kawa.lib.prim_imports>)
(require <kawa.lib.std_syntax>)
(require <kawa.lib.syntax>)

(define (bytevector? x) ::boolean
  (instance? x bytevector))

(define (make-bytevector (n ::int) #!optional (init ::int 0)) :: bytevector
  (make gnu.lists.U8Vector n init))

(define (bytevector-length (v :: bytevector)) ::int
  (invoke v 'size))

(define (bytevector-u8-ref (v ::bytevector) (i ::int)) ::int
  (v:getInt i))

(define (bytevector-u8-set! (v ::bytevector) (i ::int) (x ::int)) ::void
  (v:setByte i x))

(define (bytevector-copy v::bytevector
                         #!optional (start ::int 0) (end ::int (v:size)))
  ::bytevector
  (let ((result (gnu.lists.U8Vector(- end start))))
    (result:copyFrom 0 v start end)
    result))

(define (bytevector-copy! (to ::bytevector)
                          (at ::int)
                          (from ::bytevector)
                          #!optional
                          (start ::int 0)
                          (end ::int (from:size)))
  (to:copyFrom at from start end))

(define (bytevector-append #!rest (bvs ::bytevector[]))
  (define nbvs ::int bvs:length)
  (define size ::int
    (let loop ((i ::int 0) (sz ::int 0))
      (if (< i nbvs)
          (loop (+ i 1) (+ sz ((bvs i):size)))
          sz)))
  (define result ::bytevector (gnu.lists.U8Vector size))
  (let loop ((i ::int 0) (off ::int 0))
    (if (< i nbvs)
        (let* ((bv (bvs i))
               (bvlength (bv:size)))
          (result:copyFrom off bv 0 bvlength)
          (loop (+ i 1) (+ off bvlength)))
        result)))

(define (utf8->string (v ::bytevector)
                      #!optional
                      (start ::int 0)
                      (end ::int (v:size)))
  ::string
  (gnu.lists.IString (v:utf8ToString start (- end start))))

(define (utf16->string (v ::bytevector)
                      #!optional
                      (start ::int 0)
                      (end ::int (v:size)))
  ::string
  (gnu.lists.IString (v:utf16ToString start (- end start))))

(define (utf16le->string (v ::bytevector)
                      #!optional
                      (start ::int 0)
                      (end ::int (v:size)))
  ::string
  (gnu.lists.IString (v:utf16ToString start (- end start) #f)))

(define (utf16be->string (v ::bytevector)
                      #!optional
                      (start ::int 0)
                      (end ::int (v:size)))
  ::string
  (gnu.lists.IString (v:utf16ToString start (- end start) #t)))
