package main

/*
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

static unsigned int sum_bytes(const unsigned char *p, size_t n) {
    unsigned int sum = 0;
    for (size_t i = 0; i < n; i++) sum += p[i];
    return sum;
}
static uintptr_t echo_handle(uintptr_t h) { return h; }
static unsigned char *saved;
static void retain(unsigned char *p) { saved = p; }
static unsigned char read_saved(void) { return *saved; }
static void release_saved(void) { saved = NULL; }
*/
import "C"

import (
	"fmt"
	"runtime"
	"runtime/cgo"
	"unsafe"
)

func sumBytes(b []byte) uint32 {
	if len(b) == 0 {
		return 0
	}
	return uint32(C.sum_bytes((*C.uchar)(unsafe.Pointer(&b[0])), C.size_t(len(b))))
}

func cStringLen(s string) int {
	p := C.CString(s)
	defer C.free(unsafe.Pointer(p))
	return int(C.strlen(p))
}

func handleRoundTrip(value string) string {
	h := cgo.NewHandle(value)
	defer h.Delete()
	returned := C.echo_handle(C.uintptr_t(h))
	return cgo.Handle(returned).Value().(string)
}

// Single-caller demonstration: the C global saved is not concurrency-safe.
func retainedByte() byte {
	b := []byte{7}
	var pin runtime.Pinner
	pin.Pin(&b[0])
	defer pin.Unpin()
	C.retain((*C.uchar)(unsafe.Pointer(&b[0])))
	defer C.release_saved() // Runs before Unpin because defers run in reverse order.
	runtime.GC()
	return byte(C.read_saved())
}

func main() {
	fmt.Println("sum:", sumBytes([]byte{1, 2, 3}), "empty:", sumBytes(nil))
	fmt.Println("C strlen:", cStringLen("Go\x00lang"))
	fmt.Println("handle:", handleRoundTrip("request-42"))
	fmt.Println("retained:", retainedByte())
}
