/*---------------------------------------------------------------------------
  Copyright 2024-2026, Tim Whiting, Microsoft Research, Daan Leijen

  This is free software; you can redistribute it and/or modify it under the
  terms of the Apache License, Version 2.0. A copy of the License can be
  found in the LICENSE file at the root of this distribution.
---------------------------------------------------------------------------*/

// Byte slices
//
// Todo: add iteration (foreach, prev, next etc)
module std/core/bslicestd/core/bslice

import std/core/debugstd/core/debug
import std/core/bytesstd/core/bytes
import std/core/typesstd/core/types
import std/core/intstd/core/int
import std/core/exnstd/core/exn
import std/core/liststd/core/list

extern import 
  c file "inline/bslice" 

// A byte slice represents a range of bytes in a `:bytes` type.
abstract value struct bslicestd/core/bslice/bslice: V 
  backing-bytesstd/core/bslice/bslice/backing-bytes: (bslice : bslice) -> bytes : bytesstd/core/types/bytes: V
  startstd/core/bslice/bslice/start: (bslice : bslice) -> int : intstd/core/types/int: V
  lenstd/core/bslice/bslice/len: (bslice : bslice) -> int   : intstd/core/types/int: V 
  

// An empty byte slice
pub val emptystd/core/bslice/empty: bslice = Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(emptystd/core/bytes/empty: bytes,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) // Is a slice empty? pub fun is-emptystd/core/bslice/is-empty: (slice : bslice) -> bool( sliceslice: bslice : bslicestd/core/bslice/bslice: V )result: -> total bool : boolstd/core/types/bool: V sliceslice: bslice.lenstd/core/bslice/bslice/len: (bslice : bslice) -> int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
// Create a byte slice from bytes pub fun slicestd/core/bslice/slice: (b : bytes) -> bslice( bb: bytes : bytesstd/core/types/bytes: V )result: -> total bslice : bslicestd/core/bslice/bslice: V Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int
) // View of the first `n` bytes pub fun firststd/core/bslice/first: (b : bytes, n : ? int) -> bslice( bb: bytes : bytesstd/core/types/bytes: V, nn: ? int : intstd/core/types/int: V = 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)result: -> total bslice : bslicestd/core/bslice/bslice: V Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, nn: int.clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int)
) // View of the last `n` bytes pub fun laststd/core/bslice/last: (b : bytes, n : ? int) -> bslice( bb: bytes : bytesstd/core/types/bytes: V, nn: ? int : intstd/core/types/int: V = 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)result: -> total bslice : bslicestd/core/bslice/bslice: V val totaltotal: int = bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int val countcount: int = nn: int.clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,totaltotal: int) val startstart: int = totaltotal: int -std/core/int/(-): (x : int, y : int) -> int countcount: int Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes, startstart: int, countcount: int
) // Get the bytes referenced by the slice pub fun bytesstd/core/bslice/bytes: (bslice) -> bytes( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V )result: -> total bytes : bytesstd/core/types/bytes: V bb: bytes.subbytesstd/core/bytes/subbytes: (bs : bytes, start : ? int, len : ? int) -> bytes( startstart: int, lenlen: int ) // If the slice is not empty, // return the first byte, and a new slice that is advanced by 1. pub fun nextstd/core/bslice/next: (bslice) -> maybe2<int,bslice>( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V )result: -> total maybe2<int,bslice> : maybe2std/core/types/maybe2: (V, V) -> V<intstd/core/types/int: V, bslicestd/core/bslice/bslice: V> if lenlen: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then Nothing2std/core/types/Nothing2: forall<a,b> maybe2<a,b> else Just2std/core/types/Just2: forall<a,b> (fst : a, snd : b) -> maybe2<a,b>(bb: bytes.unsafe-indexstd/core/bytes/unsafe-index: (b : bytes, i : ssize_t) -> uint8(startstart: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t).intstd/core/int/uint8/int: (i : uint8) -> int, Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes, startstart: int +std/core/int/(+): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
, lenlen: int -std/core/int/(-): (x : int, y : int) -> int 1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
)
) // O(1). Advance the start position of a byte slice by `count` bytes // up to the end of the byte array. // A negative `count` advances the start position backwards up to index 0. pub fun advancestd/core/bslice/advance: (bslice, count : int) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V, countcount: int : intstd/core/types/int: V)result: -> total bslice : bslicestd/core/bslice/bslice: V val totaltotal: int = bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int val newstartnewstart: int = clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(startstart: int +std/core/int/(+): (x : int, y : int) -> int countcount: int, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, totaltotal: int) val newlennewlen: int = maxstd/core/int/max: (i : int, j : int) -> int(lenlen: int, totaltotal: int -std/core/int/(-): (x : int, y : int) -> int newstartnewstart: int) Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,newstartnewstart: int,newlennewlen: int
) // O(1). Extend a byte slice range by `count` bytes up to the end of the byte slice. // A negative `count` shrinks the slice up to the empty slice. pub fun extendstd/core/bslice/extend: (bslice, count : int) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V, countcount: int : intstd/core/types/int: V )result: -> total bslice : bslicestd/core/bslice/bslice: V val totaltotal: int = bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int val newlennewlen: int = clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int( lenlen: int +std/core/int/(+): (x : int, y : int) -> int countcount: int, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, totaltotal: int -std/core/int/(-): (x : int, y : int) -> int startstart: int ) Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,newlennewlen: int
) // Truncates a slice to length 0 pub fun truncatestd/core/bslice/truncate: (bslice) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,_): bslicestd/core/bslice/bslice: V )result: -> total bslice: bslicestd/core/bslice/bslice: V Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) // O(1). Drop the first `n` bytes of the slice. Identity for `n<=0`. pub fun dropstd/core/bslice/drop: (bslice, n : int) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V, nn: int : intstd/core/types/int: V )result: -> total bslice : bslicestd/core/bslice/bslice: V val countcount: int = minstd/core/int/min: (i : int, j : int) -> int(nn: int,0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) val totaltotal: int = bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int val newstartnewstart: int = clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(startstart: int +std/core/int/(+): (x : int, y : int) -> int countcount: int, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, totaltotal: int) val newlennewlen: int = clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(lenlen: int -std/core/int/(-): (x : int, y : int) -> int countcount: int, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, totaltotal: int -std/core/int/(-): (x : int, y : int) -> int newstartnewstart: int) Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,newstartnewstart: int,newlennewlen: int
) // O(1). Take the first `n` bytes of the slice. pub fun takestd/core/bslice/take: (bslice, n : int) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V, nn: int : intstd/core/types/int: V )result: -> total bslice : bslicestd/core/bslice/bslice: V val newlennewlen: int = nn: int.clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,lenlen: int) Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,newlennewlen: int
) // O(1). Get a subslice of `len` bytes from `start` in a given byte slice. pub fun subslicestd/core/bslice/subslice: (bslice, start : int, len : int) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,bstartbstart: int,blenblen: int) : bslicestd/core/bslice/bslice: V, startstart: int : intstd/core/types/int: V, lenlen: int : intstd/core/types/int: V )result: -> total bslice : bslicestd/core/bslice/bslice: V val newstartnewstart: int = startstart: int.clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,blenblen: int) val newlennewlen: int = lenlen: int.clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,blenblen: int -std/core/int/(-): (x : int, y : int) -> int newstartnewstart: int) Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,bstartbstart: int +std/core/int/(+): (x : int, y : int) -> int newstartnewstart: int, newlennewlen: int
) // O(1). Return the byte slice from the start of the bytes up to the // start of the `slice` argument. pub fun beforestd/core/bslice/before: (bslice) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,_) : bslicestd/core/bslice/bslice: V )result: -> total bslice : bslicestd/core/bslice/bslice: V Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes, 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, startstart: int
) // O(1). Return the byte slice from the end of the `slice` argument // to the end of the byte array. pub fun afterstd/core/bslice/after: (bslice) -> bslice( Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int) : bslicestd/core/bslice/bslice: V )result: -> total bslice : bslicestd/core/bslice/bslice: V val newstartnewstart: int = startstart: int +std/core/int/(+): (x : int, y : int) -> int lenlen: int val newlennewlen: int = maxstd/core/int/max: (i : int, j : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int -std/core/int/(-): (x : int, y : int) -> int newstartnewstart: int) // assert: b.length - newstart >= 0 Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes, newstartnewstart: int, newlennewlen: int
) // Get's the byte at the offset `i` pub fun @index( ^(Bslicestd/core/bslice/Bslice: (backing-bytes : bytes, start : int, len : int) -> bslice(bb: bytes,startstart: int,lenlen: int)) : bslicestd/core/bslice/bslice: V, ii: int : intstd/core/types/int: V )result: -> exn int : exnstd/core/exn/exn: (E, V) -> V intstd/core/types/int: V if ii: int <std/core/int/(<): (x : int, y : int) -> exn bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
||std/core/types/(||): (x : bool, y : bool) -> exn bool ii: int >=std/core/int/(>=): (x : int, y : int) -> exn bool lenlen: int then throwstd/core/exn/throw: (message : string, info : ? exception-info) -> exn ()("index out of bounds"literal: string
count= 19
, ExnRangestd/core/exn/ExnRange: exception-info)std/core/types/Unit: () bb: bytes.unsafe-indexstd/core/bytes/unsafe-index: (b : bytes, i : ssize_t) -> exn uint8((startstart: int +std/core/int/(+): (x : int, y : int) -> exn int ii: int).ssize_tstd/core/int/ssize_t: (i : int) -> exn ssize_t).intstd/core/int/uint8/int: (i : uint8) -> exn int /* // Assigns the bytes starting at offset `i` to `new-value`, throws if there is not enough space or the index is invalid pub fun assign( b : bytes, i : int, new-value : bslice ) : exn bytes val l = b.length val size = new-value.len if i < 0 || i > l then throw("index out of bounds", ExnRange) elif size + i > l then throw("size overflow", ExnRange) else assign(b, i.ssize_t, new-value) extern slice/assign(b : bytes, i : ssize_t, new-value : bslice ): bytes c "kk_bslice_assign" */