// Copyright 2026 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.
///|
/// Memory ownership mode for blob data.
pub enum MemoryMode {
Duplicate
Readonly
Writable
ReadonlyMayMakeWritable
} derive(Eq, Show, ToJson)
///|
suberror BlobError {
OutOfBounds
} derive(Eq, Show, ToJson)
///|
/// Blob wraps binary data with a view range.
pub struct Blob {
bytes : Bytes
offset : Int
length : Int
mode : MemoryMode
} derive(Eq, Show, ToJson)
///|
/// Create a blob from bytes.
pub fn Blob::from_bytes(
bytes : Bytes,
mode? : MemoryMode = MemoryMode::Readonly,
) -> Blob {
Blob::{ bytes, offset: 0, length: bytes.length(), mode }
}
///|
/// Create a blob by copying bytes.
pub fn Blob::from_bytes_copy(bytes : Bytes) -> Blob {
let copy = Bytes::from_array(bytes.to_array())
Blob::from_bytes(copy, mode=MemoryMode::Duplicate)
}
///|
/// Create a blob from a byte array view.
pub fn Blob::from_array(
bytes : ArrayView[Byte],
mode? : MemoryMode = MemoryMode::Readonly,
) -> Blob {
Blob::from_bytes(Bytes::from_array(bytes), mode~)
}
///|
/// Create a sub-blob.
pub fn Blob::sub(
self : Blob,
offset : Int,
length : Int,
) -> Result[Blob, BlobError] {
if offset < 0 || length < 0 {
return Err(OutOfBounds)
}
if offset > self.length {
return Err(OutOfBounds)
}
let end = offset + length
if end > self.length {
return Err(OutOfBounds)
}
Ok(Blob::{
bytes: self.bytes,
offset: self.offset + offset,
length,
mode: MemoryMode::Readonly,
})
}
///|
/// Return the blob length in bytes.
pub fn Blob::len(self : Blob) -> Int {
self.length
}
///|
/// Return true when empty.
pub fn Blob::is_empty(self : Blob) -> Bool {
self.length == 0
}
///|
/// Get a view of the blob bytes.
pub fn Blob::as_view(self : Blob) -> BytesView {
self.bytes.sub(start=self.offset, end=self.offset + self.length)
}
///|
/// Copy the blob into a new Bytes value.
pub fn Blob::to_bytes(self : Blob) -> Bytes {
self.as_view().to_bytes()
}
///|
/// Raw byte access with bounds checking.
pub fn Blob::get(self : Blob, index : Int) -> Byte? {
if index < 0 || index >= self.length {
None
} else {
self.bytes.get(self.offset + index)
}
}
///|
/// Access the memory mode.
pub fn Blob::memory_mode(self : Blob) -> MemoryMode {
self.mode
}