runtime.LockOSThread()
defer runtime.UnlockOSThread()
handle := {{ start_call }}
if handle == 0 {
if err := lastError(); err != nil {
return nil, err
}
return nil, fmt.Errorf("failed to start {{ method_name }} stream")
}
ch := make(chan {{ item_type }})
stream := &{{ stream_type_name }}{ch: ch}
go func() {
defer close(ch)
defer C.{{ fn_free }}(handle)
for {
runtime.LockOSThread()
chunkPtr := C.{{ fn_next }}(handle)
if chunkPtr == 0 {
// Null means either a clean end-of-stream (errno 0) or a stream error
// (errno != 0); read lastError() while still locked to this OS thread,
// since the native last-error slot is per-OS-thread.
stream.err = lastError()
runtime.UnlockOSThread()
return
}
jsonPtr := C.{{ item_to_json_fn }}(chunkPtr)
if jsonPtr == nil {
C.{{ item_free_fn }}(chunkPtr)
stream.err = fmt.Errorf("{{ method_name }}: stream item could not be converted to JSON")
runtime.UnlockOSThread()
return
}
{% if item_is_sum_type %}
chunk, unmarshalErr := Unmarshal{{ item_type }}([]byte(C.GoString(jsonPtr)))
{% else %}
var chunk {{ item_type }}
unmarshalErr := json.Unmarshal([]byte(C.GoString(jsonPtr)), &chunk)
{% endif %}
C.{{ free_string_fn }}(jsonPtr)
C.{{ item_free_fn }}(chunkPtr)
runtime.UnlockOSThread()
if unmarshalErr != nil {
stream.err = fmt.Errorf("{{ method_name }}: failed to decode stream item: %w", unmarshalErr)
return
}
ch <- chunk
}
}()
return stream, nil
}