diff --git a/src/internal/c_buffer/README.mbt.md b/src/internal/c_buffer/README.mbt.md new file mode 100644 index 00000000..db603f17 --- /dev/null +++ b/src/internal/c_buffer/README.mbt.md @@ -0,0 +1,39 @@ +# internal/c_buffer + +Internal wrapper for C-allocated byte buffers. + +## Overview + +`@internal/c_buffer` exposes an opaque `Buffer` type and a small set of +FFI-backed helpers used throughout the async runtime. These APIs are unsafe: +they operate on raw pointers and assume correct size, lifetime, and +null-termination guarantees from native code. + +This package is **native-only**. The JavaScript backend is not supported. + +## API Summary + +- `Buffer`: opaque C pointer +- `blit_from_bytes`: copy MoonBit `Bytes` into a C buffer +- `blit_to_bytes`: copy C buffer content into a MoonBit `FixedArray[Byte]` +- `get`: read a single byte by index +- `strlen`: length of a NUL-terminated C string +- `null`, `is_null`, `free` + +## Safety and Ownership + +- `Buffer` values are raw pointers; no bounds checks are performed. +- `free` must only be called on memory allocated by `malloc` or a compatible + allocator. Passing `null` is allowed. +- `strlen` requires a valid NUL-terminated sequence. + +## Examples + +```mbt check +///| +#cfg(not(target="js")) +test "null helpers" { + inspect(@c_buffer.Buffer::is_null(@c_buffer.null), content="true") + @c_buffer.Buffer::free(@c_buffer.null) +} +``` diff --git a/src/internal/c_buffer/c_buffer.mbt b/src/internal/c_buffer/c_buffer.mbt index 41ec85e1..cf6c1324 100644 --- a/src/internal/c_buffer/c_buffer.mbt +++ b/src/internal/c_buffer/c_buffer.mbt @@ -13,10 +13,31 @@ // limitations under the License. ///| +/// Opaque handle to a native C buffer. +/// +/// `Buffer` represents a raw pointer managed by native code. All functions in +/// this package assume the pointer is valid and sized appropriately. It is an +/// internal FFI helper, not a general-purpose memory container. +/// +/// # Example +/// ```mbt nocheck +/// test { +/// let ptr : Buffer = null +/// inspect(Buffer::is_null(ptr), content="true") +/// } +/// ``` #external pub type Buffer ///| +/// Copy bytes from a MoonBit `Bytes` into a C buffer. +/// +/// `offset` and `len` select a range within `src`. The destination buffer must +/// have at least `len` bytes available. +/// +/// # Safety +/// `dst` must be a valid writable buffer; `src` must be valid for the requested +/// range. #borrow(src) pub extern "C" fn Buffer::blit_from_bytes( dst : Buffer, @@ -26,6 +47,13 @@ pub extern "C" fn Buffer::blit_from_bytes( ) = "moonbitlang_async_blit_to_c" ///| +/// Copy bytes from a C buffer into a MoonBit fixed array. +/// +/// The destination array must have enough room for `len` bytes starting at +/// `offset`. +/// +/// # Safety +/// `src` must be a valid readable buffer containing at least `len` bytes. #borrow(dst) pub extern "C" fn Buffer::blit_to_bytes( src : Buffer, @@ -35,21 +63,51 @@ pub extern "C" fn Buffer::blit_to_bytes( ) = "moonbitlang_async_blit_from_c" ///| +/// Read a single byte from the buffer at `index`. +/// +/// # Safety +/// `buf` must be valid and the index must be within bounds of the allocated +/// buffer. #borrow(buf) #alias("_[_]") pub extern "C" fn Buffer::get(buf : Buffer, index : Int) -> Byte = "moonbitlang_async_c_buffer_get" ///| +/// Measure the length of a NUL-terminated C string. +/// +/// # Safety +/// `buf` must point to a valid NUL-terminated byte sequence. pub extern "C" fn Buffer::strlen(buf : Buffer) -> Int = "moonbitlang_async_strlen" ///| extern "C" fn Buffer::null() -> Buffer = "moonbitlang_async_null_pointer" ///| +/// A null C pointer for use with `Buffer`. +/// +/// # Example +/// ```mbt nocheck +/// test { +/// inspect(Buffer::is_null(null), content="true") +/// Buffer::free(null) +/// } +/// ``` pub let null : Buffer = Buffer::null() ///| +/// Check whether the pointer is null. +/// +/// # Example +/// ```mbt nocheck +/// test { +/// let ptr = null +/// inspect(Buffer::is_null(ptr), content="true") +/// } +/// ``` pub extern "C" fn Buffer::is_null(ptr : Buffer) -> Bool = "moonbitlang_async_pointer_is_null" ///| +/// Free a C buffer allocated with `malloc` or compatible APIs. +/// +/// Passing `null` is allowed and has no effect. pub extern "C" fn Buffer::free(buf : Buffer) = "free"