chore(ax): align exported cgo comments with usage examples

- Update exported API comments to concrete usage examples for Buffer, Scope, and C conversion helpers.
- Emphasize concrete call patterns in Call/Errno/CString/SizeT docs per AX principles.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-03 19:38:58 +00:00
parent 1f5056d1aa
commit eb0494fddf
3 changed files with 42 additions and 39 deletions

View file

@ -18,15 +18,16 @@ import (
// n := buffer.CopyFrom([]byte("payload"))
// _ = buffer.Bytes()[:n]
type Buffer struct {
data []byte
length int
pointer unsafe.Pointer
freed atomic.Bool
data []byte
length int
pointer unsafe.Pointer
freed atomic.Bool
}
// NewBuffer allocates a C-backed buffer that can be passed to C safely.
// NewBuffer allocates a C-backed byte buffer for C interop.
//
// buffer := NewBuffer(32)
// input := make([]byte, 32)
// buffer := NewBuffer(len(input))
// defer buffer.Free()
func NewBuffer(size int) *Buffer {
if size < 0 {
@ -107,7 +108,7 @@ func (b *Buffer) Bytes() []byte {
// Ptr returns the raw pointer to the buffer.
//
// buffer := NewBuffer(4)
// call := buffer.Ptr()
// _ = buffer.Ptr()
func (b *Buffer) Ptr() unsafe.Pointer {
b.assertNotFreed()
return b.pointer
@ -116,7 +117,9 @@ func (b *Buffer) Ptr() unsafe.Pointer {
// Len returns the allocated byte length of the buffer.
//
// buffer := NewBuffer(4)
// if buffer.Len() == 4 { ... }
// if buffer.Len() == 4 {
// // preallocated 4-byte buffer
// }
func (b *Buffer) Len() int {
b.assertNotFreed()
return b.length
@ -125,7 +128,9 @@ func (b *Buffer) Len() int {
// IsFreed reports whether Free has already been called.
//
// buffer := NewBuffer(4)
// if buffer.IsFreed() { ... }
// if buffer.IsFreed() {
// return
// }
func (b *Buffer) IsFreed() bool {
if b == nil {
return true

View file

@ -12,20 +12,20 @@ import (
"unsafe"
)
// Scope tracks multiple allocations and releases them together.
// Scope tracks multiple C allocations and releases them together.
//
// scope := cgo.NewScope()
// defer scope.FreeAll()
// buffer := scope.Buffer(32)
// cString := scope.CString("hello")
// scope := NewScope()
// defer scope.FreeAll()
// buffer := scope.Buffer(32)
// cString := scope.CString("hello")
type Scope struct {
lock sync.Mutex
buffers []*Buffer
strings []unsafe.Pointer
freed atomic.Bool
lock sync.Mutex
buffers []*Buffer
strings []unsafe.Pointer
freed atomic.Bool
}
// NewScope creates a zero-value scope for grouped CGo allocations.
// NewScope creates a grouped allocator for temporary C memory.
//
// scope := NewScope()
// defer scope.FreeAll()
@ -37,7 +37,7 @@ func NewScope() *Scope {
return scope
}
// Buffer allocates a managed buffer and registers it for scope cleanup.
// Buffer allocates a managed buffer and registers it for cleanup.
//
// buffer := scope.Buffer(64)
func (s *Scope) Buffer(size int) *Buffer {
@ -53,7 +53,7 @@ func (s *Scope) Buffer(size int) *Buffer {
return buffer
}
// CString allocates a managed C string and registers it for scope cleanup.
// CString allocates a managed C string and registers it for cleanup.
//
// cString := scope.CString("hello")
func (s *Scope) CString(value string) *C.char {
@ -102,7 +102,9 @@ func (s *Scope) FreeAll() {
// IsFreed reports whether FreeAll has been called.
//
// if scope.IsFreed() { return }
// if scope.IsFreed() {
// // scope is inactive
// }
func (s *Scope) IsFreed() bool {
if s == nil {
return true

View file

@ -100,9 +100,9 @@ import (
"unsafe"
)
// SizeT converts a Go int into a C size_t for cgo calls.
// SizeT converts a Go int into a C size_t for C APIs.
//
// size := cgo.SizeT(len(data))
// bufferSize := SizeT(len(payload))
func SizeT(value int) C.size_t {
if value < 0 {
panic("cgo.SizeT: negative values are not representable as C.size_t")
@ -120,9 +120,9 @@ func SizeT(value int) C.size_t {
return C.size_t(value)
}
// Int converts a Go int into a C int for cgo calls.
// Int converts a Go int into a C int for C APIs.
//
// rc := cgo.Int(returnCode)
// remaining := Int(2)
func Int(value int) C.int {
cIntBits := cIntBitSize()
if cIntBits < strconv.IntSize {
@ -140,12 +140,10 @@ func cIntBitSize() int {
return int(unsafe.Sizeof(C.int(0)) * 8)
}
// Call invokes a C function pointer and maps a non-zero return into a Go error.
// Call invokes a C function pointer and maps a non-zero return code to an error.
//
// err := Call(unsafe.Pointer(C.some_function), buffer.Ptr(), SizeT(len(data)))
// if err != nil {
// return err
// }
// err := Call(unsafe.Pointer(C.some_function), buffer.Ptr(), SizeT(len(payload)))
// if err != nil { return err }
func Call(function unsafe.Pointer, args ...interface{}) error {
if function == nil {
panic("cgo.Call: function pointer is nil")
@ -829,9 +827,7 @@ func toSyscallArg(value interface{}) (uintptr, bool) {
// GoString converts a null-terminated C string to a Go string.
//
// cString := CString("example")
// result := GoString(cString)
// Free(unsafe.Pointer(cString))
// native := GoString(CString("hello"))
func GoString(cs *C.char) string {
if cs == nil {
return ""
@ -847,7 +843,7 @@ func CString(value string) *C.char {
return C.CString(value)
}
// Free releases memory previously returned by CString.
// Free releases memory previously allocated by this package.
//
// cString := CString("hello")
// Free(unsafe.Pointer(cString))
@ -858,9 +854,9 @@ func Free(ptr unsafe.Pointer) {
C.free(ptr)
}
// Errno converts a C error number to a Go error.
// Errno converts a C errno-like return value to a Go error.
//
// resultCode := Errno(-2)
// err := Errno(C.int(13))
func Errno(resultCode C.int) error {
if resultCode == 0 {
return nil
@ -874,9 +870,9 @@ func Errno(resultCode C.int) error {
return syscall.Errno(recordedCode)
}
// WithErrno runs a function that returns C.int and maps the result to Go error.
// WithErrno runs a C-style function and converts the C return value to (result, error).
//
// resultCode, err := WithErrno(func() C.int {
// result, err := WithErrno(func() C.int {
// return C.my_function()
// })
func WithErrno(fn func() C.int) (int, error) {