checker: stricter rules for C types; C aliases; sokol fixes

This commit is contained in:
Alexander Medvednikov 2023-10-14 18:31:37 +03:00
parent 5f1e6815cd
commit 545ee1ae23
27 changed files with 123 additions and 59 deletions

View file

@ -1,5 +1,5 @@
// Build with // Build with
// v -gc none -use-coroutines simple_coroutines.v // v -use-coroutines simple_coroutines.v
// //
import coroutines import coroutines
import time import time

View file

@ -329,7 +329,7 @@ fn my_init(mut app App) {
mut pipdesc := gfx.PipelineDesc{} mut pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) } unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) }
color_state := gfx.ColorState{ color_state := gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha

View file

@ -529,7 +529,7 @@ fn my_init(mut app App) {
mut pipdesc := gfx.PipelineDesc{} mut pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) } unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) }
color_state := gfx.ColorState{ color_state := gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha

View file

@ -120,7 +120,7 @@ pub fn (mut obj_part ObjPart) create_pipeline(in_part []int, shader gfx.Shader,
// pipdesc.layout.attrs[C.ATTR_vs_a_Texcoord0].format = .short2n // u,v as u16 // pipdesc.layout.attrs[C.ATTR_vs_a_Texcoord0].format = .short2n // u,v as u16
pipdesc.index_type = .uint32 pipdesc.index_type = .uint32
color_state := gfx.ColorState{ color_state := gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha

View file

@ -83,7 +83,7 @@ fn init(mut app App) {
mut pipdesc := gfx.PipelineDesc{} mut pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) } unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) }
color_state := gfx.ColorState{ color_state := gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha

View file

@ -329,7 +329,7 @@ fn app_init(mut app App) {
mut pipdesc := gfx.PipelineDesc{} mut pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) } unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) }
color_state := gfx.ColorState{ color_state := gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha

View file

@ -1,6 +1,7 @@
module builtin module builtin
// struct C.FILE {} [typedef]
pub struct C.FILE {}
// <string.h> // <string.h>
fn C.memcpy(dest voidptr, const_src voidptr, n usize) voidptr fn C.memcpy(dest voidptr, const_src voidptr, n usize) voidptr
@ -226,6 +227,8 @@ fn C.sysctl(name &int, namelen u32, oldp voidptr, oldlenp voidptr, newp voidptr,
[trusted] [trusted]
fn C._fileno(int) int fn C._fileno(int) int
struct C.intptr_t {}
fn C._get_osfhandle(fd int) C.intptr_t fn C._get_osfhandle(fd int) C.intptr_t
fn C.GetModuleFileName(hModule voidptr, lpFilename &u16, nSize u32) u32 fn C.GetModuleFileName(hModule voidptr, lpFilename &u16, nSize u32) u32

View file

@ -120,7 +120,7 @@ fn (mut container PipelineContainer) init_pipeline() {
mut alpha_pipdesc := gfx.PipelineDesc{} mut alpha_pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&alpha_pipdesc, 0, int(sizeof(alpha_pipdesc))) } unsafe { vmemset(&alpha_pipdesc, 0, int(sizeof(alpha_pipdesc))) }
alpha_pipdesc.label = c'alpha-pipeline' alpha_pipdesc.label = c'alpha-pipeline'
alpha_pipdesc.colors[0] = gfx.ColorState{ alpha_pipdesc.colors[0] = gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha
@ -133,7 +133,7 @@ fn (mut container PipelineContainer) init_pipeline() {
mut add_pipdesc := gfx.PipelineDesc{} mut add_pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&add_pipdesc, 0, int(sizeof(add_pipdesc))) } unsafe { vmemset(&add_pipdesc, 0, int(sizeof(add_pipdesc))) }
add_pipdesc.label = c'additive-pipeline' add_pipdesc.label = c'additive-pipeline'
add_pipdesc.colors[0] = gfx.ColorState{ add_pipdesc.colors[0] = gfx.ColorTargetState{
blend: gfx.BlendState{ blend: gfx.BlendState{
enabled: true enabled: true
src_factor_rgb: .src_alpha src_factor_rgb: .src_alpha

View file

@ -38,6 +38,18 @@ $if $pkgconfig('openssl') {
pub struct C.SSL { pub struct C.SSL {
} }
[typedef]
pub struct C.BIO {
}
[typedef]
pub struct C.SSL_METHOD {
}
[typedef]
pub struct C.X509 {
}
[typedef] [typedef]
pub struct C.SSL_CTX { pub struct C.SSL_CTX {
} }

View file

@ -217,14 +217,14 @@ pub fn stderr() File {
// eof returns true, when the end of file has been reached // eof returns true, when the end of file has been reached
pub fn (f &File) eof() bool { pub fn (f &File) eof() bool {
cfile := &C.FILE(f.cfile) cfile := unsafe { &C.FILE(f.cfile) }
return C.feof(cfile) != 0 return C.feof(cfile) != 0
} }
// reopen allows a `File` to be reused. It is mostly useful for reopening standard input and output. // reopen allows a `File` to be reused. It is mostly useful for reopening standard input and output.
pub fn (mut f File) reopen(path string, mode string) ! { pub fn (mut f File) reopen(path string, mode string) ! {
p := fix_windows_path(path) p := fix_windows_path(path)
mut cfile := &C.FILE(0) mut cfile := &C.FILE(unsafe { nil })
$if windows { $if windows {
cfile = C._wfreopen(p.to_wide(), mode.to_wide(), f.cfile) cfile = C._wfreopen(p.to_wide(), mode.to_wide(), f.cfile)
} $else { } $else {
@ -242,13 +242,13 @@ pub fn (f &File) read(mut buf []u8) !int {
return Eof{} return Eof{}
} }
// the following is needed, because on FreeBSD, C.feof is a macro: // the following is needed, because on FreeBSD, C.feof is a macro:
nbytes := int(C.fread(buf.data, 1, buf.len, &C.FILE(f.cfile))) nbytes := int(C.fread(buf.data, 1, buf.len, unsafe { &C.FILE(f.cfile) }))
// if no bytes were read, check for errors and end-of-file. // if no bytes were read, check for errors and end-of-file.
if nbytes <= 0 { if nbytes <= 0 {
if C.feof(&C.FILE(f.cfile)) != 0 { if C.feof(unsafe { &C.FILE(f.cfile) }) != 0 {
return Eof{} return Eof{}
} }
if C.ferror(&C.FILE(f.cfile)) != 0 { if C.ferror(unsafe { &C.FILE(f.cfile) }) != 0 {
return NotExpected{ return NotExpected{
cause: 'unexpected error from fread' cause: 'unexpected error from fread'
code: -1 code: -1
@ -466,7 +466,7 @@ pub fn (f &File) read_bytes_into_newline(mut buf []u8) !int {
mut buf_ptr := 0 mut buf_ptr := 0
mut nbytes := 0 mut nbytes := 0
stream := &C.FILE(f.cfile) stream := unsafe { &C.FILE(f.cfile) }
for (buf_ptr < buf.len) { for (buf_ptr < buf.len) {
c = C.getc(stream) c = C.getc(stream)
match c { match c {

View file

@ -335,7 +335,7 @@ pub fn fileno(cfile voidptr) int {
$if windows { $if windows {
return C._fileno(cfile) return C._fileno(cfile)
} $else { } $else {
mut cfile_casted := &C.FILE(0) // FILE* cfile_casted = 0; mut cfile_casted := &C.FILE(unsafe { nil }) // FILE* cfile_casted = 0;
cfile_casted = cfile cfile_casted = cfile
// Required on FreeBSD/OpenBSD/NetBSD as stdio.h defines fileno(..) with a macro // Required on FreeBSD/OpenBSD/NetBSD as stdio.h defines fileno(..) with a macro
// that performs a field access on its argument without casting from void*. // that performs a field access on its argument without casting from void*.

View file

@ -14,6 +14,9 @@ struct C.vm_statistics64_data_t {
external_page_count u32 external_page_count u32
} }
[typedef]
struct C.host_t {}
fn C.mach_host_self() C.host_t fn C.mach_host_self() C.host_t
fn C.host_page_size(host C.host_t, out_page_size &C.vm_size_t) int fn C.host_page_size(host C.host_t, out_page_size &C.vm_size_t) int
fn C.host_statistics64(host C.host_t, flavor int, host_info_out &int, host_info_outCnt &u32) int fn C.host_statistics64(host C.host_t, flavor int, host_info_out &int, host_info_outCnt &u32) int

View file

@ -216,7 +216,7 @@ pub enum VertexFormat as u32 {
float3 float3
float4 float4
byte4 byte4
byte4n byte4n // normalized
ubyte4 ubyte4
ubyte4n ubyte4n
short2 short2
@ -266,11 +266,11 @@ pub enum CullMode as u32 {
// FaceWindin is C.sg_face_winding // FaceWindin is C.sg_face_winding
pub enum FaceWinding as u32 { pub enum FaceWinding as u32 {
_facewinding_default // value 0 reserved for default-init default // value 0 reserved for default-init
facewinding_ccw ccw
facewinding_cw cw
_facewinding_num num
_force_u32 = 0x7FFFFFFF force_u32 = 0x7FFFFFFF
} }
pub enum CompareFunc as u32 { pub enum CompareFunc as u32 {

View file

@ -52,12 +52,12 @@ fn C.sg_query_limits() C.sg_limits
fn C.sg_query_pixelformat(fmt PixelFormat) C.sg_pixelformat_info fn C.sg_query_pixelformat(fmt PixelFormat) C.sg_pixelformat_info
// get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID) // get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID)
fn C.sg_query_buffer_state(buf C.sg_buffer) C.sg_resource_state fn C.sg_query_buffer_state(buf C.sg_buffer) ResourceState
fn C.sg_query_image_state(img C.sg_image) C.sg_resource_state fn C.sg_query_image_state(img C.sg_image) ResourceState
fn C.sg_query_sampler_state(smp C.sg_sampler) C.sg_sampler_state fn C.sg_query_sampler_state(smp C.sg_sampler) ResourceState
fn C.sg_query_shader_state(shd C.sg_shader) C.sg_resource_state fn C.sg_query_shader_state(shd C.sg_shader) ResourceState
fn C.sg_query_pipeline_state(pip C.sg_pipeline) C.sg_resource_state fn C.sg_query_pipeline_state(pip C.sg_pipeline) ResourceState
fn C.sg_query_pass_state(pass C.sg_pass) C.sg_resource_state fn C.sg_query_pass_state(pass C.sg_pass) ResourceState
// get runtime information about a resource // get runtime information about a resource
fn C.sg_query_buffer_info(buf C.sg_buffer) C.sg_buffer_info fn C.sg_query_buffer_info(buf C.sg_buffer) C.sg_buffer_info

View file

@ -67,16 +67,16 @@ pub mut:
blend BlendState blend BlendState
} }
pub type ColorState = C.sg_color_target_state pub type ColorTargetState = C.sg_color_target_state
pub struct C.sg_pipeline_desc { pub struct C.sg_pipeline_desc {
pub mut: pub mut:
shader Shader shader Shader
layout LayoutDesc layout VertexLayoutState
depth DepthState depth DepthState
stencil StencilState stencil StencilState
color_count int color_count int
colors [4]ColorState // C.SG_MAX_COLOR_ATTACHMENTS colors [4]ColorTargetState // C.SG_MAX_COLOR_ATTACHMENTS
primitive_type PrimitiveType primitive_type PrimitiveType
index_type IndexType index_type IndexType
cull_mode CullMode cull_mode CullMode
@ -109,12 +109,14 @@ pub fn (mut p C.sg_pipeline) free() {
struct C.sg_bindings { struct C.sg_bindings {
pub mut: pub mut:
_start_canary u32
vertex_buffers [8]Buffer vertex_buffers [8]Buffer
vertex_buffer_offsets [8]int vertex_buffer_offsets [8]int
index_buffer Buffer index_buffer Buffer
index_buffer_offset int index_buffer_offset int
vs StageBindings vs StageBindings
fs StageBindings fs StageBindings
_end_canary u32
// vs_images [8]Image // old // vs_images [8]Image // old
// fs_images [8]Image // old // fs_images [8]Image // old
} }
@ -553,11 +555,11 @@ pub type Limits = C.sg_limits
pub struct C.sg_vertex_layout_state { pub struct C.sg_vertex_layout_state {
pub mut: pub mut:
buffers [8]BufferLayoutDesc buffers [8]VertexBufferLayoutState
attrs [16]VertexAttrDesc attrs [16]VertexAttrDesc
} }
pub type LayoutDesc = C.sg_vertex_layout_state pub type VertexLayoutState = C.sg_vertex_layout_state
pub struct C.sg_vertex_buffer_layout_state { pub struct C.sg_vertex_buffer_layout_state {
pub mut: pub mut:
@ -566,7 +568,7 @@ pub mut:
step_rate int step_rate int
} }
pub type BufferLayoutDesc = C.sg_vertex_buffer_layout_state pub type VertexBufferLayoutState = C.sg_vertex_buffer_layout_state
pub struct C.sg_vertex_attr_state { pub struct C.sg_vertex_attr_state {
pub mut: pub mut:
@ -695,3 +697,8 @@ pub:
} }
pub type CommitListener = C.sg_commit_listener pub type CommitListener = C.sg_commit_listener
pub struct C.sg_trace_hooks {}
// pub struct C.sg_resource_state {} enum
pub struct C.sg_sampler_info {}

View file

@ -2,11 +2,11 @@ module sgl
// SglError is C.sgl_error_t // SglError is C.sgl_error_t
pub enum SglError { pub enum SglError {
no_error = C.SGL_NO_ERROR // 0 no_error = C.SGL_NO_ERROR // 0
vertices_full = C.SGL_ERROR_VERTICES_FULL vertices_full = C.SGL_ERROR_VERTICES_FULL
uniforms_full = C.SGL_ERROR_UNIFORMS_FULL uniforms_full = C.SGL_ERROR_UNIFORMS_FULL
commands_full = C.SGL_ERROR_COMMANDS_FULL commands_full = C.SGL_ERROR_COMMANDS_FULL
stack_overflow = C.SGL_ERROR_STACK_OVERFLOW stack_overflow = C.SGL_ERROR_STACK_OVERFLOW
stack_underfloat = C.SGL_ERROR_STACK_UNDERFLOW stack_underflow = C.SGL_ERROR_STACK_UNDERFLOW
no_context = C.SGL_ERROR_NO_CONTEXT no_context = C.SGL_ERROR_NO_CONTEXT
} }

View file

@ -3,8 +3,8 @@ module sgl
// setup/shutdown/misc // setup/shutdown/misc
fn C.sgl_setup(desc &C.sgl_desc_t) fn C.sgl_setup(desc &C.sgl_desc_t)
fn C.sgl_shutdown() fn C.sgl_shutdown()
fn C.sgl_error() C.sgl_error_t fn C.sgl_error() SglError
fn C.sgl_context_error(ctx C.sgl_context) C.sgl_error_t fn C.sgl_context_error(ctx C.sgl_context) SglError
fn C.sgl_rad(deg f32) f32 fn C.sgl_rad(deg f32) f32
fn C.sgl_deg(rad f32) f32 fn C.sgl_deg(rad f32) f32

View file

@ -31,6 +31,9 @@ pub enum Direction {
push push
} }
[typedef]
struct C.atomic_uintptr_t {}
pub struct Channel { pub struct Channel {
ringbuf &u8 = unsafe { nil } // queue for buffered channels ringbuf &u8 = unsafe { nil } // queue for buffered channels
statusbuf &u8 = unsafe { nil } // flags to synchronize write/read in ringbuf statusbuf &u8 = unsafe { nil } // flags to synchronize write/read in ringbuf

View file

@ -61,6 +61,9 @@ struct RwMutexAttr {
attr C.pthread_rwlockattr_t attr C.pthread_rwlockattr_t
} }
[typedef]
struct C.pthread_condattr_t {}
struct CondAttr { struct CondAttr {
attr C.pthread_condattr_t attr C.pthread_condattr_t
} }

View file

@ -22,9 +22,16 @@ type MHANDLE = voidptr
// Semaphore HANDLE // Semaphore HANDLE
type SHANDLE = voidptr type SHANDLE = voidptr
[typedef]
struct C.SRWLOCK {}
[typedef]
struct C.CONDITION_VARIABLE {}
//[init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function. //[init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function.
// `SRWLOCK` is much more performant that `Mutex` on Windows, so use that in both cases since we don't want to share with other processes // `SRWLOCK` is much more performant that `Mutex` on Windows, so use that in both cases since we don't
// want to share with other processes
[heap] [heap]
pub struct Mutex { pub struct Mutex {
mut: mut:

View file

@ -14,6 +14,10 @@ pub struct C.timeval {
fn C.localtime(t &C.time_t) &C.tm fn C.localtime(t &C.time_t) &C.tm
fn C.localtime_r(t &C.time_t, tm &C.tm) fn C.localtime_r(t &C.time_t, tm &C.tm)
// struct C.time_t {}
// type C.time_t = i64
fn C.time(t &C.time_t) C.time_t fn C.time(t &C.time_t) C.time_t
fn C.gmtime(t &C.time_t) &C.tm fn C.gmtime(t &C.time_t) &C.tm

View file

@ -26,7 +26,7 @@ fn C.timegm(&C.tm) C.time_t
fn C.localtime_r(t &C.time_t, tm &C.tm) fn C.localtime_r(t &C.time_t, tm &C.tm)
fn make_unix_time(t C.tm) i64 { fn make_unix_time(t C.tm) i64 {
return i64(C.timegm(&t)) return unsafe { i64(C.timegm(&t)) }
} }
// local returns t with the location set to local time. // local returns t with the location set to local time.

View file

@ -54,9 +54,9 @@ struct C.timespec {
tv_nsec i64 tv_nsec i64
} }
fn C.QueryPerformanceCounter(&u64) C.BOOL fn C.QueryPerformanceCounter(&u64) bool
fn C.QueryPerformanceFrequency(&u64) C.BOOL fn C.QueryPerformanceFrequency(&u64) bool
fn make_unix_time(t C.tm) i64 { fn make_unix_time(t C.tm) i64 {
return portable_timegm(&t) return portable_timegm(&t)

View file

@ -760,8 +760,10 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
c.error('enums can only be assigned `int` values', right.pos()) c.error('enums can only be assigned `int` values', right.pos())
} }
} else { } else {
if !var_option || (var_option && right_type_unwrapped != ast.none_type) { if right_type_unwrapped != ast.void_type {
c.error('cannot assign to `${left}`: ${err.msg()}', right.pos()) if !var_option || (var_option && right_type_unwrapped != ast.none_type) {
c.error('cannot assign to `${left}`: ${err.msg()}', right.pos())
}
} }
} }
} }

View file

@ -500,9 +500,9 @@ fn (mut c Checker) type_decl(node ast.TypeDecl) {
fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) { fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
// TODO Remove when `u8` isn't an alias in builtin anymore // TODO Remove when `u8` isn't an alias in builtin anymore
if c.file.mod.name != 'builtin' { // if c.file.mod.name != 'builtin' {
c.check_valid_pascal_case(node.name, 'type alias', node.pos) // c.check_valid_pascal_case(node.name, 'type alias', node.pos)
} //}
if !c.ensure_type_exists(node.parent_type, node.type_pos) { if !c.ensure_type_exists(node.parent_type, node.type_pos) {
return return
} }
@ -4700,10 +4700,23 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) bool {
} }
match sym.kind { match sym.kind {
.placeholder { .placeholder {
if sym.language == .v && !sym.name.starts_with('C.') { if sym.language == .c && sym.name == 'C.time_t' {
// TODO temporary hack until we can define C aliases
return true
}
// if sym.language == .v && !sym.name.starts_with('C.') {
// if sym.language in [.v, .c] {
if sym.language == .v {
c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `${sym.name}`'), c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `${sym.name}`'),
pos) pos)
return false return false
} else if sym.language == .c {
c.warn(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `${sym.name}` (all virtual C types must be defined, this will be an error soon)'),
pos)
// dump(sym)
// for _, t in c.table.type_symbols {
// println(t.name)
//}
} }
} }
.int_literal, .float_literal { .int_literal, .float_literal {

View file

@ -4127,11 +4127,18 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
if p.disallow_declarations_in_script_mode() { if p.disallow_declarations_in_script_mode() {
return ast.SumTypeDecl{} return ast.SumTypeDecl{}
} }
name := p.check_name() mut name := p.check_name()
mut language := ast.Language.v
if name.len == 1 && name[0].is_capital() { if name.len == 1 && name[0].is_capital() {
p.error_with_pos('single letter capital names are reserved for generic template types', if name == 'C' && p.tok.kind == .dot {
name_pos) p.next() // .
return ast.FnTypeDecl{} name = 'C.' + p.check_name()
language = .c
} else {
p.error_with_pos('1single letter capital names are reserved for generic template types',
name_pos)
return ast.FnTypeDecl{}
}
} }
if name in p.imported_symbols { if name in p.imported_symbols {
p.error_with_pos('cannot register alias `${name}`, this type was already imported', p.error_with_pos('cannot register alias `${name}`, this type was already imported',
@ -4216,7 +4223,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
parent_sym := p.table.sym(parent_type) parent_sym := p.table.sym(parent_type)
pidx := parent_type.idx() pidx := parent_type.idx()
p.check_for_impure_v(parent_sym.language, decl_pos) p.check_for_impure_v(parent_sym.language, decl_pos)
prepend_mod_name := p.prepend_mod(name) prepend_mod_name := if language == .v { p.prepend_mod(name) } else { name } // `C.time_t`, not `time.C.time_t`
idx := p.table.register_sym(ast.TypeSymbol{ idx := p.table.register_sym(ast.TypeSymbol{
kind: .alias kind: .alias
name: prepend_mod_name name: prepend_mod_name

View file

@ -20,7 +20,7 @@ fn C.pthread_self() u64
// windows: // windows:
fn C.GetCurrentThreadId() u32 fn C.GetCurrentThreadId() u32
fn C.QueryPerformanceCounter(&u64) C.BOOL fn C.QueryPerformanceCounter(&u64) bool
[markused] [markused]
pub fn on_call(fname string) { pub fn on_call(fname string) {