diff --git a/mops.toml b/mops.toml index 59ecfed..a403194 100644 --- a/mops.toml +++ b/mops.toml @@ -3,20 +3,20 @@ name = "byte-utils" version = "0.1.2" license = "MIT" description = "A collection of utilities for byte manipulation and conversion." -keywords = ["encoding", "decoding", "conversion", "uleb128", "sleb128"] +keywords = [ "encoding", "decoding", "conversion", "uleb128", "sleb128" ] repository = "https://github.com/NatLabs/ByteUtils" [dependencies] -'base@0.14.13' = "0.14.13" -'xtended-numbers@2.0.0' = "2.0.0" +core = "2.1.0" +"xtended-numbers@2.3.0" = "2.3.0" [dev-dependencies] -test = "2.1.1" -bench = "1.0.0" +test = "2.1.2" +bench = "2.0.0" fuzz = "1.0.0" augmented-btrees = "0.7.1" itertools = "0.2.2" [toolchain] -moc = "0.14.13" +moc = "1.3.0" wasmtime = "33.0.1" diff --git a/src/lib.mo b/src/lib.mo index 0506fe4..f56546d 100644 --- a/src/lib.mo +++ b/src/lib.mo @@ -1,22 +1,21 @@ import Prim "mo:prim"; -import B "mo:base@0.14.13/Buffer"; -import Iter "mo:base@0.14.13/Iter"; -import Array "mo:base@0.14.13/Array"; -import Nat8 "mo:base@0.14.13/Nat8"; -import Nat16 "mo:base@0.14.13/Nat16"; -import Nat32 "mo:base@0.14.13/Nat32"; -import Nat64 "mo:base@0.14.13/Nat64"; -import Int8 "mo:base@0.14.13/Int8"; -import Int16 "mo:base@0.14.13/Int16"; -import Int32 "mo:base@0.14.13/Int32"; -import Int64 "mo:base@0.14.13/Int64"; -import Int "mo:base@0.14.13/Int"; -import Nat "mo:base@0.14.13/Nat"; -import Debug "mo:base@0.14.13/Debug"; -import BInterface "mo:buffer"; - -import FloatX "mo:xtended-numbers@2.0.0/FloatX"; +import Iter "mo:core/Iter"; +import Array "mo:core/Array"; +import List "mo:core/List"; +import Nat8 "mo:core/Nat8"; +import Nat16 "mo:core/Nat16"; +import Nat32 "mo:core/Nat32"; +import Nat64 "mo:core/Nat64"; +import Int8 "mo:core/Int8"; +import Int16 "mo:core/Int16"; +import Int32 "mo:core/Int32"; +import Int64 "mo:core/Int64"; +import Int "mo:core/Int"; +import Nat "mo:core/Nat"; +import Runtime "mo:core/Runtime"; + +import FloatX "mo:xtended-numbers@2.3.0/FloatX"; module ByteUtils { /// An iterator of bytes. @@ -25,7 +24,7 @@ module ByteUtils { func to_nat8(bytes : Bytes) : Nat8 { switch (bytes.next()) { case (?byte) { byte }; - case (_) { Debug.trap("ByteUtils: out of bounds") }; + case (_) { Runtime.trap("ByteUtils: out of bounds") }; }; }; @@ -36,6 +35,20 @@ module ByteUtils { size : () -> Nat; }; + class ListBuffer() { + let list = List.empty(); + public func size() : Nat = List.size(list); + public func add(elem : A) = List.add(list, elem); + public func get(i : Nat) : A { + switch (List.get(list, i)) { + case (?elem) elem; + case (null) Runtime.trap("ByteUtils: ListBuffer index out of bounds"); + }; + }; + public func put(i : Nat, elem : A) = List.put(list, i, elem); + public func toArray() : [A] = List.toArray(list); + }; + public type Functions = module { toNat8 : (Bytes) -> Nat8; toNat16 : (Bytes) -> Nat16; @@ -114,7 +127,7 @@ module ByteUtils { }; public func toFloat(bytes : Bytes) : Float { - let ?fx = FloatX.fromBytes(bytes, #f64, #lsb) else Debug.trap("ByteUtils: failed to decode Float"); + let ?fx = FloatX.fromBytes(bytes, #f64, #lsb) else Runtime.trap("ByteUtils: failed to decode Float"); FloatX.toFloat(fx); }; @@ -158,10 +171,10 @@ module ByteUtils { public func fromFloat(f : Float) : [Nat8] { let fx = FloatX.fromFloat(f, #f64); - let buffer = B.Buffer(8); + let buffer = ListBuffer(); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(buffer), fx, #lsb); - B.toArray(buffer); + FloatX.toBytesBuffer({ write = buffer.add }, fx, #lsb); + buffer.toArray(); }; }; @@ -219,7 +232,7 @@ module ByteUtils { }; public func toFloat(bytes : Bytes) : Float { - let ?fx = FloatX.fromBytes(bytes, #f64, #msb) else Debug.trap("ByteUtils: failed to decode Float"); + let ?fx = FloatX.fromBytes(bytes, #f64, #msb) else Runtime.trap("ByteUtils: failed to decode Float"); FloatX.toFloat(fx); }; @@ -263,10 +276,10 @@ module ByteUtils { public func fromFloat(f : Float) : [Nat8] { let fx = FloatX.fromFloat(f, #f64); - let buffer = B.Buffer(8); + let buffer = ListBuffer(); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(buffer), fx, #msb); - B.toArray(buffer); + FloatX.toBytesBuffer({ write = buffer.add }, fx, #msb); + buffer.toArray(); }; }; @@ -327,23 +340,23 @@ module ByteUtils { public func fromFloat(f : Float) : [Nat8] { // IEEE-754 sortable encoding let fx = FloatX.fromFloat(f, #f64); - let buffer = B.Buffer(8); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(buffer), fx, #msb); // Use big-endian + let buffer = ListBuffer(); + FloatX.toBytesBuffer({ write = buffer.add }, fx, #msb); // Use big-endian - let bytes = B.toArray(buffer); + let bytes = buffer.toArray(); if (f < 0.0) { // For negative numbers, flip all bits - Array.tabulate(buffer.size(), func(i : Nat) : Nat8 { ^(bytes.get(i)) }); + Array.tabulate(buffer.size(), func(i : Nat) : Nat8 { ^(bytes[i]) }); } else { // For positive numbers, flip only the sign bit Array.tabulate( buffer.size(), func(i : Nat) : Nat8 { if (i == 0) { - return bytes.get(i) ^ 0x80; // Flip sign bit only for first byte + return bytes[i] ^ 0x80; // Flip sign bit only for first byte } else { - return bytes.get(i); // Keep other bytes unchanged + return bytes[i]; // Keep other bytes unchanged }; }, ); @@ -447,7 +460,7 @@ module ByteUtils { ); }; - let ?fx = FloatX.fromBytes(decodedBytes.vals(), #f64, #msb) else Debug.trap("ByteUtils: failed to decode Float"); + let ?fx = FloatX.fromBytes(decodedBytes.vals(), #f64, #msb) else Runtime.trap("ByteUtils: failed to decode Float"); FloatX.toFloat(fx); }; }; @@ -457,60 +470,60 @@ module ByteUtils { /// Encodes a `Nat64` into ULEB128 format. public func toLEB128_64(n64 : Nat64) : [Nat8] { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); Buffer.addLEB128_64(buffer, n64); - B.toArray(buffer); + buffer.toArray(); }; /// Decodes a ULEB128-encoded `Nat64` from a byte iterator. /// Traps if end of buffer is reached before value is completely decoded. public func fromLEB128_64(bytes : Bytes) : Nat64 { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); for (byte in bytes) { buffer.add(byte) }; Buffer.readLEB128_64(buffer); }; /// Encodes a `Nat` into ULEB128 format. public func toLEB128(n : Nat) : [Nat8] { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); Buffer.addLEB128_nat(buffer, n); - B.toArray(buffer); + buffer.toArray(); }; /// Decodes a ULEB128-encoded `Nat` from a byte iterator. /// Traps if end of buffer is reached before value is completely decoded. public func fromLEB128(bytes : Bytes) : Nat { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); for (byte in bytes) { buffer.add(byte) }; Buffer.readLEB128_nat(buffer); }; /// Encodes an `Int64` into SLEB128 format. public func toSLEB128_64(n : Int64) : [Nat8] { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); Buffer.addSLEB128_64(buffer, n); - B.toArray(buffer); + buffer.toArray(); }; /// Decodes an SLEB128-encoded `Int64` from a byte iterator. /// Traps if end of buffer is reached before value is completely decoded. public func fromSLEB128_64(bytes : Bytes) : Int64 { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); for (byte in bytes) { buffer.add(byte) }; Buffer.readSLEB128_64(buffer); }; /// Encodes an `Int` into SLEB128 format. public func toSLEB128(n : Int) : [Nat8] { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); Buffer.addSLEB128_int(buffer, n); - B.toArray(buffer); + buffer.toArray(); }; /// Decodes an SLEB128-encoded `Int` from a byte iterator. /// Traps if end of buffer is reached before value is completely decoded. public func fromSLEB128(bytes : Bytes) : Int { - let buffer = B.Buffer(10); + let buffer = ListBuffer(); for (byte in bytes) { buffer.add(byte) }; Buffer.readSLEB128_int(buffer); }; @@ -572,9 +585,9 @@ module ByteUtils { addNat64(buffer, nat64); }; - public func addFloat(buffer : B.Buffer, f : Float) { + public func addFloat(buffer : BufferLike, f : Float) { let fx = FloatX.fromFloat(f, #f64); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(buffer), fx, #lsb); + FloatX.toBytesBuffer({ write = buffer.add }, fx, #lsb); }; // Add new write methods (write at specific offset) @@ -629,11 +642,11 @@ module ByteUtils { public func writeFloat(buffer : BufferLike, offset : Nat, f : Float) { let fx = FloatX.fromFloat(f, #f64); - let tempBuffer = B.Buffer(8); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(tempBuffer), fx, #lsb); + let tempBuffer = ListBuffer(); + FloatX.toBytesBuffer({ write = tempBuffer.add }, fx, #lsb); // Copy from temp buffer to target buffer at offset - for (i in Iter.range(0, 7)) { + for (i in Nat.range(0, 8)) { buffer.put(offset + i, tempBuffer.get(i)); }; }; @@ -742,9 +755,9 @@ module ByteUtils { addNat64(buffer, nat64); }; - public func addFloat(buffer : B.Buffer, f : Float) { + public func addFloat(buffer : BufferLike, f : Float) { let fx = FloatX.fromFloat(f, #f64); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(buffer), fx, #msb); + FloatX.toBytesBuffer({ write = buffer.add }, fx, #msb); }; // Add new write methods (write at specific offset) @@ -797,13 +810,13 @@ module ByteUtils { writeNat64(buffer, offset, nat64); }; - public func writeFloat(buffer : B.Buffer, offset : Nat, f : Float) { + public func writeFloat(buffer : BufferLike, offset : Nat, f : Float) { let fx = FloatX.fromFloat(f, #f64); - let tempBuffer = B.Buffer(8); - FloatX.toBytesBuffer(BInterface.fromDeprecatedBuffer(tempBuffer), fx, #msb); + let tempBuffer = ListBuffer(); + FloatX.toBytesBuffer({ write = tempBuffer.add }, fx, #msb); // Copy from temp buffer to target buffer at offset - for (i in Iter.range(0, 7)) { + for (i in Nat.range(0, 8)) { buffer.put(offset + i, tempBuffer.get(i)); }; }; @@ -912,63 +925,63 @@ module ByteUtils { // Write functions (at specific offset) public func writeNat8(buffer : BufferLike, offset : Nat, n : Nat8) { let bytes = ByteUtils.Sorted.fromNat8(n); - for (i in Iter.range(0, bytes.size() - 1)) { + for (i in Nat.range(0, bytes.size())) { buffer.put(offset + i, bytes[i]); }; }; public func writeNat16(buffer : BufferLike, offset : Nat, n : Nat16) { let bytes = ByteUtils.Sorted.fromNat16(n); - for (i in Iter.range(0, bytes.size() - 1)) { + for (i in Nat.range(0, bytes.size())) { buffer.put(offset + i, bytes[i]); }; }; public func writeNat32(buffer : BufferLike, offset : Nat, n : Nat32) { let bytes = ByteUtils.Sorted.fromNat32(n); - for (i in Iter.range(0, bytes.size() - 1)) { + for (i in Nat.range(0, bytes.size())) { buffer.put(offset + i, bytes[i]); }; }; public func writeNat64(buffer : BufferLike, offset : Nat, n : Nat64) { let bytes = ByteUtils.Sorted.fromNat64(n); - for (i in Iter.range(0, bytes.size() - 1)) { + for (i in Nat.range(0, bytes.size())) { buffer.put(offset + i, bytes[i]); }; }; public func writeInt8(buffer : BufferLike, offset : Nat, i : Int8) { let bytes = ByteUtils.Sorted.fromInt8(i); - for (j in Iter.range(0, bytes.size() - 1)) { + for (j in Nat.range(0, bytes.size())) { buffer.put(offset + j, bytes[j]); }; }; public func writeInt16(buffer : BufferLike, offset : Nat, i : Int16) { let bytes = ByteUtils.Sorted.fromInt16(i); - for (j in Iter.range(0, bytes.size() - 1)) { + for (j in Nat.range(0, bytes.size())) { buffer.put(offset + j, bytes[j]); }; }; public func writeInt32(buffer : BufferLike, offset : Nat, i : Int32) { let bytes = ByteUtils.Sorted.fromInt32(i); - for (j in Iter.range(0, bytes.size() - 1)) { + for (j in Nat.range(0, bytes.size())) { buffer.put(offset + j, bytes[j]); }; }; public func writeInt64(buffer : BufferLike, offset : Nat, i : Int64) { let bytes = ByteUtils.Sorted.fromInt64(i); - for (j in Iter.range(0, bytes.size() - 1)) { + for (j in Nat.range(0, bytes.size())) { buffer.put(offset + j, bytes[j]); }; }; - public func writeFloat(buffer : B.Buffer, offset : Nat, f : Float) { + public func writeFloat(buffer : BufferLike, offset : Nat, f : Float) { let bytes = ByteUtils.Sorted.fromFloat(f); - for (i in Iter.range(0, bytes.size() - 1)) { + for (i in Nat.range(0, bytes.size())) { buffer.put(offset + i, bytes[i]); }; }; @@ -1111,7 +1124,7 @@ module ByteUtils { // Determine if we need more bytes if ( (value == 0 and (byte & 0x40) == 0) or - (is_negative and value == Nat64.fromNat(Int.abs(Int64.toInt(Int64.maximumValue))) and (byte & 0x40) != 0) + (is_negative and value == Nat64.fromNat(Int.abs(Int64.toInt(Int64.maxValue))) and (byte & 0x40) != 0) ) { more := false; } else { @@ -1154,7 +1167,7 @@ module ByteUtils { // Determine if we need more bytes if ( (value == 0 and (byte & 0x40) == 0) or - (is_negative and value == Nat64.fromNat(Int.abs(Int64.toInt(Int64.maximumValue))) and (byte & 0x40) != 0) + (is_negative and value == Nat64.fromNat(Int.abs(Int64.toInt(Int64.maxValue))) and (byte & 0x40) != 0) ) { more := false; } else {