# Bytes — foundational byte-buffer for Bend. # Publish entry for this package. Depends only on Base (does not reimplement List). # # Encoding: newtype over List<&2, U32>, matching File.read_bytes payload. # Each element is a raw U32 "byte" (callers conventionally keep 0..255). # Quantity: Bytes is Data (U32 elements are Data / Kind(&2)). # # Does not duplicate Base List algorithms: wrappers specialize List ops to the # byte buffer type. Base has no Bytes type (bend base Bytes → missing). import Base type Bytes is Data: B{data: List<&2, U32>} # ---- constructors --------------------------------------------------------- def Bytes.empty() -> Bytes: B{Nil{}} def Bytes.singleton(+b: U32) -> Bytes: B{b <> Nil{}} def Bytes.from_list(xs: List<&2, U32>) -> Bytes: B{xs} def Bytes.to_list(bs: Bytes) -> List<&2, U32>: match bs: case B{xs}: xs # ---- queries / combinators (thin List facades) ---------------------------- def Bytes.length(bs: Bytes) -> Nat: match bs: case B{xs}: List.length(&2, U32, xs) def Bytes.append(xs: Bytes, ys: Bytes) -> Bytes: match xs ys: case B{a} B{b}: B{List.append(&2, U32, a, b)} def Bytes.reverse(bs: Bytes) -> Bytes: match bs: case B{xs}: B{List.reverse(&2, U32, xs)} def Bytes.get(bs: Bytes, n: Nat) -> Maybe<&2, U32>: match bs: case B{xs}: List.get(&2, U32, xs, n) # ---- equality ------------------------------------------------------------- def Bytes.eq.go(xs: List<&2, U32>, ys: List<&2, U32>) -> Bool: match xs ys: case Nil{} Nil{}: True{} case Nil{} _ <> _: False{} case _ <> _ Nil{}: False{} case x <> xt y <> yt: Bool.and(U32.is_eq(x, y), Bytes.eq.go(xt, yt)) def Bytes.eq(a: Bytes, b: Bytes) -> Bool: match a b: case B{xs} B{ys}: Bytes.eq.go(xs, ys) # ---- hex encode (small subset; nibble + byte + buffer) -------------------- # Digits 0..15 → '0'..'9' / 'a'..'f'. Byte encode uses the low 8 bits only. def Bytes.hex.digit(+n: U32) -> Char: Bool.pick(Char, U32.is_lt(n, 10), Chr{U32.add(48, n)}, Chr{U32.add(87, n)}) def Bytes.hex.byte(+b: U32) -> String: +lo8 = U32.and(b, 255) +hi = U32.div(lo8, 16) +lo = U32.mod(lo8, 16) SCon{Bytes.hex.digit(hi), SCon{Bytes.hex.digit(lo), SNil{}}} def Bytes.hex.go(xs: List<&2, U32>) -> String: match xs: case Nil{}: SNil{} case h <> t: String.append(Bytes.hex.byte(h), Bytes.hex.go(t)) def Bytes.hex(bs: Bytes) -> String: match bs: case B{xs}: Bytes.hex.go(xs)