/*---------------------------------------------------------------------------
  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 sequences.
module std/core/bytesstd/core/bytes

import std/core/typesstd/core/types
import std/core/exnstd/core/exn
import std/core/boolstd/core/bool
import std/core/intstd/core/int
import std/core/showstd/core/show
import std/core/vectorstd/core/vector
import std/core/stringstd/core/string
import std/core/liststd/core/list

extern import 
  js file "inline/bytes.js"

// Create a new empty array of bytes
extern prim-emptystd/core/bytes/prim-empty: () -> bytes() : bytesstd/core/types/bytes: V
  c  inline "kk_bytes_empty()"
  js inline "new Uint8Array(0)"

pub val emptystd/core/bytes/empty: bytes : bytesstd/core/types/bytes: V = prim-emptystd/core/bytes/prim-empty: () -> bytes()  

// Allocate a new zero initialized array of `n` bytes.
extern prim-bytesstd/core/bytes/prim-bytes: (n : ssize_t) -> bytes( nn: ssize_t : ssize_tstd/core/types/ssize_t: V ) : bytesstd/core/types/bytes: V
  c  inline "kk_bytes_zalloc_buf(#1, NULL, kk_context())"
  js inline "new Uint8Array(#1).fill(0)" 

// Allocate a array of `n` uninitialized bytes.
extern prim-unsafe-bytesstd/core/bytes/prim-unsafe-bytes: (n : ssize_t) -> bytes( nn: ssize_t : ssize_tstd/core/types/ssize_t: V ) : bytesstd/core/types/bytes: V
  c  inline "kk_bytes_alloc_buf(#1, NULL, kk_context())"
  js inline "new Uint8Array(#1)"

// Create `len` new zero-initialized bytes.
pub fun bytesstd/core/bytes/bytes: (len : int) -> bytes( lenlen: int : intstd/core/types/int: V )result: -> total bytes : bytesstd/core/types/bytes: V
  prim-bytesstd/core/bytes/prim-bytes: (n : ssize_t) -> bytes(lenlen: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t)  

// Create `len` uninitialized bytes.
pub fun unsafe-bytesstd/core/bytes/unsafe-bytes: (len : int) -> bytes( lenlen: int : intstd/core/types/int: V )result: -> total bytes : bytesstd/core/types/bytes: V
  prim-unsafe-bytesstd/core/bytes/prim-unsafe-bytes: (n : ssize_t) -> bytes(lenlen: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t)  


// Gets the length of the byte array
extern prim-lengthstd/core/bytes/prim-length: (b : bytes) -> ssize_t( ^bb: bytes : bytesstd/core/types/bytes: V ) : ssize_tstd/core/types/ssize_t: V
  c  "kk_bytes_len_borrow"
  js inline "#1.length"

// The count of bytes
pub fun lengthstd/core/bytes/length: (bs : bytes) -> int( bsbs: bytes : bytesstd/core/types/bytes: V )result: -> total int : intstd/core/types/int: V
  bsbs: bytes.prim-lengthstd/core/bytes/prim-length: (b : bytes) -> ssize_t.intstd/core/int/ssize_t/int: (i : ssize_t) -> int

// Are the bytes empty?
pub fun is-emptystd/core/bytes/is-empty: (bs : bytes) -> bool( bsbs: bytes : bytesstd/core/types/bytes: V )result: -> total bool : boolstd/core/types/bool: V
  bsbs: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int ==std/core/int/(==): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
// Adjusts the byte array to be the size of the `len` argument extern prim-adjust-lengthstd/core/bytes/prim-adjust-length: (b : bytes, len : ssize_t) -> bytes(bb: bytes: bytesstd/core/types/bytes: V, lenlen: ssize_t: ssize_tstd/core/types/ssize_t: V): bytesstd/core/types/bytes: V c "kk_bytes_adjust_length" js "kk_bytes_adjust_length" extern prim-appendstd/core/bytes/prim-append: (b1 : bytes, b2 : bytes) -> bytes(b1b1: bytes: bytesstd/core/types/bytes: V, b2b2: bytes: bytesstd/core/types/bytes: V): bytesstd/core/types/bytes: V c "kk_bytes_cat" js "kk_bytes_cat" extern prim-joinstd/core/bytes/prim-join: (bss : vector<bytes>) -> bytes(bssbss: vector<bytes> : vectorstd/core/types/vector: V -> V<bytesstd/core/types/bytes: V> ) : bytesstd/core/types/bytes: V c "kk_bytes_join" js "kk_bytes_join" // Concatenates two byte arrays pub fun (++)std/core/bytes/(++): (b1 : bytes, b2 : bytes) -> bytes(b1b1: bytes : bytesstd/core/types/bytes: V, b2b2: bytes: bytesstd/core/types/bytes: V)result: -> total bytes: bytesstd/core/types/bytes: V prim-appendstd/core/bytes/prim-append: (b1 : bytes, b2 : bytes) -> bytes(b1b1: bytes, b2b2: bytes) // Concatenate a vector of bytes pub fun vector/joinstd/core/bytes/vector/join: (bss : vector<bytes>) -> bytes(bssbss: vector<bytes> : vectorstd/core/types/vector: V -> V<bytesstd/core/types/bytes: V> )result: -> total bytes : bytesstd/core/types/bytes: V prim-joinstd/core/bytes/prim-join: (bss : vector<bytes>) -> bytes(bssbss: vector<bytes>) // Concatenate a list of bytes pub fun list/joinstd/core/bytes/list/join: (bss : list<bytes>) -> bytes(bssbss: list<bytes> : liststd/core/types/list: V -> V<bytesstd/core/types/bytes: V> )result: -> total bytes : bytesstd/core/types/bytes: V bssbss: list<bytes>.vectorstd/core/vector/list/vector: (xs : list<bytes>) -> vector<bytes>.joinstd/core/bytes/vector/join: (bss : vector<bytes>) -> bytes // Adjust the length of the bytes. If enlarged, the added bytes are initialized to zero. pub fun adjust-lengthstd/core/bytes/adjust-length: (bs : bytes, newlen : int) -> bytes( bsbs: bytes : bytesstd/core/types/bytes: V, newlennewlen: int : intstd/core/types/int: V )result: -> total bytes : bytesstd/core/types/bytes: V prim-adjust-lengthstd/core/bytes/prim-adjust-length: (b : bytes, len : ssize_t) -> bytes(bsbs: bytes,newlennewlen: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t) extern prim-subbytesstd/core/bytes/prim-subbytes: (bs : bytes, start : ssize_t, len : ssize_t) -> bytes(bsbs: bytes : bytesstd/core/types/bytes: V, startstart: ssize_t : ssize_tstd/core/types/ssize_t: V, lenlen: ssize_t : ssize_tstd/core/types/ssize_t: V ) : bytesstd/core/types/bytes: V c "kk_bytes_subbytes" js inline "#1.slice(#2,#3)" // Return a range of `len` bytes starting at `start`. // If `len < 0`, it copies all bytes from `start` to the end (`bs.length - start`). pub fun subbytesstd/core/bytes/subbytes: (bs : bytes, start : ? int, len : ? int) -> bytes( bsbs: bytes : bytesstd/core/types/bytes: V, startstart: ? int : intstd/core/types/int: V = 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, lenlen: ? int : intstd/core/types/int: V = -1literal: int
dec = -1
hex8 = 0xFF
bit8 = 0b11111111
)result: -> total bytes : bytesstd/core/types/bytes: V val totaltotal: int = bsbs: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int if startstart: int >=std/core/int/(>=): (x : int, y : int) -> bool totaltotal: int then returnreturn: bytes emptystd/core/bytes/empty: bytes val ofsofs: int = if startstart: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
else startstart: int val countcount: int = if lenlen: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
||std/core/types/(||): (x : bool, y : bool) -> bool ofsofs: int +std/core/int/(+): (x : int, y : int) -> int lenlen: int >std/core/int/(>): (x : int, y : int) -> bool totaltotal: int then totaltotal: int -std/core/int/(-): (x : int, y : int) -> int ofsofs: int else lenlen: int if countcount: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then returnreturn: bytes emptystd/core/bytes/empty: bytes prim-subbytesstd/core/bytes/prim-subbytes: (bs : bytes, start : ssize_t, len : ssize_t) -> bytes(bsbs: bytes,ofsofs: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t,countcount: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t
) // Converts bytes to a vector. // Individual bytes are interpreted as `:uint8` extern prim-subvectorstd/core/bytes/prim-subvector: (bytes : bytes, start : ssize_t, len : ssize_t) -> vector<int>( bytesbytes: bytes : bytesstd/core/types/bytes: V, startstart: ssize_t : ssize_tstd/core/types/ssize_t: V, lenlen: ssize_t : ssize_tstd/core/types/ssize_t: V ) : vectorstd/core/types/vector: V -> V<intstd/core/types/int: V> c "kk_bytes_subvector" js "kk_bytes_subvector" // Convert a range of bytes to vector of integers. // Individual bytes are interpreted as `:uint8` pub fun subvectorstd/core/bytes/subvector: (bytes : bytes, start : ? int, len : ? int) -> vector<int>( bytesbytes: bytes : bytesstd/core/types/bytes: V, startstart: ? int : intstd/core/types/int: V = 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, lenlen: ? int : intstd/core/types/int: V = -1literal: int
dec = -1
hex8 = 0xFF
bit8 = 0b11111111
)result: -> total vector<int> : vectorstd/core/types/vector: V -> V<intstd/core/types/int: V> val totaltotal: int = bytesbytes: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int if startstart: int >=std/core/int/(>=): (x : int, y : int) -> bool totaltotal: int then returnreturn: vector<int> emptystd/core/vector/empty: () -> vector<int>()std/core/types/Unit: () val ofsofs: int = maxstd/core/int/max: (i : int, j : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,startstart: int) val countcount: int = if lenlen: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
||std/core/types/(||): (x : bool, y : bool) -> bool ofsofs: int +std/core/int/(+): (x : int, y : int) -> int lenlen: int >std/core/int/(>): (x : int, y : int) -> bool totaltotal: int then totaltotal: int -std/core/int/(-): (x : int, y : int) -> int ofsofs: int else lenlen: int if countcount: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then emptystd/core/vector/empty: () -> vector<int>() else prim-subvectorstd/core/bytes/prim-subvector: (bytes : bytes, start : ssize_t, len : ssize_t) -> vector<int>(bytesbytes: bytes,ofsofs: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t,countcount: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t
) // Convert bytes to vector of integers (between 0 and 255). pub fun vectorstd/core/bytes/vector: (bytes : bytes) -> vector<int>( bytesbytes: bytes : bytesstd/core/types/bytes: V )result: -> total vector<int> : vectorstd/core/types/vector: V -> V<intstd/core/types/int: V> bytesbytes: bytes.subvectorstd/core/bytes/subvector: (bytes : bytes, start : ? int, len : ? int) -> vector<int>() // Convert bytes to a list of integers (between 0 and 255). pub fun liststd/core/bytes/list: (bytes : bytes) -> list<int>( bytesbytes: bytes : bytesstd/core/types/bytes: V )result: -> total list<int> : liststd/core/types/list: V -> V<intstd/core/types/int: V> bytesbytes: bytes.vectorstd/core/bytes/vector: (bytes : bytes) -> vector<int>.liststd/core/vector/list: (v : vector<int>) -> list<int> // Iterate through the bytes pub fun foreachstd/core/bytes/foreach: forall<e> (bytes : bytes, f : (int) -> e ()) -> e ()( bytesbytes: bytes : bytesstd/core/types/bytes: V, ff: (int) -> $567 () : (intstd/core/types/int: V) -> ee: E (std/core/types/unit: V)std/core/types/unit: V )result: -> 600 () : ee: E (std/core/types/unit: V)std/core/types/unit: V bytesbytes: bytes.vectorstd/core/bytes/vector: (bytes : bytes) -> $567 vector<int>.foreachstd/core/vector/foreach: (v : vector<int>, f : (int) -> $567 ()) -> $567 ()(ff: (int) -> $567 ()) // Show bytes as a hexadecimal sequence. pub fun showstd/core/bytes/show: (bytes : bytes) -> string( bytesbytes: bytes : bytesstd/core/types/bytes: V )result: -> total string : stringstd/core/types/string: V "["literal: string
count= 1
++std/core/types/(++): (x : string, y : string) -> string bytesbytes: bytes.vectorstd/core/bytes/vector: (bytes : bytes) -> vector<int>.mapstd/core/vector/map: (v : vector<int>, f : (int) -> string) -> vector<string>( fnfn: (i : int) -> string(ii: int) ii: int.show-hexstd/core/show/show-hex: (i : int, width : ? int, use-capitals : ? bool, pre : ? string) -> string(2literal: int
dec = 2
hex8 = 0x02
bit8 = 0b00000010
,pre=""literal: string
count= 0
) ).joinstd/core/string/vectorsep/join: (v : vector<string>, sep : string) -> string(" "literal: string
count= 1
) ++std/core/types/(++): (x : string, y : string) -> string "]"literal: string
count= 1
// Convert a vector of integers to bytes (by clamping between 0 and 255) pub extern vector/bytesstd/core/bytes/vector/bytes: (v : vector<int>) -> bytes( vv: vector<int> : vectorstd/core/types/vector: V -> V<intstd/core/types/int: V> ) : bytesstd/core/types/bytes: V c "kk_bytes_from_vector" js "kk_bytes_from_vector" // Convert a string to a sequence of utf-8 encoded bytes pub extern string/bytesstd/core/bytes/string/bytes: (s : string) -> bytes( ss: string : stringstd/core/types/string: V ) : bytesstd/core/types/bytes: V c inline "#1.bytes" js inline "(new TextEncoder()).encode(#1)" // Get's the byte at the offset `i`, without checking the offset is valid pub extern unsafe-indexstd/core/bytes/unsafe-index: (b : bytes, i : ssize_t) -> uint8( ^bb: bytes : bytesstd/core/types/bytes: V, ii: ssize_t : ssize_tstd/core/types/ssize_t: V ) : uint8std/core/types/uint8: V c "kk_bytes_at" js inline "#1[#2]" // Assigns the byte at offset `i` to `value`. Does not check the bounds! pub extern unsafe-assignstd/core/bytes/unsafe-assign: (b : bytes, i : ssize_t, value : uint8) -> bytes( bb: bytes : bytesstd/core/types/bytes: V, ii: ssize_t : ssize_tstd/core/types/ssize_t: V, valuevalue: uint8 : uint8std/core/types/uint8: V ) : bytesstd/core/types/bytes: V c "kk_bytes_set" js "kk_bytes_assign" // Get's the byte at the offset `i` pub fun @index( ^bb: bytes : bytesstd/core/types/bytes: 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 bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> exn 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(ii: int.ssize_tstd/core/int/ssize_t: (i : int) -> exn ssize_t).intstd/core/int/uint8/int: (i : uint8) -> exn int // Assign a (clamped) byte `value` at index `i`. Throws on out-of-bound. pub fun assignstd/core/bytes/assign: (bs : bytes, i : int, value : int) -> exn bytes( bsbs: bytes : bytesstd/core/types/bytes: V, ii: int : intstd/core/types/int: V, valuevalue: int : intstd/core/types/int: V )result: -> exn bytes : exnstd/core/exn/exn: (E, V) -> V bytesstd/core/types/bytes: 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 bsbs: bytes.lengthstd/core/bytes/length: (bs : bytes) -> exn 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: () bsbs: bytes.unsafe-assignstd/core/bytes/unsafe-assign: (b : bytes, i : ssize_t, value : uint8) -> exn bytes(ii: int.ssize_tstd/core/int/ssize_t: (i : int) -> exn ssize_t,valuevalue: int.uint8std/core/int/uint8: (i : int) -> exn uint8
) // Converts a sequence of qutf-8 bytes to a string. pub extern stringstd/core/bytes/string: (bytes : bytes) -> string( bytesbytes: bytes : bytesstd/core/types/bytes: V ) : stringstd/core/types/string: V c "kk_string_convert_from_qutf8" js "kk_string_from_bytes" extern prim-substringstd/core/bytes/prim-substring: (b : bytes, start : ssize_t, len : ssize_t) -> string( bb: bytes : bytesstd/core/types/bytes: V, startstart: ssize_t : ssize_tstd/core/types/ssize_t: V, lenlen: ssize_t : ssize_tstd/core/types/ssize_t: V ) : stringstd/core/types/string: V c "kk_string_convert_from_qutf8_slice" js "kk_bytes_substring" // Return a range of utf-8 encoded bytes as qutf-8 pub fun substringstd/core/bytes/substring: (b : bytes, start : ? int, len : ? int) -> string( bb: bytes : bytesstd/core/types/bytes: V, startstart: ? int : intstd/core/types/int: V = 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
, lenlen: ? int : intstd/core/types/int: V = -1literal: int
dec = -1
hex8 = 0xFF
bit8 = 0b11111111
)result: -> total string : stringstd/core/types/string: V val totaltotal: int = bb: bytes.lengthstd/core/bytes/length: (bs : bytes) -> int val ofsofs: int = startstart: int.clampstd/core/int/clamp: (i : int, lo : int, hi : int) -> int(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,totaltotal: int) val countcount: int = if lenlen: int <std/core/int/(<): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
||std/core/types/(||): (x : bool, y : bool) -> bool ofsofs: int +std/core/int/(+): (x : int, y : int) -> int lenlen: int >std/core/int/(>): (x : int, y : int) -> bool totaltotal: int then totaltotal: int -std/core/int/(-): (x : int, y : int) -> int ofsofs: int else lenlen: int if countcount: int <=std/core/int/(<=): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then ""literal: string
count= 0
else prim-substringstd/core/bytes/prim-substring: (b : bytes, start : ssize_t, len : ssize_t) -> string(bb: bytes,ofsofs: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t,lenlen: int.ssize_tstd/core/int/ssize_t: (i : int) -> ssize_t
) // Return initial `n<=3` utf-8 continuation bytes (`>=0x80`) extern utf8-partial-prestd/core/bytes/utf8-partial-pre: (b : bytes) -> ssize_t( ^bb: bytes : bytesstd/core/types/bytes: V ) : ssize_tstd/core/types/ssize_t: V c "kk_bytes_utf8_partial_pre_borrow" js "kk_bytes_utf8_partial_pre" // Return final `n<=3` bytes for an incomplete utf-8 code point encoding. extern utf8-partial-poststd/core/bytes/utf8-partial-post: (b : bytes) -> ssize_t( ^bb: bytes : bytesstd/core/types/bytes: V ) : ssize_tstd/core/types/ssize_t: V c "kk_bytes_utf8_partial_post_borrow" js "kk_bytes_utf8_partial_post" fun partial-stringsstd/core/bytes/partial-strings: (b : bytes, previous-post : ? bytes) -> (list<string>, bytes)( bb: bytes : bytesstd/core/types/bytes: V, previous-postprevious-post: ? bytes : bytesstd/core/types/bytes: V = emptystd/core/bytes/empty: bytes )result: -> total (list<string>, bytes) : (std/core/types/tuple2: (V, V) -> Vliststd/core/types/list: V -> V<stringstd/core/types/string: V>,bytesstd/core/types/bytes: V) val pre-lenpre-len: int = utf8-partial-prestd/core/bytes/utf8-partial-pre: (b : bytes) -> ssize_t(bb: bytes).intstd/core/int/ssize_t/int: (i : ssize_t) -> int val post-lenpost-len: int = utf8-partial-poststd/core/bytes/utf8-partial-post: (b : bytes) -> ssize_t(bb: bytes).intstd/core/int/ssize_t/int: (i : ssize_t) -> int val mid-lenmid-len: 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 pre-lenpre-len: int -std/core/int/(-): (x : int, y : int) -> int post-lenpost-len: int) val partialpartial: bytes = if pre-lenpre-len: int ==std/core/int/(==): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
then previous-postprevious-post: bytes else previous-postprevious-post: bytes ++std/core/bytes/(++): (b1 : bytes, b2 : bytes) -> bytes bb: bytes.subbytesstd/core/bytes/subbytes: (bs : bytes, start : ? int, len : ? int) -> bytes(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
,pre-lenpre-len: int) if (mid-lenmid-len: int ==std/core/int/(==): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
&&std/core/types/(&&): (x : bool, y : bool) -> bool post-lenpost-len: int ==std/core/int/(==): (x : int, y : int) -> bool 0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) then (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)[std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a>,partialpartial: bytes)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) else (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) (if partialpartial: bytes.is-emptystd/core/bytes/is-empty: (bs : bytes) -> bool() then [std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a> else [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>partialpartial: bytes.stringstd/core/bytes/string: (bytes : bytes) -> string]std/core/types/Nil: forall<a> list<a>) ++std/core/list/(++): (xs : list<string>, ys : list<string>) -> list<string> [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>bb: bytes.substringstd/core/bytes/substring: (b : bytes, start : ? int, len : ? int) -> string(pre-lenpre-len: int,mid-lenmid-len: int)]std/core/types/Nil: forall<a> list<a> , bb: bytes.subbytesstd/core/bytes/subbytes: (bs : bytes, start : ? int, len : ? int) -> bytes(pre-lenpre-len: int +std/core/int/(+): (x : int, y : int) -> int mid-lenmid-len: int, post-lenpost-len: int)
)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) // Convert a sequence of qutf-8 bytes to a string. Take a potential `previous-post` previous // uncompleted utf-8 code point (of at most 3 bytes) (in case the full byte sequence was split // over a utf-8 code point). Returns the qutf-8 decoded string and also potential left-over // bytes for a final uncompleted utf-8 code point (of at most 3 bytes). pub fun partial-stringstd/core/bytes/partial-string: (b : bytes, previous-post : ? bytes) -> (string, bytes)( bb: bytes : bytesstd/core/types/bytes: V, previous-postprevious-post: ? bytes : bytesstd/core/types/bytes: V = emptystd/core/bytes/empty: bytes )result: -> total (string, bytes) : (std/core/types/tuple2: (V, V) -> Vstringstd/core/types/string: V,bytesstd/core/types/bytes: V) val (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)partsparts: list<string>,postpost: bytes)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) = bb: bytes.partial-stringsstd/core/bytes/partial-strings: (b : bytes, previous-post : ? bytes) -> (list<string>, bytes)(previous-postprevious-post: bytes) (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)partsparts: list<string>.joinstd/core/list/concat/join: (xs : list<string>) -> string,postpost: bytes)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) // Join a list of utf-8 bytes into a string. // Ensures that utf-8 sequences that are split over different bytes are handled correctly. pub fun list/stringstd/core/bytes/list/string: (bs : list<bytes>) -> string( bsbs: list<bytes> : liststd/core/types/list: V -> V<bytesstd/core/types/bytes: V> )result: -> total string : stringstd/core/types/string: V tail fun collectcollect: (previous-post : bytes, xs : list<bytes>) -> list<list<string>>( previous-postprevious-post: bytes : bytesstd/core/types/bytes: V, xsxs: list<bytes> : liststd/core/types/list: V -> V<bytesstd/core/types/bytes: V> )result: -> total list<list<string>> : liststd/core/types/list: V -> V<liststd/core/types/list: V -> V<stringstd/core/types/string: V>> match xsxs: list<bytes> Nilstd/core/types/Nil: forall<a> list<a> -> [std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>[std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>previous-postprevious-post: bytes.stringstd/core/bytes/string: (bytes : bytes) -> string]std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(bb: bytes,bbbb: list<bytes>) -> val (std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b)partpart: list<string>,postpost: bytes)std/core/types/Tuple2: forall<a,b> (fst : a, snd : b) -> (a, b) = bb: bytes.partial-stringsstd/core/bytes/partial-strings: (b : bytes, previous-post : ? bytes) -> (list<string>, bytes)(previous-postprevious-post: bytes) Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(partpart: list<string>,collectcollect: (previous-post : bytes, xs : list<bytes>) -> list<list<string>>(postpost: bytes,bbbb: list<bytes>)) collectcollect: (previous-post : bytes, xs : list<bytes>) -> list<list<string>>(emptystd/core/bytes/empty: bytes,bsbs: list<bytes>).concatstd/core/list/concat: (xss : list<list<string>>) -> list<string>.joinstd/core/list/concat/join: (xs : list<string>) -> string