mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: disallow struct int to ptr outside unsafe (#17923)
This commit is contained in:
parent
92cb7468ce
commit
3d99f1f2c2
@ -704,7 +704,7 @@ const (
|
||||
)
|
||||
|
||||
fn init_settings() {
|
||||
mut s := &VpmSettings(0)
|
||||
mut s := &VpmSettings(unsafe { nil })
|
||||
unsafe {
|
||||
s = settings
|
||||
}
|
||||
|
@ -6188,12 +6188,12 @@ fn my_callback(arg voidptr, howmany int, cvalues &&char, cnames &&char) int {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
db := &C.sqlite3(0) // this means `sqlite3* db = 0`
|
||||
db := &C.sqlite3(unsafe { nil }) // this means `sqlite3* db = 0`
|
||||
// passing a string literal to a C function call results in a C string, not a V string
|
||||
C.sqlite3_open(c'users.db', &db)
|
||||
// C.sqlite3_open(db_path.str, &db)
|
||||
query := 'select count(*) from users'
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
// Note: You can also use the `.str` field of a V string,
|
||||
// to get its C style zero terminated representation
|
||||
C.sqlite3_prepare_v2(db, &char(query.str), -1, &stmt, 0)
|
||||
|
@ -28,7 +28,7 @@ pub fn (mut s System) init(sc SystemConfig) {
|
||||
}
|
||||
|
||||
pub fn (mut s System) update(dt f64) {
|
||||
mut p := &Particle(0)
|
||||
mut p := &Particle(unsafe { nil })
|
||||
mut moved := 0
|
||||
for i := 0; i < s.pool.len; i++ {
|
||||
p = s.pool[i]
|
||||
@ -70,7 +70,7 @@ pub fn (mut s System) reset() {
|
||||
pub fn (mut s System) explode(x f32, y f32) {
|
||||
mut reserve := 500
|
||||
center := vec.Vec2[f64]{x, y}
|
||||
mut p := &Particle(0)
|
||||
mut p := &Particle(unsafe { nil })
|
||||
mut moved := 0
|
||||
for i := 0; i < s.bin.len && reserve > 0; i++ {
|
||||
p = s.bin[i]
|
||||
|
@ -70,7 +70,7 @@ fn new_node() &mapnode {
|
||||
fn (mut m SortedMap) set(key string, value voidptr) {
|
||||
mut node := m.root
|
||||
mut child_index := 0
|
||||
mut parent := &mapnode(0)
|
||||
mut parent := &mapnode(unsafe { nil })
|
||||
for {
|
||||
if node.len == max_len {
|
||||
if parent == unsafe { nil } {
|
||||
@ -228,7 +228,7 @@ fn (mut n mapnode) remove_key(k string) bool {
|
||||
n.fill(idx)
|
||||
}
|
||||
|
||||
mut node := &mapnode(0)
|
||||
mut node := &mapnode(unsafe { nil })
|
||||
if flag && idx > n.len {
|
||||
node = unsafe { &mapnode(n.children[idx - 1]) }
|
||||
} else {
|
||||
|
@ -63,7 +63,7 @@ fn C.mysql_stmt_next_result(&C.MYSQL_STMT) int
|
||||
fn C.mysql_stmt_store_result(&C.MYSQL_STMT) int
|
||||
|
||||
pub struct Stmt {
|
||||
stmt &C.MYSQL_STMT = &C.MYSQL_STMT(0)
|
||||
stmt &C.MYSQL_STMT = &C.MYSQL_STMT(unsafe { nil })
|
||||
query string
|
||||
mut:
|
||||
binds []C.MYSQL_BIND
|
||||
|
@ -127,7 +127,7 @@ fn C.sqlite3_changes(&C.sqlite3) int
|
||||
|
||||
// connect Opens the connection with a database.
|
||||
pub fn connect(path string) !DB {
|
||||
db := &C.sqlite3(0)
|
||||
db := &C.sqlite3(unsafe { nil })
|
||||
code := C.sqlite3_open(&char(path.str), &db)
|
||||
if code != 0 {
|
||||
return &SQLError{
|
||||
@ -182,7 +182,7 @@ pub fn (db &DB) get_affected_rows_count() int {
|
||||
|
||||
// q_int returns a single integer value, from the first column of the result of executing `query`
|
||||
pub fn (db &DB) q_int(query string) int {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
defer {
|
||||
C.sqlite3_finalize(stmt)
|
||||
}
|
||||
@ -195,7 +195,7 @@ pub fn (db &DB) q_int(query string) int {
|
||||
|
||||
// q_string returns a single string value, from the first column of the result of executing `query`
|
||||
pub fn (db &DB) q_string(query string) string {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
defer {
|
||||
C.sqlite3_finalize(stmt)
|
||||
}
|
||||
@ -210,7 +210,7 @@ pub fn (db &DB) q_string(query string) string {
|
||||
// Result codes: https://www.sqlite.org/rescode.html
|
||||
[manualfree]
|
||||
pub fn (db &DB) exec(query string) ([]Row, int) {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
defer {
|
||||
C.sqlite3_finalize(stmt)
|
||||
}
|
||||
@ -278,7 +278,7 @@ pub fn (db &DB) error_message(code int, query string) IError {
|
||||
// Use it, in case you don't expect any row results, but still want a result code.
|
||||
// e.g. for queries like these: `INSERT INTO ... VALUES (...)`
|
||||
pub fn (db &DB) exec_none(query string) int {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
|
||||
code := C.sqlite3_step(stmt)
|
||||
C.sqlite3_finalize(stmt)
|
||||
|
@ -8,7 +8,7 @@ fn C.sqlite3_bind_text(&C.sqlite3_stmt, int, &char, int, voidptr) int
|
||||
// Only for V ORM
|
||||
fn (db &DB) init_stmt(query string) (&C.sqlite3_stmt, int) {
|
||||
// println('init_stmt("$query")')
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
err := C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
|
||||
return stmt, err
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ pub enum OpenModeFlag {
|
||||
// connect_full Opens connection to sqlite database. It gives more control than `open`.
|
||||
// Flags give control over readonly and create decisions. Specific VFS can be chosen.
|
||||
pub fn connect_full(path string, mode_flags []OpenModeFlag, vfs_name string) !DB {
|
||||
db := &C.sqlite3(0)
|
||||
db := &C.sqlite3(unsafe { nil })
|
||||
|
||||
mut flags := 0
|
||||
|
||||
|
@ -1355,7 +1355,7 @@ fn (mut dl Dlmalloc) segment_holding(ptr voidptr) &Segment {
|
||||
}
|
||||
sp = sp.next
|
||||
}
|
||||
return &Segment(0)
|
||||
return &Segment(unsafe { nil })
|
||||
}
|
||||
|
||||
// realloc behaves as libc realloc, but operates within the given space
|
||||
|
@ -194,7 +194,7 @@ pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr {
|
||||
hints.ai_socktype = int(typ)
|
||||
hints.ai_flags = C.AI_PASSIVE
|
||||
|
||||
results := &C.addrinfo(0)
|
||||
results := &C.addrinfo(unsafe { nil })
|
||||
|
||||
sport := '${port}'
|
||||
|
||||
|
@ -70,7 +70,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||
// infinite timeout is signaled by passing null as the timeout to
|
||||
// select
|
||||
if timeout == net.infinite_timeout {
|
||||
timeval_timeout = &C.timeval(0)
|
||||
timeval_timeout = &C.timeval(unsafe { nil })
|
||||
}
|
||||
|
||||
match test {
|
||||
|
@ -379,7 +379,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||
// infinite timeout is signaled by passing null as the timeout to
|
||||
// select
|
||||
if timeout == net.infinite_timeout {
|
||||
timeval_timeout = &C.timeval(0)
|
||||
timeval_timeout = &C.timeval(unsafe { nil })
|
||||
}
|
||||
|
||||
match test {
|
||||
|
@ -5,7 +5,7 @@ struct Abc {
|
||||
}
|
||||
|
||||
fn test_printing_struct_with_reference_field_of_type_ssl_ctx() {
|
||||
a := Abc{&C.SSL_CTX(123)}
|
||||
a := unsafe { Abc{&C.SSL_CTX(123)} }
|
||||
dump(a)
|
||||
sa := a.str()
|
||||
assert sa.contains('&C.SSL_CTX(0x7b)')
|
||||
|
@ -436,7 +436,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||
// infinite timeout is signaled by passing null as the timeout to
|
||||
// select
|
||||
if timeout == net.infinite_timeout {
|
||||
timeval_timeout = &C.timeval(0)
|
||||
timeval_timeout = &C.timeval(unsafe { nil })
|
||||
}
|
||||
|
||||
match test {
|
||||
|
@ -42,7 +42,7 @@ fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||
// infinite timeout is signaled by passing null as the timeout to
|
||||
// select
|
||||
if timeout == unix.infinite_timeout {
|
||||
timeval_timeout = &C.timeval(0)
|
||||
timeval_timeout = &C.timeval(unsafe { nil })
|
||||
}
|
||||
|
||||
match test {
|
||||
|
@ -272,7 +272,7 @@ pub fn ls(path string) ![]string {
|
||||
if isnil(dir) {
|
||||
return error('ls() couldnt open dir "${path}"')
|
||||
}
|
||||
mut ent := &C.dirent(0)
|
||||
mut ent := &C.dirent(unsafe { nil })
|
||||
// mut ent := &C.dirent{!}
|
||||
for {
|
||||
ent = C.readdir(dir)
|
||||
|
@ -126,7 +126,7 @@ fn C.sqlite3_changes(&C.sqlite3) int
|
||||
|
||||
// connect Opens the connection with a database.
|
||||
pub fn connect(path string) !DB {
|
||||
db := &C.sqlite3(0)
|
||||
db := &C.sqlite3(unsafe { nil })
|
||||
code := C.sqlite3_open(&char(path.str), &db)
|
||||
if code != 0 {
|
||||
return &SQLError{
|
||||
@ -181,7 +181,7 @@ pub fn (db &DB) get_affected_rows_count() int {
|
||||
|
||||
// Returns a single cell with value int.
|
||||
pub fn (db &DB) q_int(query string) int {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
defer {
|
||||
C.sqlite3_finalize(stmt)
|
||||
}
|
||||
@ -194,7 +194,7 @@ pub fn (db &DB) q_int(query string) int {
|
||||
|
||||
// Returns a single cell with value string.
|
||||
pub fn (db &DB) q_string(query string) string {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
defer {
|
||||
C.sqlite3_finalize(stmt)
|
||||
}
|
||||
@ -209,7 +209,7 @@ pub fn (db &DB) q_string(query string) string {
|
||||
// Result codes: https://www.sqlite.org/rescode.html
|
||||
[manualfree]
|
||||
pub fn (db &DB) exec(query string) ([]Row, int) {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
defer {
|
||||
C.sqlite3_finalize(stmt)
|
||||
}
|
||||
@ -276,7 +276,7 @@ pub fn (db &DB) error_message(code int, query string) IError {
|
||||
// In case you don't expect any row results, but still want a result code.
|
||||
// e.g. INSERT INTO ... VALUES (...)
|
||||
pub fn (db &DB) exec_none(query string) int {
|
||||
stmt := &C.sqlite3_stmt(0)
|
||||
stmt := &C.sqlite3_stmt(unsafe { nil })
|
||||
C.sqlite3_prepare_v2(db.conn, &char(query.str), query.len, &stmt, 0)
|
||||
code := C.sqlite3_step(stmt)
|
||||
C.sqlite3_finalize(stmt)
|
||||
|
@ -149,7 +149,7 @@ pub enum OpenModeFlag {
|
||||
// connect_full Opens connection to sqlite database. It gives more control than `open`.
|
||||
// Flags give control over readonly and create decisions. Specific VFS can be chosen.
|
||||
pub fn connect_full(path string, mode_flags []OpenModeFlag, vfs_name string) !DB {
|
||||
db := &C.sqlite3(0)
|
||||
db := &C.sqlite3(unsafe { nil })
|
||||
|
||||
mut flags := 0
|
||||
|
||||
|
@ -11,7 +11,7 @@ mut:
|
||||
read_all_bytes bool = true
|
||||
}
|
||||
|
||||
const ctx_ptr = &Context(0)
|
||||
const ctx_ptr = &Context(unsafe { nil })
|
||||
|
||||
// init initializes the terminal console with Config `cfg`.
|
||||
pub fn init(cfg Config) &Context {
|
||||
|
@ -8,7 +8,7 @@ import time
|
||||
|
||||
const buf_size = 64
|
||||
|
||||
const ctx_ptr = &Context(0)
|
||||
const ctx_ptr = &Context(unsafe { nil })
|
||||
|
||||
const stdin_at_startup = u32(0)
|
||||
|
||||
|
@ -255,7 +255,7 @@ fn (mut ctx Context) parse_events() {
|
||||
if nr_iters > 100 {
|
||||
ctx.shift(1)
|
||||
}
|
||||
mut event := &Event(0)
|
||||
mut event := &Event(unsafe { nil })
|
||||
if ctx.read_buf[0] == 0x1b {
|
||||
e, len := escape_sequence(ctx.read_buf.bytestr())
|
||||
event = e
|
||||
@ -420,7 +420,7 @@ fn escape_sequence(buf_ string) (&Event, int) {
|
||||
if buf.len > 2 && buf[1] == `<` {
|
||||
split := buf[2..].split(';')
|
||||
if split.len < 3 {
|
||||
return &Event(0), 0
|
||||
return &Event(unsafe { nil }), 0
|
||||
}
|
||||
|
||||
typ, x, y := split[0].int(), split[1].int(), split[2].int()
|
||||
|
@ -4,7 +4,7 @@ import toml.to
|
||||
import toml.ast
|
||||
|
||||
const empty_toml_document = toml.Doc{
|
||||
ast: &ast.Root(0)
|
||||
ast: &ast.Root(unsafe { nil })
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -102,7 +102,7 @@ pub fn new_table() &Table {
|
||||
return t
|
||||
}
|
||||
|
||||
__global global_table = &Table(0)
|
||||
__global global_table = &Table(unsafe { nil })
|
||||
|
||||
pub fn set_global_table(t &Table) {
|
||||
global_table = t
|
||||
|
@ -2836,6 +2836,30 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||
if from_sym.kind == .alias {
|
||||
from_type = (from_sym.info as ast.Alias).parent_type.derive_add_muls(from_type)
|
||||
}
|
||||
if mut node.expr is ast.IntegerLiteral {
|
||||
if node.expr.val.int() == 0 && !c.pref.translated && !c.file.is_translated {
|
||||
c.error('cannot null cast a struct pointer, use &${to_sym.name}(unsafe { nil })',
|
||||
node.pos)
|
||||
} else if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
|
||||
c.error('cannot cast int to a struct pointer outside `unsafe`', node.pos)
|
||||
}
|
||||
} else if mut node.expr is ast.Ident {
|
||||
match mut node.expr.obj {
|
||||
ast.GlobalField, ast.ConstField, ast.Var {
|
||||
if mut node.expr.obj.expr is ast.IntegerLiteral {
|
||||
if node.expr.obj.expr.val.int() == 0 && !c.pref.translated
|
||||
&& !c.file.is_translated {
|
||||
c.error('cannot null cast a struct pointer, use &${to_sym.name}(unsafe { nil })',
|
||||
node.pos)
|
||||
} else if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
|
||||
c.error('cannot cast int to a struct pointer outside `unsafe`',
|
||||
node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
if from_type == ast.voidptr_type_idx && !c.inside_unsafe {
|
||||
// TODO make this an error
|
||||
c.warn('cannot cast voidptr to a struct outside `unsafe`', node.pos)
|
||||
@ -3611,9 +3635,10 @@ fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {
|
||||
}
|
||||
|
||||
fn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) ast.Type {
|
||||
prev_unsafe := c.inside_unsafe
|
||||
c.inside_unsafe = true
|
||||
t := c.expr(node.expr)
|
||||
c.inside_unsafe = false
|
||||
c.inside_unsafe = prev_unsafe
|
||||
return t
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv:6:5: error: cannot cast int to a struct pointer outside `unsafe`
|
||||
4 | a := 1
|
||||
5 |
|
||||
6 | _ = &Context(a)
|
||||
| ~~~~~~~~~~~
|
||||
7 | _ = &Context(b)
|
||||
8 | _ = &Context(1)
|
||||
vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv:7:5: error: cannot cast int to a struct pointer outside `unsafe`
|
||||
5 |
|
||||
6 | _ = &Context(a)
|
||||
7 | _ = &Context(b)
|
||||
| ~~~~~~~~~~~
|
||||
8 | _ = &Context(1)
|
||||
vlib/v/checker/tests/struct_ptr_cast_int_outside_unsafe_err.vv:8:5: error: cannot cast int to a struct pointer outside `unsafe`
|
||||
6 | _ = &Context(a)
|
||||
7 | _ = &Context(b)
|
||||
8 | _ = &Context(1)
|
||||
| ~~~~~~~~~~~
|
@ -0,0 +1,8 @@
|
||||
struct Context {}
|
||||
|
||||
const b = 1
|
||||
a := 1
|
||||
|
||||
_ = &Context(a)
|
||||
_ = &Context(b)
|
||||
_ = &Context(1)
|
18
vlib/v/checker/tests/struct_ptr_cast_zero_err.out
Normal file
18
vlib/v/checker/tests/struct_ptr_cast_zero_err.out
Normal file
@ -0,0 +1,18 @@
|
||||
vlib/v/checker/tests/struct_ptr_cast_zero_err.vv:6:5: error: cannot null cast a struct pointer, use &Context(unsafe { nil })
|
||||
4 | b := 0
|
||||
5 |
|
||||
6 | _ = &Context(0)
|
||||
| ~~~~~~~~~~~
|
||||
7 | _ = &Context(a)
|
||||
8 | _ = &Context(b)
|
||||
vlib/v/checker/tests/struct_ptr_cast_zero_err.vv:7:5: error: cannot null cast a struct pointer, use &Context(unsafe { nil })
|
||||
5 |
|
||||
6 | _ = &Context(0)
|
||||
7 | _ = &Context(a)
|
||||
| ~~~~~~~~~~~
|
||||
8 | _ = &Context(b)
|
||||
vlib/v/checker/tests/struct_ptr_cast_zero_err.vv:8:5: error: cannot null cast a struct pointer, use &Context(unsafe { nil })
|
||||
6 | _ = &Context(0)
|
||||
7 | _ = &Context(a)
|
||||
8 | _ = &Context(b)
|
||||
| ~~~~~~~~~~~
|
8
vlib/v/checker/tests/struct_ptr_cast_zero_err.vv
Normal file
8
vlib/v/checker/tests/struct_ptr_cast_zero_err.vv
Normal file
@ -0,0 +1,8 @@
|
||||
struct Context {}
|
||||
|
||||
const a = 0
|
||||
b := 0
|
||||
|
||||
_ = &Context(0)
|
||||
_ = &Context(a)
|
||||
_ = &Context(b)
|
@ -428,7 +428,7 @@ pub fn (mut g JsGen) enter_namespace(name string) {
|
||||
}
|
||||
|
||||
pub fn (mut g JsGen) escape_namespace() {
|
||||
g.ns = &Namespace(0)
|
||||
g.ns = &Namespace(unsafe { nil })
|
||||
g.inside_builtin = false
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ pub fn (mut p Parser) free_scanner() {
|
||||
unsafe {
|
||||
if p.scanner != 0 {
|
||||
p.scanner.free()
|
||||
p.scanner = &scanner.Scanner(0)
|
||||
p.scanner = &scanner.Scanner(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ pub fn (mut m Main) run() !string {
|
||||
}
|
||||
// m.opt = options
|
||||
opt := m.opt
|
||||
mut pc := &PkgConfig(0)
|
||||
mut pc := &PkgConfig(unsafe { nil })
|
||||
mut res := m.res
|
||||
for arg in opt.args {
|
||||
mut pcdep := load(arg, options) or {
|
||||
|
@ -41,11 +41,11 @@ struct Foo {
|
||||
type Alias = Foo
|
||||
|
||||
fn test_cast_to_alias_of_ref_struct() {
|
||||
foo := &Foo(0)
|
||||
foo := &Foo(unsafe { nil })
|
||||
println(typeof(foo).name)
|
||||
assert typeof(foo).name == '&Foo'
|
||||
|
||||
bar := &Alias(0)
|
||||
bar := &Alias(unsafe { nil })
|
||||
println(typeof(bar).name)
|
||||
assert typeof(bar).name == '&Alias'
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ pub fn new_keywords_matcher_trie[T](kw_map map[string]T) KeywordsMatcherTrie {
|
||||
nodes: []&TrieNode{cap: 20}
|
||||
}
|
||||
for _ in 0 .. 20 {
|
||||
km.nodes << &TrieNode(0)
|
||||
km.nodes << &TrieNode(unsafe { nil })
|
||||
}
|
||||
for k, v in kw_map {
|
||||
km.add_word(k, int(v))
|
||||
|
@ -297,7 +297,7 @@ mut:
|
||||
|
||||
[unsafe]
|
||||
pub fn cached_read_source_file(path string) !string {
|
||||
mut static cache := &SourceCache(0)
|
||||
mut static cache := &SourceCache(unsafe { nil })
|
||||
if cache == unsafe { nil } {
|
||||
cache = &SourceCache{}
|
||||
}
|
||||
@ -308,7 +308,7 @@ pub fn cached_read_source_file(path string) !string {
|
||||
if path.len == 0 {
|
||||
unsafe { cache.sources.free() }
|
||||
unsafe { free(cache) }
|
||||
cache = &SourceCache(0)
|
||||
cache = &SourceCache(unsafe { nil })
|
||||
return error('memory source file cache cleared')
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ struct SimpleTcpClientConfig {
|
||||
}
|
||||
|
||||
fn simple_tcp_client(config SimpleTcpClientConfig) !string {
|
||||
mut client := &net.TcpConn(0)
|
||||
mut client := &net.TcpConn(unsafe { nil })
|
||||
mut tries := 0
|
||||
for tries < config.retries {
|
||||
tries++
|
||||
@ -308,7 +308,7 @@ ${config.content}'
|
||||
}
|
||||
|
||||
fn simple_tcp_client_post_json(config SimpleTcpClientConfig) !string {
|
||||
mut client := &net.TcpConn(0)
|
||||
mut client := &net.TcpConn(unsafe { nil })
|
||||
mut tries := 0
|
||||
for tries < config.retries {
|
||||
tries++
|
||||
|
@ -266,7 +266,7 @@ struct SimpleTcpClientConfig {
|
||||
}
|
||||
|
||||
fn simple_tcp_client(config SimpleTcpClientConfig) !string {
|
||||
mut client := &net.TcpConn(0)
|
||||
mut client := &net.TcpConn(unsafe { nil })
|
||||
mut tries := 0
|
||||
for tries < config.retries {
|
||||
tries++
|
||||
|
Loading…
Reference in New Issue
Block a user