// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. // Goroutine support for Five runtime. // Provides Go's goroutine, channel, and WaitGroup primitives // as first-class Harbour values. package hbrt import ( "sync" ) // --- Channel --- // HbChannel wraps Go's chan Value for use in PRG code. type HbChannel struct { Ch chan Value } // MakeChannel creates a channel Value with optional buffer size. func MakeChannel(size int) Value { return MakePointer(&HbChannel{Ch: make(chan Value, size)}) } // AsChannel extracts HbChannel from a Pointer value. func (v Value) AsChannel() *HbChannel { if !v.IsPointer() { return nil } if ch, ok := v.AsPointer().(*HbChannel); ok { return ch } return nil } // Send sends a value into the channel. func (ch *HbChannel) Send(val Value) { ch.Ch <- val } // Receive receives a value from the channel. func (ch *HbChannel) Receive() Value { return <-ch.Ch } // TryReceive attempts non-blocking receive. Returns (value, true) or (nil, false). func (ch *HbChannel) TryReceive() (Value, bool) { select { case v := <-ch.Ch: return v, true default: return MakeNil(), false } } // Close closes the channel. func (ch *HbChannel) Close() { close(ch.Ch) } // --- WaitGroup --- // HbWaitGroup wraps sync.WaitGroup. type HbWaitGroup struct { WG sync.WaitGroup } // MakeWaitGroup creates a WaitGroup Value with initial count. func MakeWaitGroup(n int) Value { wg := &HbWaitGroup{} if n > 0 { wg.WG.Add(n) } return MakePointer(wg) } // AsWaitGroup extracts HbWaitGroup from a Pointer value. func (v Value) AsWaitGroup() *HbWaitGroup { if !v.IsPointer() { return nil } if wg, ok := v.AsPointer().(*HbWaitGroup); ok { return wg } return nil } // --- Mutex --- // HbMutex wraps sync.Mutex. type HbMutex struct { Mu sync.Mutex } // MakeMutex creates a Mutex Value. func MakeMutex() Value { return MakePointer(&HbMutex{}) } // AsMutex extracts HbMutex from a Pointer value. func (v Value) AsMutex() *HbMutex { if !v.IsPointer() { return nil } if mu, ok := v.AsPointer().(*HbMutex); ok { return mu } return nil } // --- GoRoutine launcher --- // GoLaunch spawns a new goroutine that runs a function on a new Thread. func (vm *VM) GoLaunch(fn func(*Thread), args []Value) { go func() { t := vm.NewThread() for _, a := range args { t.push(a) } t.PendingParams2(len(args)) fn(t) }() } // GoLaunchBlock spawns a goroutine that evaluates a code block. func (vm *VM) GoLaunchBlock(blk *HbBlock, args []Value) { go func() { t := vm.NewThread() for _, a := range args { t.push(a) } t.PendingParams2(len(args)) blk.Fn(t) }() }