diff --git a/builtin/bitstring.mbt b/builtin/bitstring.mbt index f37a41d41..5f9c74103 100644 --- a/builtin/bitstring.mbt +++ b/builtin/bitstring.mbt @@ -557,3 +557,445 @@ pub fn FixedArray::unsafe_extract_bytesview( ) -> ArrayView[Byte] { bs[:].unsafe_extract_bytesview(offset, len) } + +//-------------------------------- +// BytesView +//-------------------------------- + +///| +/// Extract a single bit. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_bit( + bs : BytesView, + offset : Int, + _len : Int, +) -> UInt { + let byte_index = offset >> 3 + let bit_shift = 7 - (offset & 7) + let byte_val = bs.unsafe_get(byte_index).to_uint() + (byte_val >> bit_shift) & 1U +} + +///| +/// Extract a single bit. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_bit_signed( + bs : BytesView, + offset : Int, + _len : Int, +) -> Int { + let byte_index = offset >> 3 + let bit_shift = 7 - (offset & 7) + let byte_val = bs.unsafe_get(byte_index).to_int() + // Extract bit and convert to signed: 0 -> 0, 1 -> -1 + ((byte_val >> bit_shift) & 1) * -1 +} + +///| +/// Extract [2..8] bits. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_byte( + bs : BytesView, + offset : Int, + len : Int, +) -> UInt { + let byte_index = offset >> 3 + if (offset & 7) == 0 { + // byte-aligned case + let byte = bs.unsafe_get(byte_index) + (byte >> (8 - len)).to_uint() + } else if (offset & 7) + len <= 8 { + // All bits are within the same byte - no need to read next byte + let byte = bs.unsafe_get(byte_index).to_uint() + let shift = 8 - ((offset & 7) + len) + let mask = (1U << len) - 1 + (byte >> shift) & mask + } else { + // extract 16 bits at [byte_index, byte_index + 1] + let b0 = bs.unsafe_get(byte_index).to_uint() + let b1 = bs.unsafe_get(byte_index + 1).to_uint() + let data = (b0 << 8) | b1 + // mask off the top bits + let bit_mask = (1U << (16 - (offset & 7))) - 1 + let data = data & bit_mask + let shift = 16 - ((offset & 7) + len) + data >> shift + } +} + +///| +/// Extract [9..32] bits in little-endian byte order. +/// +/// # Invariants +/// - It's guaranteed to have at least 2 bytes available for extraction +/// - Only reads the necessary number of bytes based on the bit length +/// +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_uint_le( + bs : BytesView, + offset : Int, + len : Int, +) -> UInt { + let bytes_needed = (len + 7) / 8 + // TODO: add fast path for aligned case + // non-aligned case: extract bytes using unsafe_extract_byte + let b0 = bs.unsafe_extract_byte(offset, 8) + match bytes_needed { + 2 => { + let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) + (b1 << 8) | b0 + } + 3 => { + let b1 = bs.unsafe_extract_byte(offset + 8, 8) + let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) + (b2 << 16) | (b1 << 8) | b0 + } + 4 => { + let b1 = bs.unsafe_extract_byte(offset + 8, 8) + let b2 = bs.unsafe_extract_byte(offset + 16, 8) + let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) + (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + } + _ => abort("Invalid byte count for int32 extraction") + } +} + +///| +/// Extract [9..32] bits in big-endian byte order. +/// +/// # Invariants +/// - It's guaranteed to have at least 2 bytes available for extraction +/// - Only reads the necessary number of bytes based on the bit length +/// +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_uint_be( + bs : BytesView, + offset : Int, + len : Int, +) -> UInt { + let bytes_needed = (len + 7) / 8 + // TODO: add fast path for aligned case + // non-aligned case: extract bytes using unsafe_extract_byte + let b0 = bs.unsafe_extract_byte(offset, 8) + match bytes_needed { + 2 => { + let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) + let shift = 16 - len + let data = (b0 << 8) | (b1 << shift) + data >> shift + } + 3 => { + let b1 = bs.unsafe_extract_byte(offset + 8, 8) + let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) + let shift = 24 - len + let data = (b0 << 16) | (b1 << 8) | (b2 << shift) + data >> shift + } + 4 => { + let b1 = bs.unsafe_extract_byte(offset + 8, 8) + let b2 = bs.unsafe_extract_byte(offset + 16, 8) + let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) + let shift = 32 - len + let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift) + data >> shift + } + _ => abort("Invalid byte count for int32 extraction") + } +} + +///| +/// Extract [33..64] bits in little-endian byte order. +/// +/// # Invariants +/// - It's guaranteed to have at least 5 bytes available for extraction +/// - Only reads the necessary number of bytes based on the bit length (5-8 bytes) +/// - For bit lengths < 33, use unsafe_extract_int_le instead +/// +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_uint64_le( + bs : BytesView, + offset : Int, + len : Int, +) -> UInt64 { + let bytes_needed = (len + 7) / 8 + // TODO: add fast path for aligned case + // non-aligned case: extract bytes using unsafe_extract_byte + let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() + let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() + let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() + let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() + match bytes_needed { + 5 => { + let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() + (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + } + 6 => { + let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() + (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 + } + 7 => { + let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() + (b6 << 48) | + (b5 << 40) | + (b4 << 32) | + (b3 << 24) | + (b2 << 16) | + (b1 << 8) | + b0 + } + 8 => { + let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() + let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() + (b7 << 56) | + (b6 << 48) | + (b5 << 40) | + (b4 << 32) | + (b3 << 24) | + (b2 << 16) | + (b1 << 8) | + b0 + } + _ => abort("Invalid byte count for int64 extraction") + } +} + +///| +/// Extract [33..64] bits in big-endian byte order. +/// +/// # Invariants +/// - It's guaranteed to have at least 5 bytes available for extraction +/// - Only reads the necessary number of bytes based on the bit length (5-8 bytes) +/// - For bit lengths < 33, use unsafe_extract_int_be instead +/// +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_uint64_be( + bs : BytesView, + offset : Int, + len : Int, +) -> UInt64 { + let bytes_needed = (len + 7) / 8 + // TODO: add fast path for aligned case + // non-aligned case: extract bytes using unsafe_extract_byte + let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() + let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() + let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() + let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() + match bytes_needed { + 5 => { + let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() + let shift = 40 - len + let data = (b0 << 32) | + (b1 << 24) | + (b2 << 16) | + (b3 << 8) | + (b4 << shift) + data >> shift + } + 6 => { + let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() + let shift = 48 - len + let data = (b0 << 40) | + (b1 << 32) | + (b2 << 24) | + (b3 << 16) | + (b4 << 8) | + (b5 << shift) + data >> shift + } + 7 => { + let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() + let shift = 56 - len + let data = (b0 << 48) | + (b1 << 40) | + (b2 << 32) | + (b3 << 24) | + (b4 << 16) | + (b5 << 8) | + (b6 << shift) + data >> shift + } + 8 => { + let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() + let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() + let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() + let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() + let shift = 64 - len + let data = (b0 << 56) | + (b1 << 48) | + (b2 << 40) | + (b3 << 32) | + (b4 << 24) | + (b5 << 16) | + (b6 << 8) | + (b7 << shift) + data >> shift + } + _ => abort("Invalid byte count for int64 extraction") + } +} + +///| +/// Extract a subview from a view. `offset` and `len` are in bits and must be +/// aligned to bytes. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_bytesview( + bs : BytesView, + offset : Int, + len : Int, +) -> BytesView { + BytesView::make(bs.bytes(), bs.start() + (offset >> 3), len >> 3) +} + +///| +/// Extract [2..8] bits as a signed integer. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_byte_signed( + bs : BytesView, + offset : Int, + len : Int, +) -> Int { + let unsigned = bs.unsafe_extract_byte(offset, len) + unsigned.extend_sign(len) +} + +///| +/// Extract [9..32] bits as a signed integer. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_int_le( + bs : BytesView, + offset : Int, + len : Int, +) -> Int { + let unsigned = bs.unsafe_extract_uint_le(offset, len) + unsigned.extend_sign(len) +} + +///| +/// Extract [9..32] bits as a signed integer. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_int_be( + bs : BytesView, + offset : Int, + len : Int, +) -> Int { + let unsigned = bs.unsafe_extract_uint_be(offset, len) + unsigned.extend_sign(len) +} + +///| +/// Extract [33..64] bits as a signed integer. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_int64_le( + bs : BytesView, + offset : Int, + len : Int, +) -> Int64 { + let unsigned = bs.unsafe_extract_uint64_le(offset, len) + unsigned.extend_sign(len) +} + +///| +/// Extract [33..64] bits as a signed integer. +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn BytesView::unsafe_extract_int64_be( + bs : BytesView, + offset : Int, + len : Int, +) -> Int64 { + let unsigned = bs.unsafe_extract_uint64_be(offset, len) + unsigned.extend_sign(len) +} + +//-------------------------------- +// Bytes +//-------------------------------- + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_bit(bs : Bytes, offset : Int, len : Int) -> UInt { + bs[:].unsafe_extract_bit(offset, len) +} + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_byte(bs : Bytes, offset : Int, len : Int) -> UInt { + bs[:].unsafe_extract_byte(offset, len) +} + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_uint_le( + bs : Bytes, + offset : Int, + len : Int, +) -> UInt { + bs[:].unsafe_extract_uint_le(offset, len) +} + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_uint_be( + bs : Bytes, + offset : Int, + len : Int, +) -> UInt { + bs[:].unsafe_extract_uint_be(offset, len) +} + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_uint64_le( + bs : Bytes, + offset : Int, + len : Int, +) -> UInt64 { + bs[:].unsafe_extract_uint64_le(offset, len) +} + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_uint64_be( + bs : Bytes, + offset : Int, + len : Int, +) -> UInt64 { + bs[:].unsafe_extract_uint64_be(offset, len) +} + +///| +#internal(experimental, "subject to breaking change without notice") +#doc(hidden) +pub fn Bytes::unsafe_extract_bytesview( + bs : Bytes, + offset : Int, + len : Int, +) -> BytesView { + bs[:].unsafe_extract_bytesview(offset, len) +} diff --git a/builtin/byte.mbt b/builtin/byte.mbt index a54cb73d7..129018120 100644 --- a/builtin/byte.mbt +++ b/builtin/byte.mbt @@ -277,6 +277,48 @@ pub fn Byte::to_uint(self : Byte) -> UInt { self.to_int().reinterpret_as_uint() } +///| +/// Converts a byte value to an unsigned 64-bit integer. +/// +/// Parameters: +/// +/// * `byte` : The byte value to be converted. +/// +/// Returns an unsigned 64-bit integer representation of the byte value. +/// +/// Example: +/// +/// ```mbt test +/// let b = b'\xFF' +/// inspect(b.to_uint64(), content="255") +/// ``` +pub fn Byte::to_uint64(self : Byte) -> UInt64 { + self.to_uint().to_uint64() +} + +///| +/// Counts the number of 1-bits (population count) in the byte using bitwise operations. +/// +/// Parameters: +/// +/// * `self` : The byte value whose 1-bits are to be counted. +/// +/// Returns the number of 1-bits in the byte. +/// +/// Example: +/// +/// ```mbt test +/// let b = b'\x0F' +/// inspect(b.popcnt(), content="4") +/// ``` +pub fn Byte::popcnt(self : Byte) -> Int { + let mut n = self + n = (n & 0x55) + ((n >> 1) & 0x55) + n = (n & 0x33) + ((n >> 2) & 0x33) + n = (n & 0x0F) + ((n >> 4) & 0x0F) + n.to_int() +} + ///| /// Shifts the bits of the `Byte` value to the left by the specified number of /// positions. diff --git a/builtin/bytes.mbt b/builtin/bytes.mbt index 1b3e7da52..9c7180055 100644 --- a/builtin/bytes.mbt +++ b/builtin/bytes.mbt @@ -403,13 +403,459 @@ pub impl Compare for Bytes with compare(self, other) { } } -// intrinsics for bytesview +///| +/// Creates a new bytes sequence from a byte array. +/// +/// Parameters: +/// +/// * `array` : An array of bytes to be converted. +/// +/// Returns a new bytes sequence containing the same bytes as the input array. +/// +/// Example: +/// +/// ```mbt test +/// let arr = [b'h', b'i'] +/// let bytes = Bytes::from_array(arr) +/// inspect( +/// bytes, +/// content=( +/// #|b"hi" +/// ), +/// ) +/// ``` +#as_free_fn(deprecated) +#alias(of, deprecated="Use from_array instead") +#as_free_fn(of, deprecated="Use from_array instead") +pub fn Bytes::from_array(arr : ArrayView[Byte]) -> Bytes { + Bytes::makei(arr.length(), i => arr[i]) +} + +///| +/// Creates a new bytes sequence from a fixed-size array of bytes with an +/// optional length parameter. +/// +/// Parameters: +/// +/// * `array` : A fixed-size array of bytes to be converted into a bytes +/// sequence. +/// * `length` : (Optional) The length of the resulting bytes sequence. If not +/// provided, uses the full length of the input array. +/// +/// Returns a new bytes sequence containing the bytes from the input array. If a +/// length is specified, only includes up to that many bytes. +/// +/// Example: +/// +/// ```mbt test +/// let arr : FixedArray[Byte] = [b'h', b'e', b'l', b'l', b'o'] +/// let bytes = Bytes::from_array(arr[0:3]) +/// inspect( +/// bytes, +/// content=( +/// #|b"hel" +/// ), +/// ) +/// ``` +/// +/// Panics if the length is invalid +#as_free_fn(deprecated) +#deprecated("Use Bytes::from_array instead") +pub fn Bytes::from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { + let len = match len { + None => arr.length() + Some(x) => { + guard 0 <= x && x <= arr.length() + x + } + } + let result = unsafe_to_fixedarray(UninitializedArray::make(len)) + arr.blit_to(result, len~) + result.unsafe_reinterpret_as_bytes() +} + +///| +/// Converts a bytes sequence into a fixed-size array of bytes. If an optional +/// length is provided, the resulting array will have exactly that length, +/// otherwise it will match the length of the input bytes. +/// +/// Parameters: +/// +/// * `self` : The bytes sequence to convert. +/// * `len` : Optional. The desired length of the output array. If specified, the +/// resulting array will have this length. If not specified, the length of the +/// input bytes sequence will be used. +/// +/// Returns a fixed-size array containing the bytes from the input sequence. +/// +/// Example: +/// +/// ```mbt test +/// let bytes = b"hello" +/// let arr = bytes.to_fixedarray() +/// inspect(arr, content="[b'\\x68', b'\\x65', b'\\x6C', b'\\x6C', b'\\x6F']") +/// let arr2 = bytes[:3].to_fixedarray() +/// inspect(arr2, content="[b'\\x68', b'\\x65', b'\\x6C']") +/// ``` +/// +/// Panics if the length is invalid +#label_migration(len, fill=false) +pub fn Bytes::to_fixedarray(self : Bytes, len? : Int) -> FixedArray[Byte] { + let len = match len { + None => self.length() + Some(x) => { + guard 0 <= x && x <= self.length() + x + } + } + let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) + arr.blit_from_bytes(0, self, 0, len) + arr +} + +///| +pub fn BytesView::to_fixedarray(self : BytesView) -> FixedArray[Byte] { + let len = self.length() + let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) + arr.blit_from_bytes(0, self.data(), self.start_offset(), len) + arr +} + +///| +/// Creates a new bytes sequence from an iterator of bytes. +/// +/// Parameters: +/// +/// * `iterator` : An iterator that yields bytes. +/// +/// Returns a new bytes sequence containing all the bytes from the iterator. +/// +/// Example: +/// +/// ```mbt test +/// let iter = Iter::singleton(b'h') +/// let bytes = Bytes::from_iter(iter) +/// inspect( +/// bytes, +/// content=( +/// #|b"h" +/// ), +/// ) +/// ``` +#as_free_fn(deprecated) +pub fn Bytes::from_iter(iter : Iter[Byte]) -> Bytes { + Bytes::from_array(iter.collect()) +} + +///| +/// Creates a new bytes sequence from an iterator of bytes. +/// +/// Parameters: +/// +/// * `iterator` : An iterator that yields bytes. +/// +/// Returns a new bytes sequence containing all the bytes from the iterator. +/// +/// Example: +/// +/// ```mbt test +/// let iter = Iterator::singleton(b'h') +/// let bytes = Bytes::from_iterator(iter) +/// inspect( +/// bytes, +/// content=( +/// #|b"h" +/// ), +/// ) +/// ``` +#as_free_fn(deprecated) +pub fn Bytes::from_iterator(iter : Iterator[Byte]) -> Bytes { + Bytes::from_array(iter.collect()) +} + +///| +/// Creates a new bytes sequence from a fixed-size byte array. +/// +/// Parameters: +/// +/// * `array` : A fixed-size array of bytes to be converted into a bytes +/// sequence. Elements in the array should be of type `Byte`. +/// +/// Returns a new bytes sequence containing the same bytes as the input array. +/// +/// Example: +/// +/// ```mbt test +/// let arr : FixedArray[Byte] = [b'h', b'e', b'l', b'l', b'o'] +/// let bytes = Bytes::of(arr) +/// inspect( +/// bytes, +/// content=( +/// +/// #|b"hello" +/// +/// ), +/// ) +/// ``` +/// TODO: marked as intrinsic, inline if it is constant + +///| +/// Converts a bytes sequence into an array of bytes. +/// +/// Parameters: +/// +/// * `bytes` : A sequence of bytes to be converted into an array. +/// +/// Returns an array containing the same bytes as the input sequence. +/// +/// Example: +/// +/// ```mbt test +/// let bytes = b"hello" +/// let arr = bytes.to_array() +/// inspect(arr, content="[b'\\x68', b'\\x65', b'\\x6C', b'\\x6C', b'\\x6F']") +/// ``` +pub fn Bytes::to_array(self : Bytes) -> Array[Byte] { + let len = self.length() + let rv = Array::make(len, b'0') + for i in 0.. Array[Byte] { + let len = self.length() + let rv = Array::make(len, b'0') + for i in 0.. sum = sum + b.to_int()) +/// inspect(sum, content="209") // ASCII values: 'h'(104) + 'i'(105) = 209 +/// ``` +pub fn Bytes::iter(self : Bytes) -> Iter[Byte] { + Iter::new(yield_ => for i in 0.. sum = sum + b.to_int()) +/// inspect(sum, content="209") // ASCII values: 'h'(104) + 'i'(105) = 209 +/// ``` +pub fn Bytes::iterator(self : Bytes) -> Iterator[Byte] { + let mut i = 0 + let len = self.length() + Iterator::new(fn() { + guard i < len else { None } + let c = self.unsafe_get(i) + i += 1 + Some(c) + }) +} + +///| +/// Creates an iterator that yields tuples of index and byte, +/// indices start from 0. +/// +/// Example: +/// let buf = StringBuilder::new(size_hint=5) +/// let keys = [] +/// b"abcde".iter2().each((i, x) => { +/// buf.write_string(x.to_string()) +/// keys.push( i ) +/// }) +/// inspect(buf, content="b'\\x61'b'\\x62'b'\\x63'b'\\x64'b'\\x65'") +/// inspect(keys, content="[0, 1, 2, 3, 4]") +pub fn Bytes::iter2(self : Bytes) -> Iter2[Int, Byte] { + Iter2::new(yield_ => for i in 0.. Iterator2[Int, Byte] { + let mut i = 0 + let len = self.length() + Iterator::new(fn() { + guard i < len else { None } + let result = (i, self.unsafe_get(i)) + i += 1 + Some(result) + }) +} ///| -fn BytesView::len(self : BytesView) -> Int = "%bytesview.len" +/// Creates a new empty bytes sequence. +/// +/// Returns an empty bytes sequence. +/// +/// Example: +/// +/// ```mbt test +/// let bytes = Bytes::default() +/// inspect(bytes, content="b\"\"") +/// inspect(bytes.length(), content="0") +/// ``` +pub impl Default for Bytes with default() { + b"" +} ///| -fn BytesView::bytes(self : BytesView) -> Bytes = "%bytesview.bytes" +/// Retrieves a byte from the view at the specified index. +/// +/// Parameters: +/// +/// * `self` : The bytes view to retrieve the byte from. +/// * `index` : The position in the view from which to retrieve the byte. +/// +/// Returns the byte at the specified index, or None if the index is out of bounds. +/// +/// Example: +/// +/// ```mbt test +/// let bytes = b"\x01\x02\x03" +/// let byte = bytes.get(1) +/// inspect(byte, content="Some(b'\\x02')") +/// let bytes = b"\x01\x02\x03" +/// let byte = bytes.get(3) +/// inspect(byte, content="None") +/// ``` +pub fn Bytes::get(self : Bytes, index : Int) -> Byte? { + guard index >= 0 && index < self.length() else { None } + Some(self[index]) +} + +///| +fn unsafe_to_fixedarray(array : UninitializedArray[Byte]) -> FixedArray[Byte] = "%identity" ///| -fn BytesView::start(self : BytesView) -> Int = "%bytesview.start" +/// Concatenates two bytes sequences. +/// +/// Parameters: +/// +/// * `self` : The first bytes sequence. +/// * `other` : The second bytes sequence. +/// TODO: marked as intrinsic, inline if it is constant +pub impl Add for Bytes with add(self : Bytes, other : Bytes) -> Bytes { + let len_self = self.length() + let len_other = other.length() + let rv : FixedArray[Byte] = FixedArray::make(len_self + len_other, 0) + for i in 0.. Bytes { + if count <= 0 || self.length() == 0 { + return [] + } + if count == 1 { + return self + } + let len = self.length() + let total = len * count + // (Optional) detect overflow: if multiplication wrapped (best-effort) + guard total / count == len + let arr = FixedArray::make(total, (0 : Byte)) + arr.blit_from_bytes(0, self, 0, len) + let mut filled = len + while filled < total { + let remaining = total - filled + let copy_len = if filled < remaining { filled } else { remaining } + let src = unsafe_to_bytes(arr) + arr.blit_from_bytes(filled, src, 0, copy_len) + filled = filled + copy_len + } + unsafe_to_bytes(arr) +} diff --git a/bytes/methods.mbt b/builtin/bytes_find.mbt similarity index 100% rename from bytes/methods.mbt rename to builtin/bytes_find.mbt diff --git a/builtin/bytes_unsafe.mbt b/builtin/bytes_unsafe.mbt index 44ea1f03b..fddac9066 100644 --- a/builtin/bytes_unsafe.mbt +++ b/builtin/bytes_unsafe.mbt @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// #region FixedArray + ///| /// **UNSAFE**: Writes a UInt64 to the FixedArray[Byte] in little-endian byte order. /// @@ -205,3 +207,328 @@ pub fn FixedArray::unsafe_write_uint16_be( bytes.unsafe_set(i + index, (value >> (8 * (1 - i))).to_byte()) } } + +// #endregion +// #region Bytes + +///| +/// **UNSAFE**: Reads a UInt64 from the bytes in little-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory +/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures +/// - **Responsibility**: Caller must ensure sufficient bytes are available +/// +/// # Parameters +/// - `bytes`: The Bytes to read from +/// - `index`: Starting byte index (0-based) +/// +/// # Behavior +/// Reads 8 bytes starting at `index` and interprets them as a UInt64 in little-endian order: +/// - `bytes[index]` → bits 0-7 (least significant) +/// - `bytes[index+1]` → bits 8-15 +/// - ... +/// - `bytes[index+7]` → bits 56-63 (most significant) +#intrinsic("%bytes.unsafe_read_uint64_le") +#doc(hidden) +pub fn Bytes::unsafe_read_uint64_le(bytes : Bytes, index : Int) -> UInt64 { + let mut result : UInt64 = 0 + for i in 0..=7 { + result = result | (bytes.unsafe_get(i + index).to_uint64() << (8 * i)) + } + result +} + +///| +/// **UNSAFE**: Reads a UInt64 from the bytes in big-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory +/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures +/// - **Responsibility**: Caller must ensure sufficient bytes are available +/// +/// # Parameters +/// - `bytes`: The Bytes to read from +/// - `index`: Starting byte index (0-based) +/// +/// # Behavior +/// Reads 8 bytes starting at `index` and interprets them as a UInt64 in big-endian order: +/// - `bytes[index]` → bits 56-63 (most significant) +/// - `bytes[index+1]` → bits 48-55 +/// - ... +/// - `bytes[index+7]` → bits 0-7 (least significant) +#intrinsic("%bytes.unsafe_read_uint64_be") +#doc(hidden) +pub fn Bytes::unsafe_read_uint64_be(bytes : Bytes, index : Int) -> UInt64 { + let mut result : UInt64 = 0 + for i in 0..=7 { + result = result | (bytes.unsafe_get(i + index).to_uint64() << (8 * (7 - i))) + } + result +} + +///| +/// **UNSAFE**: Reads a UInt32 from the bytes in little-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory +/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures +/// - **Responsibility**: Caller must ensure sufficient bytes are available +/// +/// # Parameters +/// - `bytes`: The Bytes to read from +/// - `index`: Starting byte index (0-based) +/// +/// # Behavior +/// Reads 4 bytes starting at `index` and interprets them as a UInt32 in little-endian order: +/// - `bytes[index]` → bits 0-7 (least significant) +/// - `bytes[index+1]` → bits 8-15 +/// - `bytes[index+2]` → bits 16-23 +/// - `bytes[index+3]` → bits 24-31 (most significant) +#intrinsic("%bytes.unsafe_read_uint32_le") +#doc(hidden) +pub fn Bytes::unsafe_read_uint32_le(bytes : Bytes, index : Int) -> UInt { + let mut result : UInt = 0 + for i in 0..=3 { + result = result | (bytes.unsafe_get(i + index).to_uint() << (8 * i)) + } + result +} + +///| +/// **UNSAFE**: Reads a UInt32 from the bytes in big-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory +/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures +/// - **Responsibility**: Caller must ensure sufficient bytes are available +/// +/// # Parameters +/// - `bytes`: The Bytes to read from +/// - `index`: Starting byte index (0-based) +/// +/// # Behavior +/// Reads 4 bytes starting at `index` and interprets them as a UInt32 in big-endian order: +/// - `bytes[index]` → bits 24-31 (most significant) +/// - `bytes[index+1]` → bits 16-23 +/// - `bytes[index+2]` → bits 8-15 +/// - `bytes[index+3]` → bits 0-7 (least significant) +#intrinsic("%bytes.unsafe_read_uint32_be") +#doc(hidden) +pub fn Bytes::unsafe_read_uint32_be(bytes : Bytes, index : Int) -> UInt { + let mut result : UInt = 0 + for i in 0..=3 { + result = result | (bytes.unsafe_get(i + index).to_uint() << (8 * (3 - i))) + } + result +} + +///| +/// **UNSAFE**: Reads a UInt16 from the bytes in little-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory +/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures +/// - **Responsibility**: Caller must ensure sufficient bytes are available +/// +/// # Parameters +/// - `bytes`: The Bytes to read from +/// - `index`: Starting byte index (0-based) +/// +/// # Behavior +/// Reads 2 bytes starting at `index` and interprets them as a UInt16 in little-endian order: +/// - `bytes[index]` → bits 0-7 (least significant) +/// - `bytes[index+1]` → bits 8-15 (most significant) +#intrinsic("%bytes.unsafe_read_uint16_le") +#doc(hidden) +pub fn Bytes::unsafe_read_uint16_le(bytes : Bytes, index : Int) -> UInt16 { + let mut result : UInt16 = 0 + for i in 0..=1 { + result = result | (bytes.unsafe_get(i + index).to_uint16() << (8 * i)) + } + result +} + +///| +/// **UNSAFE**: Reads a UInt16 from the bytes in big-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory +/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures +/// - **Responsibility**: Caller must ensure sufficient bytes are available +/// +/// # Parameters +/// - `bytes`: The Bytes to read from +/// - `index`: Starting byte index (0-based) +/// +/// # Behavior +/// Reads 2 bytes starting at `index` and interprets them as a UInt16 in big-endian order: +/// - `bytes[index]` → bits 8-15 (most significant) +/// - `bytes[index+1]` → bits 0-7 (least significant) +#intrinsic("%bytes.unsafe_read_uint16_be") +#doc(hidden) +pub fn Bytes::unsafe_read_uint16_be(bytes : Bytes, index : Int) -> UInt16 { + let mut result : UInt16 = 0 + for i in 0..=1 { + result = result | (bytes.unsafe_get(i + index).to_uint16() << (8 * (1 - i))) + } + result +} + +///| +/// **UNSAFE**: Reads a UInt64 from the BytesView in little-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory +/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view +/// +/// # Parameters +/// - `bytes`: The BytesView to read from +/// - `index`: Relative index within the view (0-based) +/// +/// # Note +/// This function delegates to `Bytes::unsafe_read_uint64_le` with the proper offset calculation. +#doc(hidden) +pub fn BytesView::unsafe_read_uint64_le( + bytes : BytesView, + index : Int, +) -> UInt64 { + bytes.bytes().unsafe_read_uint64_le(bytes.start() + index) +} + +///| +/// **UNSAFE**: Reads a UInt64 from the BytesView in big-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory +/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view +/// +/// # Parameters +/// - `bytes`: The BytesView to read from +/// - `index`: Relative index within the view (0-based) +/// +/// # Note +/// This function delegates to `Bytes::unsafe_read_uint64_be` with the proper offset calculation. +#doc(hidden) +pub fn BytesView::unsafe_read_uint64_be( + bytes : BytesView, + index : Int, +) -> UInt64 { + bytes.bytes().unsafe_read_uint64_be(bytes.start() + index) +} + +///| +/// **UNSAFE**: Reads a UInt32 from the BytesView in little-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory +/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view +/// +/// # Parameters +/// - `bytes`: The BytesView to read from +/// - `index`: Relative index within the view (0-based) +/// +/// # Note +/// This function delegates to `Bytes::unsafe_read_uint32_le` with the proper offset calculation. +#doc(hidden) +pub fn BytesView::unsafe_read_uint32_le(bytes : BytesView, index : Int) -> UInt { + bytes.bytes().unsafe_read_uint32_le(bytes.start() + index) +} + +///| +/// **UNSAFE**: Reads a UInt32 from the BytesView in big-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory +/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view +/// +/// # Parameters +/// - `bytes`: The BytesView to read from +/// - `index`: Relative index within the view (0-based) +/// +/// # Note +/// This function delegates to `Bytes::unsafe_read_uint32_be` with the proper offset calculation. +#doc(hidden) +pub fn BytesView::unsafe_read_uint32_be(bytes : BytesView, index : Int) -> UInt { + bytes.bytes().unsafe_read_uint32_be(bytes.start() + index) +} + +///| +/// **UNSAFE**: Reads a UInt16 from the BytesView in little-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory +/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view +/// +/// # Parameters +/// - `bytes`: The BytesView to read from +/// - `index`: Relative index within the view (0-based) +/// +/// # Note +/// This function delegates to `Bytes::unsafe_read_uint16_le` with the proper offset calculation. +#doc(hidden) +pub fn BytesView::unsafe_read_uint16_le( + bytes : BytesView, + index : Int, +) -> UInt16 { + bytes.bytes().unsafe_read_uint16_le(bytes.start() + index) +} + +///| +/// **UNSAFE**: Reads a UInt16 from the BytesView in big-endian byte order. +/// +/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** +/// +/// # Safety +/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` +/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory +/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view +/// +/// # Parameters +/// - `bytes`: The BytesView to read from +/// - `index`: Relative index within the view (0-based) +/// +/// # Note +/// This function delegates to `Bytes::unsafe_read_uint16_be` with the proper offset calculation. +#doc(hidden) +pub fn BytesView::unsafe_read_uint16_be( + bytes : BytesView, + index : Int, +) -> UInt16 { + bytes.bytes().unsafe_read_uint16_be(bytes.start() + index) +} + +// #endregion diff --git a/bytes/view.mbt b/builtin/bytesview.mbt similarity index 97% rename from bytes/view.mbt rename to builtin/bytesview.mbt index d23544759..2c3ccef10 100644 --- a/bytes/view.mbt +++ b/builtin/bytesview.mbt @@ -12,29 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -///| -/// A `BytesView` represents a view into a section of a `Bytes` without copying the data. -/// -/// # Example -/// -/// ```mbt -/// let bs = b"\x00\x01\x02\x03\x04\x05" -/// let bv = bs[1:4] -/// inspect(bv.length(), content="3") -/// assert_eq(bv[0], b'\x01') -/// assert_eq(bv[1], b'\x02') -/// assert_eq(bv[2], b'\x03') -/// ``` -#builtin.valtype -#deprecated("Use `BytesView` instead") -pub type View = BytesView - ///| fn BytesView::bytes(self : BytesView) -> Bytes = "%bytesview.bytes" ///| fn BytesView::start(self : BytesView) -> Int = "%bytesview.start" +///| +fn BytesView::len(self : BytesView) -> Int = "%bytesview.len" + ///| fn BytesView::make(b : Bytes, start : Int, len : Int) -> BytesView = "%bytesview.make" @@ -58,9 +44,6 @@ pub fn BytesView::length(self : BytesView) -> Int { self.len() } -///| -fn BytesView::len(self : BytesView) -> Int = "%bytesview.len" - ///| /// Retrieves a byte from the view at the specified index. /// diff --git a/builtin/pkg.generated.mbti b/builtin/pkg.generated.mbti index 3789d91db..3b01faa7f 100644 --- a/builtin/pkg.generated.mbti +++ b/builtin/pkg.generated.mbti @@ -476,6 +476,7 @@ pub fn Byte::lnot(Byte) -> Byte pub fn Byte::lsl(Byte, Int) -> Byte #deprecated pub fn Byte::lsr(Byte, Int) -> Byte +pub fn Byte::popcnt(Byte) -> Int pub fn Byte::to_char(Byte) -> Char pub fn Byte::to_double(Byte) -> Double #deprecated @@ -488,6 +489,7 @@ pub fn Byte::to_int64(Byte) -> Int64 pub fn Byte::to_string(Byte) -> String pub fn Byte::to_uint(Byte) -> UInt pub fn Byte::to_uint16(Byte) -> UInt16 +pub fn Byte::to_uint64(Byte) -> UInt64 #deprecated pub fn Char::from_int(Int) -> Char @@ -889,14 +891,56 @@ pub fn[T] ReadOnlyArray::sub(Self[T], start? : Int, end? : Int) -> ArrayView[T] pub fn Bytes::at(Bytes, Int) -> Byte #deprecated pub fn Bytes::copy(Bytes) -> Bytes +pub fn Bytes::find(Bytes, BytesView) -> Int? +#alias(of, deprecated) +#as_free_fn(of, deprecated) +#as_free_fn(deprecated) +pub fn Bytes::from_array(ArrayView[Byte]) -> Bytes +#as_free_fn(deprecated) +#deprecated +pub fn Bytes::from_fixedarray(FixedArray[Byte], len? : Int) -> Bytes +#as_free_fn(deprecated) +pub fn Bytes::from_iter(Iter[Byte]) -> Bytes +#as_free_fn(deprecated) +pub fn Bytes::from_iterator(Iterator[Byte]) -> Bytes +pub fn Bytes::get(Bytes, Int) -> Byte? +pub fn Bytes::iter(Bytes) -> Iter[Byte] +pub fn Bytes::iter2(Bytes) -> Iter2[Int, Byte] +pub fn Bytes::iterator(Bytes) -> Iterator[Byte] +pub fn Bytes::iterator2(Bytes) -> Iterator2[Int, Byte] pub fn Bytes::length(Bytes) -> Int pub fn Bytes::make(Int, Byte) -> Bytes pub fn Bytes::makei(Int, (Int) -> Byte raise?) -> Bytes raise? pub fn Bytes::new(Int) -> Bytes #deprecated pub fn Bytes::of_string(String) -> Bytes +pub fn Bytes::repeat(Bytes, Int) -> Bytes +pub fn Bytes::rev_find(Bytes, BytesView) -> Int? +#alias("_[_:_]") +pub fn Bytes::sub(Bytes, start? : Int, end? : Int) -> BytesView +pub fn Bytes::to_array(Bytes) -> Array[Byte] +#label_migration(len, fill=false) +pub fn Bytes::to_fixedarray(Bytes, len? : Int) -> FixedArray[Byte] pub fn Bytes::to_unchecked_string(Bytes, offset? : Int, length? : Int) -> String +#alias("_[_]") +pub fn BytesView::at(Self, Int) -> Byte +pub fn BytesView::data(Self) -> Bytes +pub fn BytesView::find(Self, Self) -> Int? +pub fn BytesView::get(Self, Int) -> Byte? +pub fn BytesView::iter(Self) -> Iter[Byte] +pub fn BytesView::iter2(Self) -> Iter2[Int, Byte] +pub fn BytesView::iterator(Self) -> Iterator[Byte] +pub fn BytesView::iterator2(Self) -> Iterator2[Int, Byte] +pub fn BytesView::length(Self) -> Int +pub fn BytesView::rev_find(Self, Self) -> Int? +pub fn BytesView::start_offset(Self) -> Int +#alias("_[_:_]") +pub fn BytesView::sub(Self, start? : Int, end? : Int) -> Self +pub fn BytesView::to_array(Self) -> Array[Byte] +pub fn BytesView::to_bytes(Self) -> Bytes +pub fn BytesView::to_fixedarray(Self) -> FixedArray[Byte] + #alias("_[_]") #deprecated pub fn StringView::at(Self, Int) -> Int @@ -983,6 +1027,7 @@ pub impl Add for UInt64 pub impl Add for Double pub impl Add for String pub impl[T] Add for FixedArray[T] +pub impl Add for Bytes pub impl Add for StringView pub(open) trait BitAnd { @@ -1051,6 +1096,7 @@ pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare, T pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare, T5 : Compare, T6 : Compare, T7 : Compare, T8 : Compare, T9 : Compare, T10 : Compare, T11 : Compare, T12 : Compare, T13 : Compare] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare, T5 : Compare, T6 : Compare, T7 : Compare, T8 : Compare, T9 : Compare, T10 : Compare, T11 : Compare, T12 : Compare, T13 : Compare, T14 : Compare] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare, T5 : Compare, T6 : Compare, T7 : Compare, T8 : Compare, T9 : Compare, T10 : Compare, T11 : Compare, T12 : Compare, T13 : Compare, T14 : Compare, T15 : Compare] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) +pub impl Compare for BytesView pub impl Compare for StringView pub(open) trait Default { @@ -1068,6 +1114,7 @@ pub impl Default for String pub impl[X] Default for X? pub impl[X] Default for FixedArray[X] pub impl[T] Default for ReadOnlyArray[T] +pub impl Default for Bytes pub impl Default for StringView pub(open) trait Div { @@ -1119,6 +1166,7 @@ pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq, pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq, T8 : Eq, T9 : Eq, T10 : Eq, T11 : Eq, T12 : Eq, T13 : Eq] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq, T8 : Eq, T9 : Eq, T10 : Eq, T11 : Eq, T12 : Eq, T13 : Eq, T14 : Eq] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq, T8 : Eq, T9 : Eq, T10 : Eq, T11 : Eq, T12 : Eq, T13 : Eq, T14 : Eq, T15 : Eq] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) +pub impl Eq for BytesView pub impl Eq for StringView pub(open) trait Hash { @@ -1136,6 +1184,7 @@ pub impl Hash for String pub impl[X : Hash] Hash for X? pub impl[T : Hash, E : Hash] Hash for Result[T, E] pub impl[T : Hash] Hash for FixedArray[T] +pub impl Hash for Bytes pub impl[A : Hash, B : Hash] Hash for (A, B) pub impl[A : Hash, B : Hash, C : Hash] Hash for (A, B, C) pub impl[A : Hash, B : Hash, C : Hash, D : Hash] Hash for (A, B, C, D) @@ -1219,6 +1268,7 @@ pub impl[X : Show] Show for X? pub impl[T : Show, E : Show] Show for Result[T, E] pub impl[X : Show] Show for FixedArray[X] pub impl[T : Show] Show for ReadOnlyArray[T] +pub impl Show for Bytes pub impl[A : Show, B : Show] Show for (A, B) pub impl[A : Show, B : Show, C : Show] Show for (A, B, C) pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D) @@ -1234,6 +1284,7 @@ pub impl[T0 : Show, T1 : Show, T2 : Show, T3 : Show, T4 : Show, T5 : Show, T6 : pub impl[T0 : Show, T1 : Show, T2 : Show, T3 : Show, T4 : Show, T5 : Show, T6 : Show, T7 : Show, T8 : Show, T9 : Show, T10 : Show, T11 : Show, T12 : Show, T13 : Show] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) pub impl[T0 : Show, T1 : Show, T2 : Show, T3 : Show, T4 : Show, T5 : Show, T6 : Show, T7 : Show, T8 : Show, T9 : Show, T10 : Show, T11 : Show, T12 : Show, T13 : Show, T14 : Show] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) pub impl[T0 : Show, T1 : Show, T2 : Show, T3 : Show, T4 : Show, T5 : Show, T6 : Show, T7 : Show, T8 : Show, T9 : Show, T10 : Show, T11 : Show, T12 : Show, T13 : Show, T14 : Show, T15 : Show] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) +pub impl Show for BytesView pub impl Show for StringView pub(open) trait Shr { @@ -1279,6 +1330,7 @@ pub impl[T : ToJson] ToJson for T? pub impl[Ok : ToJson, Err : ToJson] ToJson for Result[Ok, Err] pub impl[X : ToJson] ToJson for FixedArray[X] pub impl[T : ToJson] ToJson for ReadOnlyArray[T] +pub impl ToJson for Bytes pub impl[A : ToJson, B : ToJson] ToJson for (A, B) pub impl[A : ToJson, B : ToJson, C : ToJson] ToJson for (A, B, C) pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson] ToJson for (A, B, C, D) @@ -1294,6 +1346,7 @@ pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson, pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson, G : ToJson, H : ToJson, I : ToJson, J : ToJson, K : ToJson, L : ToJson, M : ToJson, N : ToJson] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson, G : ToJson, H : ToJson, I : ToJson, J : ToJson, K : ToJson, L : ToJson, M : ToJson, N : ToJson, O : ToJson] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson, G : ToJson, H : ToJson, I : ToJson, J : ToJson, K : ToJson, L : ToJson, M : ToJson, N : ToJson, O : ToJson, P : ToJson] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) +pub impl ToJson for BytesView pub impl ToJson for StringView pub trait ToStringView { diff --git a/byte/byte.mbt b/byte/byte.mbt index f31de89e1..3e4bd4b2d 100644 --- a/byte/byte.mbt +++ b/byte/byte.mbt @@ -17,45 +17,3 @@ pub let max_value : Byte = b'\xFF' ///| pub let min_value : Byte = b'\x00' - -///| -/// Converts a byte value to an unsigned 64-bit integer. -/// -/// Parameters: -/// -/// * `byte` : The byte value to be converted. -/// -/// Returns an unsigned 64-bit integer representation of the byte value. -/// -/// Example: -/// -/// ```mbt test -/// let b = b'\xFF' -/// inspect(b.to_uint64(), content="255") -/// ``` -pub fn Byte::to_uint64(self : Byte) -> UInt64 { - self.to_uint().to_uint64() -} - -///| -/// Counts the number of 1-bits (population count) in the byte using bitwise operations. -/// -/// Parameters: -/// -/// * `self` : The byte value whose 1-bits are to be counted. -/// -/// Returns the number of 1-bits in the byte. -/// -/// Example: -/// -/// ```mbt test -/// let b = b'\x0F' -/// inspect(b.popcnt(), content="4") -/// ``` -pub fn Byte::popcnt(self : Byte) -> Int { - let mut n = self - n = (n & 0x55) + ((n >> 1) & 0x55) - n = (n & 0x33) + ((n >> 2) & 0x33) - n = (n & 0x0F) + ((n >> 4) & 0x0F) - n.to_int() -} diff --git a/byte/pkg.generated.mbti b/byte/pkg.generated.mbti index 906e470f9..c9546caea 100644 --- a/byte/pkg.generated.mbti +++ b/byte/pkg.generated.mbti @@ -9,8 +9,6 @@ pub let min_value : Byte // Errors // Types and methods -pub fn Byte::popcnt(Byte) -> Int -pub fn Byte::to_uint64(Byte) -> UInt64 // Type aliases diff --git a/bytes/alias.mbt b/bytes/alias.mbt new file mode 100644 index 000000000..d5aabcc38 --- /dev/null +++ b/bytes/alias.mbt @@ -0,0 +1,36 @@ +// Copyright 2025 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///| +/// A `BytesView` represents a view into a section of a `Bytes` without copying the data. +/// +/// # Example +/// +/// ```mbt +/// let bs = b"\x00\x01\x02\x03\x04\x05" +/// let bv = bs[1:4] +/// inspect(bv.length(), content="3") +/// assert_eq(bv[0], b'\x01') +/// assert_eq(bv[1], b'\x02') +/// assert_eq(bv[2], b'\x03') +/// ``` +#builtin.valtype +#deprecated("Use `BytesView` instead") +pub type View = BytesView + +///| +/// same as `Bytes::default` +pub fn default() -> Bytes { + b"" +} diff --git a/bytes/bitstring.mbt b/bytes/bitstring.mbt deleted file mode 100644 index cf934b3eb..000000000 --- a/bytes/bitstring.mbt +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright 2025 International Digital Economy Academy -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// offset and len are all in bits - -///| -fn UInt::extend_sign(self : UInt, len : Int) -> Int { - let b = 32 - len - self.reinterpret_as_int() << b >> b -} - -///| -fn UInt64::extend_sign(self : UInt64, len : Int) -> Int64 { - let b = 64 - len - self.reinterpret_as_int64() << b >> b -} - -//-------------------------------- -// BytesView -//-------------------------------- - -///| -/// Extract a single bit. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_bit( - bs : BytesView, - offset : Int, - _len : Int, -) -> UInt { - let byte_index = offset >> 3 - let bit_shift = 7 - (offset & 7) - let byte_val = bs.unsafe_get(byte_index).to_uint() - (byte_val >> bit_shift) & 1U -} - -///| -/// Extract a single bit. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_bit_signed( - bs : BytesView, - offset : Int, - _len : Int, -) -> Int { - let byte_index = offset >> 3 - let bit_shift = 7 - (offset & 7) - let byte_val = bs.unsafe_get(byte_index).to_int() - // Extract bit and convert to signed: 0 -> 0, 1 -> -1 - ((byte_val >> bit_shift) & 1) * -1 -} - -///| -/// Extract [2..8] bits. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_byte( - bs : BytesView, - offset : Int, - len : Int, -) -> UInt { - let byte_index = offset >> 3 - if (offset & 7) == 0 { - // byte-aligned case - let byte = bs.unsafe_get(byte_index) - (byte >> (8 - len)).to_uint() - } else if (offset & 7) + len <= 8 { - // All bits are within the same byte - no need to read next byte - let byte = bs.unsafe_get(byte_index).to_uint() - let shift = 8 - ((offset & 7) + len) - let mask = (1U << len) - 1 - (byte >> shift) & mask - } else { - // extract 16 bits at [byte_index, byte_index + 1] - let b0 = bs.unsafe_get(byte_index).to_uint() - let b1 = bs.unsafe_get(byte_index + 1).to_uint() - let data = (b0 << 8) | b1 - // mask off the top bits - let bit_mask = (1U << (16 - (offset & 7))) - 1 - let data = data & bit_mask - let shift = 16 - ((offset & 7) + len) - data >> shift - } -} - -///| -/// Extract [9..32] bits in little-endian byte order. -/// -/// # Invariants -/// - It's guaranteed to have at least 2 bytes available for extraction -/// - Only reads the necessary number of bytes based on the bit length -/// -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_uint_le( - bs : BytesView, - offset : Int, - len : Int, -) -> UInt { - let bytes_needed = (len + 7) / 8 - // TODO: add fast path for aligned case - // non-aligned case: extract bytes using unsafe_extract_byte - let b0 = bs.unsafe_extract_byte(offset, 8) - match bytes_needed { - 2 => { - let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) - (b1 << 8) | b0 - } - 3 => { - let b1 = bs.unsafe_extract_byte(offset + 8, 8) - let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) - (b2 << 16) | (b1 << 8) | b0 - } - 4 => { - let b1 = bs.unsafe_extract_byte(offset + 8, 8) - let b2 = bs.unsafe_extract_byte(offset + 16, 8) - let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) - (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - } - _ => abort("Invalid byte count for int32 extraction") - } -} - -///| -/// Extract [9..32] bits in big-endian byte order. -/// -/// # Invariants -/// - It's guaranteed to have at least 2 bytes available for extraction -/// - Only reads the necessary number of bytes based on the bit length -/// -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_uint_be( - bs : BytesView, - offset : Int, - len : Int, -) -> UInt { - let bytes_needed = (len + 7) / 8 - // TODO: add fast path for aligned case - // non-aligned case: extract bytes using unsafe_extract_byte - let b0 = bs.unsafe_extract_byte(offset, 8) - match bytes_needed { - 2 => { - let b1 = bs.unsafe_extract_byte(offset + 8, len - 8) - let shift = 16 - len - let data = (b0 << 8) | (b1 << shift) - data >> shift - } - 3 => { - let b1 = bs.unsafe_extract_byte(offset + 8, 8) - let b2 = bs.unsafe_extract_byte(offset + 16, len - 16) - let shift = 24 - len - let data = (b0 << 16) | (b1 << 8) | (b2 << shift) - data >> shift - } - 4 => { - let b1 = bs.unsafe_extract_byte(offset + 8, 8) - let b2 = bs.unsafe_extract_byte(offset + 16, 8) - let b3 = bs.unsafe_extract_byte(offset + 24, len - 24) - let shift = 32 - len - let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift) - data >> shift - } - _ => abort("Invalid byte count for int32 extraction") - } -} - -///| -/// Extract [33..64] bits in little-endian byte order. -/// -/// # Invariants -/// - It's guaranteed to have at least 5 bytes available for extraction -/// - Only reads the necessary number of bytes based on the bit length (5-8 bytes) -/// - For bit lengths < 33, use unsafe_extract_int_le instead -/// -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_uint64_le( - bs : BytesView, - offset : Int, - len : Int, -) -> UInt64 { - let bytes_needed = (len + 7) / 8 - // TODO: add fast path for aligned case - // non-aligned case: extract bytes using unsafe_extract_byte - let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() - let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() - let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() - let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() - match bytes_needed { - 5 => { - let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() - (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - } - 6 => { - let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() - (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0 - } - 7 => { - let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() - (b6 << 48) | - (b5 << 40) | - (b4 << 32) | - (b3 << 24) | - (b2 << 16) | - (b1 << 8) | - b0 - } - 8 => { - let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() - let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() - (b7 << 56) | - (b6 << 48) | - (b5 << 40) | - (b4 << 32) | - (b3 << 24) | - (b2 << 16) | - (b1 << 8) | - b0 - } - _ => abort("Invalid byte count for int64 extraction") - } -} - -///| -/// Extract [33..64] bits in big-endian byte order. -/// -/// # Invariants -/// - It's guaranteed to have at least 5 bytes available for extraction -/// - Only reads the necessary number of bytes based on the bit length (5-8 bytes) -/// - For bit lengths < 33, use unsafe_extract_int_be instead -/// -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_uint64_be( - bs : BytesView, - offset : Int, - len : Int, -) -> UInt64 { - let bytes_needed = (len + 7) / 8 - // TODO: add fast path for aligned case - // non-aligned case: extract bytes using unsafe_extract_byte - let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64() - let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64() - let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64() - let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64() - match bytes_needed { - 5 => { - let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64() - let shift = 40 - len - let data = (b0 << 32) | - (b1 << 24) | - (b2 << 16) | - (b3 << 8) | - (b4 << shift) - data >> shift - } - 6 => { - let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64() - let shift = 48 - len - let data = (b0 << 40) | - (b1 << 32) | - (b2 << 24) | - (b3 << 16) | - (b4 << 8) | - (b5 << shift) - data >> shift - } - 7 => { - let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64() - let shift = 56 - len - let data = (b0 << 48) | - (b1 << 40) | - (b2 << 32) | - (b3 << 24) | - (b4 << 16) | - (b5 << 8) | - (b6 << shift) - data >> shift - } - 8 => { - let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64() - let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64() - let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64() - let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64() - let shift = 64 - len - let data = (b0 << 56) | - (b1 << 48) | - (b2 << 40) | - (b3 << 32) | - (b4 << 24) | - (b5 << 16) | - (b6 << 8) | - (b7 << shift) - data >> shift - } - _ => abort("Invalid byte count for int64 extraction") - } -} - -///| -/// Extract a subview from a view. `offset` and `len` are in bits and must be -/// aligned to bytes. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_bytesview( - bs : BytesView, - offset : Int, - len : Int, -) -> BytesView { - BytesView::make(bs.bytes(), bs.start() + (offset >> 3), len >> 3) -} - -///| -/// Extract [2..8] bits as a signed integer. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_byte_signed( - bs : BytesView, - offset : Int, - len : Int, -) -> Int { - let unsigned = bs.unsafe_extract_byte(offset, len) - unsigned.extend_sign(len) -} - -///| -/// Extract [9..32] bits as a signed integer. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_int_le( - bs : BytesView, - offset : Int, - len : Int, -) -> Int { - let unsigned = bs.unsafe_extract_uint_le(offset, len) - unsigned.extend_sign(len) -} - -///| -/// Extract [9..32] bits as a signed integer. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_int_be( - bs : BytesView, - offset : Int, - len : Int, -) -> Int { - let unsigned = bs.unsafe_extract_uint_be(offset, len) - unsigned.extend_sign(len) -} - -///| -/// Extract [33..64] bits as a signed integer. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_int64_le( - bs : BytesView, - offset : Int, - len : Int, -) -> Int64 { - let unsigned = bs.unsafe_extract_uint64_le(offset, len) - unsigned.extend_sign(len) -} - -///| -/// Extract [33..64] bits as a signed integer. -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn BytesView::unsafe_extract_int64_be( - bs : BytesView, - offset : Int, - len : Int, -) -> Int64 { - let unsigned = bs.unsafe_extract_uint64_be(offset, len) - unsigned.extend_sign(len) -} - -//-------------------------------- -// Bytes -//-------------------------------- - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_bit(bs : Bytes, offset : Int, len : Int) -> UInt { - bs[:].unsafe_extract_bit(offset, len) -} - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_byte(bs : Bytes, offset : Int, len : Int) -> UInt { - bs[:].unsafe_extract_byte(offset, len) -} - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_uint_le( - bs : Bytes, - offset : Int, - len : Int, -) -> UInt { - bs[:].unsafe_extract_uint_le(offset, len) -} - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_uint_be( - bs : Bytes, - offset : Int, - len : Int, -) -> UInt { - bs[:].unsafe_extract_uint_be(offset, len) -} - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_uint64_le( - bs : Bytes, - offset : Int, - len : Int, -) -> UInt64 { - bs[:].unsafe_extract_uint64_le(offset, len) -} - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_uint64_be( - bs : Bytes, - offset : Int, - len : Int, -) -> UInt64 { - bs[:].unsafe_extract_uint64_be(offset, len) -} - -///| -#internal(experimental, "subject to breaking change without notice") -#doc(hidden) -pub fn Bytes::unsafe_extract_bytesview( - bs : Bytes, - offset : Int, - len : Int, -) -> BytesView { - bs[:].unsafe_extract_bytesview(offset, len) -} diff --git a/bytes/bytes.mbt b/bytes/bytes.mbt deleted file mode 100644 index 37b9753fa..000000000 --- a/bytes/bytes.mbt +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2025 International Digital Economy Academy -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -///| -/// Creates a new bytes sequence from a byte array. -/// -/// Parameters: -/// -/// * `array` : An array of bytes to be converted. -/// -/// Returns a new bytes sequence containing the same bytes as the input array. -/// -/// Example: -/// -/// ```mbt test -/// let arr = [b'h', b'i'] -/// let bytes = Bytes::from_array(arr) -/// inspect( -/// bytes, -/// content=( -/// #|b"hi" -/// ), -/// ) -/// ``` -#as_free_fn(deprecated) -#alias(of, deprecated="Use from_array instead") -#as_free_fn(of, deprecated="Use from_array instead") -pub fn Bytes::from_array(arr : ArrayView[Byte]) -> Bytes { - Bytes::makei(arr.length(), i => arr[i]) -} - -///| -/// Creates a new bytes sequence from a fixed-size array of bytes with an -/// optional length parameter. -/// -/// Parameters: -/// -/// * `array` : A fixed-size array of bytes to be converted into a bytes -/// sequence. -/// * `length` : (Optional) The length of the resulting bytes sequence. If not -/// provided, uses the full length of the input array. -/// -/// Returns a new bytes sequence containing the bytes from the input array. If a -/// length is specified, only includes up to that many bytes. -/// -/// Example: -/// -/// ```mbt test -/// let arr : FixedArray[Byte] = [b'h', b'e', b'l', b'l', b'o'] -/// let bytes = Bytes::from_array(arr[0:3]) -/// inspect( -/// bytes, -/// content=( -/// #|b"hel" -/// ), -/// ) -/// ``` -/// -/// Panics if the length is invalid -#as_free_fn(deprecated) -#deprecated("Use Bytes::from_array instead") -pub fn Bytes::from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { - let len = match len { - None => arr.length() - Some(x) => { - guard 0 <= x && x <= arr.length() - x - } - } - let result = unsafe_to_fixedarray(UninitializedArray::make(len)) - arr.blit_to(result, len~) - result.unsafe_reinterpret_as_bytes() -} - -///| -/// Converts a bytes sequence into a fixed-size array of bytes. If an optional -/// length is provided, the resulting array will have exactly that length, -/// otherwise it will match the length of the input bytes. -/// -/// Parameters: -/// -/// * `self` : The bytes sequence to convert. -/// * `len` : Optional. The desired length of the output array. If specified, the -/// resulting array will have this length. If not specified, the length of the -/// input bytes sequence will be used. -/// -/// Returns a fixed-size array containing the bytes from the input sequence. -/// -/// Example: -/// -/// ```mbt test -/// let bytes = b"hello" -/// let arr = bytes.to_fixedarray() -/// inspect(arr, content="[b'\\x68', b'\\x65', b'\\x6C', b'\\x6C', b'\\x6F']") -/// let arr2 = bytes[:3].to_fixedarray() -/// inspect(arr2, content="[b'\\x68', b'\\x65', b'\\x6C']") -/// ``` -/// -/// Panics if the length is invalid -#label_migration(len, fill=false) -pub fn Bytes::to_fixedarray(self : Bytes, len? : Int) -> FixedArray[Byte] { - let len = match len { - None => self.length() - Some(x) => { - guard 0 <= x && x <= self.length() - x - } - } - let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) - arr.blit_from_bytes(0, self, 0, len) - arr -} - -///| -pub fn BytesView::to_fixedarray(self : BytesView) -> FixedArray[Byte] { - let len = self.length() - let arr = unsafe_to_fixedarray(UninitializedArray::make(len)) - arr.blit_from_bytes(0, self.data(), self.start_offset(), len) - arr -} - -///| -/// Creates a new bytes sequence from an iterator of bytes. -/// -/// Parameters: -/// -/// * `iterator` : An iterator that yields bytes. -/// -/// Returns a new bytes sequence containing all the bytes from the iterator. -/// -/// Example: -/// -/// ```mbt test -/// let iter = Iter::singleton(b'h') -/// let bytes = Bytes::from_iter(iter) -/// inspect( -/// bytes, -/// content=( -/// #|b"h" -/// ), -/// ) -/// ``` -#as_free_fn(deprecated) -pub fn Bytes::from_iter(iter : Iter[Byte]) -> Bytes { - Bytes::from_array(iter.collect()) -} - -///| -/// Creates a new bytes sequence from an iterator of bytes. -/// -/// Parameters: -/// -/// * `iterator` : An iterator that yields bytes. -/// -/// Returns a new bytes sequence containing all the bytes from the iterator. -/// -/// Example: -/// -/// ```mbt test -/// let iter = Iterator::singleton(b'h') -/// let bytes = Bytes::from_iterator(iter) -/// inspect( -/// bytes, -/// content=( -/// #|b"h" -/// ), -/// ) -/// ``` -#as_free_fn(deprecated) -pub fn Bytes::from_iterator(iter : Iterator[Byte]) -> Bytes { - Bytes::from_array(iter.collect()) -} - -///| -/// Creates a new bytes sequence from a fixed-size byte array. -/// -/// Parameters: -/// -/// * `array` : A fixed-size array of bytes to be converted into a bytes -/// sequence. Elements in the array should be of type `Byte`. -/// -/// Returns a new bytes sequence containing the same bytes as the input array. -/// -/// Example: -/// -/// ```mbt test -/// let arr : FixedArray[Byte] = [b'h', b'e', b'l', b'l', b'o'] -/// let bytes = Bytes::of(arr) -/// inspect( -/// bytes, -/// content=( -/// -/// #|b"hello" -/// -/// ), -/// ) -/// ``` -/// TODO: marked as intrinsic, inline if it is constant - -///| -/// Converts a bytes sequence into an array of bytes. -/// -/// Parameters: -/// -/// * `bytes` : A sequence of bytes to be converted into an array. -/// -/// Returns an array containing the same bytes as the input sequence. -/// -/// Example: -/// -/// ```mbt test -/// let bytes = b"hello" -/// let arr = bytes.to_array() -/// inspect(arr, content="[b'\\x68', b'\\x65', b'\\x6C', b'\\x6C', b'\\x6F']") -/// ``` -pub fn Bytes::to_array(self : Bytes) -> Array[Byte] { - let len = self.length() - let rv = Array::make(len, b'0') - for i in 0.. Array[Byte] { - let len = self.length() - let rv = Array::make(len, b'0') - for i in 0.. sum = sum + b.to_int()) -/// inspect(sum, content="209") // ASCII values: 'h'(104) + 'i'(105) = 209 -/// ``` -pub fn Bytes::iter(self : Bytes) -> Iter[Byte] { - Iter::new(yield_ => for i in 0.. sum = sum + b.to_int()) -/// inspect(sum, content="209") // ASCII values: 'h'(104) + 'i'(105) = 209 -/// ``` -pub fn Bytes::iterator(self : Bytes) -> Iterator[Byte] { - let mut i = 0 - let len = self.length() - Iterator::new(fn() { - guard i < len else { None } - let c = self.unsafe_get(i) - i += 1 - Some(c) - }) -} - -///| -/// Creates an iterator that yields tuples of index and byte, -/// indices start from 0. -/// -/// Example: -/// let buf = StringBuilder::new(size_hint=5) -/// let keys = [] -/// b"abcde".iter2().each((i, x) => { -/// buf.write_string(x.to_string()) -/// keys.push( i ) -/// }) -/// inspect(buf, content="b'\\x61'b'\\x62'b'\\x63'b'\\x64'b'\\x65'") -/// inspect(keys, content="[0, 1, 2, 3, 4]") -pub fn Bytes::iter2(self : Bytes) -> Iter2[Int, Byte] { - Iter2::new(yield_ => for i in 0.. Iterator2[Int, Byte] { - let mut i = 0 - let len = self.length() - Iterator::new(fn() { - guard i < len else { None } - let result = (i, self.unsafe_get(i)) - i += 1 - Some(result) - }) -} - -///| -/// Creates a new empty bytes sequence. -/// -/// Returns an empty bytes sequence. -/// -/// Example: -/// -/// ```mbt test -/// let bytes = Bytes::default() -/// inspect(bytes, content="b\"\"") -/// inspect(bytes.length(), content="0") -/// ``` -pub impl Default for Bytes with default() { - b"" -} - -///| -/// same as `Bytes::default` -pub fn default() -> Bytes { - b"" -} - -///| -/// Retrieves a byte from the view at the specified index. -/// -/// Parameters: -/// -/// * `self` : The bytes view to retrieve the byte from. -/// * `index` : The position in the view from which to retrieve the byte. -/// -/// Returns the byte at the specified index, or None if the index is out of bounds. -/// -/// Example: -/// -/// ```mbt test -/// let bytes = b"\x01\x02\x03" -/// let byte = bytes.get(1) -/// inspect(byte, content="Some(b'\\x02')") -/// let bytes = b"\x01\x02\x03" -/// let byte = bytes.get(3) -/// inspect(byte, content="None") -/// ``` -pub fn Bytes::get(self : Bytes, index : Int) -> Byte? { - guard index >= 0 && index < self.length() else { None } - Some(self[index]) -} - -///| -/// Reinterpret the byte sequence as Bytes. -fn unsafe_to_bytes(array : FixedArray[Byte]) -> Bytes = "%identity" - -///| -fn unsafe_to_fixedarray(array : UninitializedArray[Byte]) -> FixedArray[Byte] = "%identity" - -///| -/// Concatenates two bytes sequences. -/// -/// Parameters: -/// -/// * `self` : The first bytes sequence. -/// * `other` : The second bytes sequence. -/// TODO: marked as intrinsic, inline if it is constant -pub impl Add for Bytes with add(self : Bytes, other : Bytes) -> Bytes { - let len_self = self.length() - let len_other = other.length() - let rv : FixedArray[Byte] = FixedArray::make(len_self + len_other, 0) - for i in 0.. Bytes { - if count <= 0 || self.length() == 0 { - return [] - } - if count == 1 { - return self - } - let len = self.length() - let total = len * count - // (Optional) detect overflow: if multiplication wrapped (best-effort) - guard total / count == len - let arr = FixedArray::make(total, (0 : Byte)) - arr.blit_from_bytes(0, self, 0, len) - let mut filled = len - while filled < total { - let remaining = total - filled - let copy_len = if filled < remaining { filled } else { remaining } - let src = unsafe_to_bytes(arr) - arr.blit_from_bytes(filled, src, 0, copy_len) - filled = filled + copy_len - } - unsafe_to_bytes(arr) -} diff --git a/bytes/moon.pkg.json b/bytes/moon.pkg.json index f3d0aa173..2314a4be4 100644 --- a/bytes/moon.pkg.json +++ b/bytes/moon.pkg.json @@ -1,12 +1,10 @@ { "import": [ - "moonbitlang/core/builtin", - "moonbitlang/core/byte", - "moonbitlang/core/uint16" + "moonbitlang/core/builtin" ], "test-import": [ "moonbitlang/core/array", - "moonbitlang/core/double", + "moonbitlang/core/double", "moonbitlang/core/uint", "moonbitlang/core/uint64", "moonbitlang/core/test", @@ -15,4 +13,4 @@ "moonbitlang/core/json", "moonbitlang/core/float" ] -} +} \ No newline at end of file diff --git a/bytes/pkg.generated.mbti b/bytes/pkg.generated.mbti index 62562cc90..a02334cee 100644 --- a/bytes/pkg.generated.mbti +++ b/bytes/pkg.generated.mbti @@ -11,57 +11,6 @@ pub fn default() -> Bytes // Errors // Types and methods -pub fn Bytes::find(Bytes, BytesView) -> Int? -#alias(of, deprecated) -#as_free_fn(of, deprecated) -#as_free_fn(deprecated) -pub fn Bytes::from_array(ArrayView[Byte]) -> Bytes -#as_free_fn(deprecated) -#deprecated -pub fn Bytes::from_fixedarray(FixedArray[Byte], len? : Int) -> Bytes -#as_free_fn(deprecated) -pub fn Bytes::from_iter(Iter[Byte]) -> Bytes -#as_free_fn(deprecated) -pub fn Bytes::from_iterator(Iterator[Byte]) -> Bytes -pub fn Bytes::get(Bytes, Int) -> Byte? -pub fn Bytes::iter(Bytes) -> Iter[Byte] -pub fn Bytes::iter2(Bytes) -> Iter2[Int, Byte] -pub fn Bytes::iterator(Bytes) -> Iterator[Byte] -pub fn Bytes::iterator2(Bytes) -> Iterator2[Int, Byte] -pub fn Bytes::repeat(Bytes, Int) -> Bytes -pub fn Bytes::rev_find(Bytes, BytesView) -> Int? -#alias("_[_:_]") -pub fn Bytes::sub(Bytes, start? : Int, end? : Int) -> BytesView -pub fn Bytes::to_array(Bytes) -> Array[Byte] -#label_migration(len, fill=false) -pub fn Bytes::to_fixedarray(Bytes, len? : Int) -> FixedArray[Byte] -pub impl Add for Bytes -pub impl Default for Bytes -pub impl Hash for Bytes -pub impl Show for Bytes -pub impl ToJson for Bytes - -#alias("_[_]") -pub fn BytesView::at(Self, Int) -> Byte -pub fn BytesView::data(Self) -> Bytes -pub fn BytesView::find(Self, Self) -> Int? -pub fn BytesView::get(Self, Int) -> Byte? -pub fn BytesView::iter(Self) -> Iter[Byte] -pub fn BytesView::iter2(Self) -> Iter2[Int, Byte] -pub fn BytesView::iterator(Self) -> Iterator[Byte] -pub fn BytesView::iterator2(Self) -> Iterator2[Int, Byte] -pub fn BytesView::length(Self) -> Int -pub fn BytesView::rev_find(Self, Self) -> Int? -pub fn BytesView::start_offset(Self) -> Int -#alias("_[_:_]") -pub fn BytesView::sub(Self, start? : Int, end? : Int) -> Self -pub fn BytesView::to_array(Self) -> Array[Byte] -pub fn BytesView::to_bytes(Self) -> Bytes -pub fn BytesView::to_fixedarray(Self) -> FixedArray[Byte] -pub impl Compare for BytesView -pub impl Eq for BytesView -pub impl Show for BytesView -pub impl ToJson for BytesView // Type aliases #deprecated diff --git a/bytes/unsafe_bytes.mbt b/bytes/unsafe_bytes.mbt deleted file mode 100644 index f25292e68..000000000 --- a/bytes/unsafe_bytes.mbt +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2025 International Digital Economy Academy -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -///| -/// **UNSAFE**: Reads a UInt64 from the bytes in little-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory -/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures -/// - **Responsibility**: Caller must ensure sufficient bytes are available -/// -/// # Parameters -/// - `bytes`: The Bytes to read from -/// - `index`: Starting byte index (0-based) -/// -/// # Behavior -/// Reads 8 bytes starting at `index` and interprets them as a UInt64 in little-endian order: -/// - `bytes[index]` → bits 0-7 (least significant) -/// - `bytes[index+1]` → bits 8-15 -/// - ... -/// - `bytes[index+7]` → bits 56-63 (most significant) -#intrinsic("%bytes.unsafe_read_uint64_le") -#doc(hidden) -pub fn Bytes::unsafe_read_uint64_le(bytes : Bytes, index : Int) -> UInt64 { - let mut result : UInt64 = 0 - for i in 0..=7 { - result = result | (bytes.unsafe_get(i + index).to_uint64() << (8 * i)) - } - result -} - -///| -/// **UNSAFE**: Reads a UInt64 from the bytes in big-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory -/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures -/// - **Responsibility**: Caller must ensure sufficient bytes are available -/// -/// # Parameters -/// - `bytes`: The Bytes to read from -/// - `index`: Starting byte index (0-based) -/// -/// # Behavior -/// Reads 8 bytes starting at `index` and interprets them as a UInt64 in big-endian order: -/// - `bytes[index]` → bits 56-63 (most significant) -/// - `bytes[index+1]` → bits 48-55 -/// - ... -/// - `bytes[index+7]` → bits 0-7 (least significant) -#intrinsic("%bytes.unsafe_read_uint64_be") -#doc(hidden) -pub fn Bytes::unsafe_read_uint64_be(bytes : Bytes, index : Int) -> UInt64 { - let mut result : UInt64 = 0 - for i in 0..=7 { - result = result | (bytes.unsafe_get(i + index).to_uint64() << (8 * (7 - i))) - } - result -} - -///| -/// **UNSAFE**: Reads a UInt32 from the bytes in little-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory -/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures -/// - **Responsibility**: Caller must ensure sufficient bytes are available -/// -/// # Parameters -/// - `bytes`: The Bytes to read from -/// - `index`: Starting byte index (0-based) -/// -/// # Behavior -/// Reads 4 bytes starting at `index` and interprets them as a UInt32 in little-endian order: -/// - `bytes[index]` → bits 0-7 (least significant) -/// - `bytes[index+1]` → bits 8-15 -/// - `bytes[index+2]` → bits 16-23 -/// - `bytes[index+3]` → bits 24-31 (most significant) -#intrinsic("%bytes.unsafe_read_uint32_le") -#doc(hidden) -pub fn Bytes::unsafe_read_uint32_le(bytes : Bytes, index : Int) -> UInt { - let mut result : UInt = 0 - for i in 0..=3 { - result = result | (bytes.unsafe_get(i + index).to_uint() << (8 * i)) - } - result -} - -///| -/// **UNSAFE**: Reads a UInt32 from the bytes in big-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory -/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures -/// - **Responsibility**: Caller must ensure sufficient bytes are available -/// -/// # Parameters -/// - `bytes`: The Bytes to read from -/// - `index`: Starting byte index (0-based) -/// -/// # Behavior -/// Reads 4 bytes starting at `index` and interprets them as a UInt32 in big-endian order: -/// - `bytes[index]` → bits 24-31 (most significant) -/// - `bytes[index+1]` → bits 16-23 -/// - `bytes[index+2]` → bits 8-15 -/// - `bytes[index+3]` → bits 0-7 (least significant) -#intrinsic("%bytes.unsafe_read_uint32_be") -#doc(hidden) -pub fn Bytes::unsafe_read_uint32_be(bytes : Bytes, index : Int) -> UInt { - let mut result : UInt = 0 - for i in 0..=3 { - result = result | (bytes.unsafe_get(i + index).to_uint() << (8 * (3 - i))) - } - result -} - -///| -/// **UNSAFE**: Reads a UInt16 from the bytes in little-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory -/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures -/// - **Responsibility**: Caller must ensure sufficient bytes are available -/// -/// # Parameters -/// - `bytes`: The Bytes to read from -/// - `index`: Starting byte index (0-based) -/// -/// # Behavior -/// Reads 2 bytes starting at `index` and interprets them as a UInt16 in little-endian order: -/// - `bytes[index]` → bits 0-7 (least significant) -/// - `bytes[index+1]` → bits 8-15 (most significant) -#intrinsic("%bytes.unsafe_read_uint16_le") -#doc(hidden) -pub fn Bytes::unsafe_read_uint16_le(bytes : Bytes, index : Int) -> UInt16 { - let mut result : UInt16 = 0 - for i in 0..=1 { - result = result | (bytes.unsafe_get(i + index).to_uint16() << (8 * i)) - } - result -} - -///| -/// **UNSAFE**: Reads a UInt16 from the bytes in big-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the buffer boundary may access invalid memory -/// - **Alignment**: No alignment requirements, but misaligned access may be slower on some architectures -/// - **Responsibility**: Caller must ensure sufficient bytes are available -/// -/// # Parameters -/// - `bytes`: The Bytes to read from -/// - `index`: Starting byte index (0-based) -/// -/// # Behavior -/// Reads 2 bytes starting at `index` and interprets them as a UInt16 in big-endian order: -/// - `bytes[index]` → bits 8-15 (most significant) -/// - `bytes[index+1]` → bits 0-7 (least significant) -#intrinsic("%bytes.unsafe_read_uint16_be") -#doc(hidden) -pub fn Bytes::unsafe_read_uint16_be(bytes : Bytes, index : Int) -> UInt16 { - let mut result : UInt16 = 0 - for i in 0..=1 { - result = result | (bytes.unsafe_get(i + index).to_uint16() << (8 * (1 - i))) - } - result -} - -///| -/// **UNSAFE**: Reads a UInt64 from the BytesView in little-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory -/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view -/// -/// # Parameters -/// - `bytes`: The BytesView to read from -/// - `index`: Relative index within the view (0-based) -/// -/// # Note -/// This function delegates to `Bytes::unsafe_read_uint64_le` with the proper offset calculation. -#doc(hidden) -pub fn BytesView::unsafe_read_uint64_le( - bytes : BytesView, - index : Int, -) -> UInt64 { - bytes.bytes().unsafe_read_uint64_le(bytes.start() + index) -} - -///| -/// **UNSAFE**: Reads a UInt64 from the BytesView in big-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 7 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory -/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view -/// -/// # Parameters -/// - `bytes`: The BytesView to read from -/// - `index`: Relative index within the view (0-based) -/// -/// # Note -/// This function delegates to `Bytes::unsafe_read_uint64_be` with the proper offset calculation. -#doc(hidden) -pub fn BytesView::unsafe_read_uint64_be( - bytes : BytesView, - index : Int, -) -> UInt64 { - bytes.bytes().unsafe_read_uint64_be(bytes.start() + index) -} - -///| -/// **UNSAFE**: Reads a UInt32 from the BytesView in little-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory -/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view -/// -/// # Parameters -/// - `bytes`: The BytesView to read from -/// - `index`: Relative index within the view (0-based) -/// -/// # Note -/// This function delegates to `Bytes::unsafe_read_uint32_le` with the proper offset calculation. -#doc(hidden) -pub fn BytesView::unsafe_read_uint32_le(bytes : BytesView, index : Int) -> UInt { - bytes.bytes().unsafe_read_uint32_le(bytes.start() + index) -} - -///| -/// **UNSAFE**: Reads a UInt32 from the BytesView in big-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 3 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory -/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view -/// -/// # Parameters -/// - `bytes`: The BytesView to read from -/// - `index`: Relative index within the view (0-based) -/// -/// # Note -/// This function delegates to `Bytes::unsafe_read_uint32_be` with the proper offset calculation. -#doc(hidden) -pub fn BytesView::unsafe_read_uint32_be(bytes : BytesView, index : Int) -> UInt { - bytes.bytes().unsafe_read_uint32_be(bytes.start() + index) -} - -///| -/// **UNSAFE**: Reads a UInt16 from the BytesView in little-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory -/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view -/// -/// # Parameters -/// - `bytes`: The BytesView to read from -/// - `index`: Relative index within the view (0-based) -/// -/// # Note -/// This function delegates to `Bytes::unsafe_read_uint16_le` with the proper offset calculation. -#doc(hidden) -pub fn BytesView::unsafe_read_uint16_le( - bytes : BytesView, - index : Int, -) -> UInt16 { - bytes.bytes().unsafe_read_uint16_le(bytes.start() + index) -} - -///| -/// **UNSAFE**: Reads a UInt16 from the BytesView in big-endian byte order. -/// -/// ⚠️ **Warning: This function is unsafe and can cause undefined behavior!** -/// -/// # Safety -/// - **No bounds checking**: This function does not verify that `index + 1 < bytes.length()` -/// - **Buffer overrun risk**: Reading beyond the view boundary may access invalid memory -/// - **Responsibility**: Caller must ensure sufficient bytes are available within the view -/// -/// # Parameters -/// - `bytes`: The BytesView to read from -/// - `index`: Relative index within the view (0-based) -/// -/// # Note -/// This function delegates to `Bytes::unsafe_read_uint16_be` with the proper offset calculation. -#doc(hidden) -pub fn BytesView::unsafe_read_uint16_be( - bytes : BytesView, - index : Int, -) -> UInt16 { - bytes.bytes().unsafe_read_uint16_be(bytes.start() + index) -}