1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

all: change optional to result of io (#16075)

This commit is contained in:
yuyi 2022-10-16 14:28:57 +08:00 committed by GitHub
parent 6e46933c55
commit f6844e9766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
187 changed files with 1885 additions and 1874 deletions

View File

@ -43,7 +43,7 @@ fn main() {
vexe := pref.vexe_path() vexe := pref.vexe_path()
vroot := os.dir(vexe) vroot := os.dir(vexe)
util.set_vroot_folder(vroot) util.set_vroot_folder(vroot)
os.chdir(vroot)? os.chdir(vroot)!
cmd := diff.find_working_diff_command() or { '' } cmd := diff.find_working_diff_command() or { '' }
mut app := App{ mut app := App{
diff_cmd: cmd diff_cmd: cmd

View File

@ -15,7 +15,7 @@ const vdir = @VEXEROOT
fn main() { fn main() {
dump(fast_dir) dump(fast_dir)
dump(vdir) dump(vdir)
os.chdir(fast_dir)? os.chdir(fast_dir)!
if !os.exists('$vdir/v') && !os.is_dir('$vdir/vlib') { if !os.exists('$vdir/v') && !os.is_dir('$vdir/vlib') {
println('fast.html generator needs to be located in `v/cmd/tools/fast`') println('fast.html generator needs to be located in `v/cmd/tools/fast`')
} }
@ -32,11 +32,11 @@ fn main() {
// fetch the last commit's hash // fetch the last commit's hash
commit := exec('git rev-parse HEAD')[..8] commit := exec('git rev-parse HEAD')[..8]
if !os.exists('table.html') { if !os.exists('table.html') {
os.create('table.html')? os.create('table.html')!
} }
mut table := os.read_file('table.html')? mut table := os.read_file('table.html')!
if os.exists('website/index.html') { if os.exists('website/index.html') {
uploaded_index := os.read_file('website/index.html')? uploaded_index := os.read_file('website/index.html')!
if uploaded_index.contains('>$commit<') { if uploaded_index.contains('>$commit<') {
println('nothing to benchmark') println('nothing to benchmark')
exit(1) exit(1)
@ -48,7 +48,7 @@ fn main() {
// build an optimized V // build an optimized V
println(' Building vprod...') println(' Building vprod...')
os.chdir(vdir)? os.chdir(vdir)!
if os.args.contains('-noprod') { if os.args.contains('-noprod') {
exec('./v -o vprod cmd/v') // for faster debugging exec('./v -o vprod cmd/v') // for faster debugging
} else { } else {
@ -82,8 +82,8 @@ fn main() {
commit_date := exec('git log -n1 --pretty="format:%at" $commit') commit_date := exec('git log -n1 --pretty="format:%at" $commit')
date := time.unix(commit_date.int()) date := time.unix(commit_date.int())
os.chdir(fast_dir)? os.chdir(fast_dir)!
mut out := os.create('table.html')? mut out := os.create('table.html')!
// place the new row on top // place the new row on top
html_message := message.replace_each(['<', '&lt;', '>', '&gt;']) html_message := message.replace_each(['<', '&lt;', '>', '&gt;'])
@ -105,25 +105,25 @@ fn main() {
<td>${int(f64(vlines) / f64(diff1) * 1000.0)}</td> <td>${int(f64(vlines) / f64(diff1) * 1000.0)}</td>
</tr>\n' + </tr>\n' +
table.trim_space() table.trim_space()
out.writeln(table)? out.writeln(table)!
out.close() out.close()
// regenerate index.html // regenerate index.html
header := os.read_file('header.html')? header := os.read_file('header.html')!
footer := os.read_file('footer.html')? footer := os.read_file('footer.html')!
mut res := os.create('index.html')? mut res := os.create('index.html')!
res.writeln(header)? res.writeln(header)!
res.writeln(table)? res.writeln(table)!
res.writeln(footer)? res.writeln(footer)!
res.close() res.close()
// upload the result to github pages // upload the result to github pages
if os.args.contains('-upload') { if os.args.contains('-upload') {
println('uploading...') println('uploading...')
os.chdir('website')? os.chdir('website')!
os.execute_or_exit('git checkout gh-pages') os.execute_or_exit('git checkout gh-pages')
os.cp('../index.html', 'index.html')? os.cp('../index.html', 'index.html')!
os.rm('../index.html')? os.rm('../index.html')!
os.system('git commit -am "update benchmark"') os.system('git commit -am "update benchmark"')
os.system('git push origin gh-pages') os.system('git push origin gh-pages')
} }

View File

@ -7,14 +7,14 @@ fn main() {
files := os.args#[1..] files := os.args#[1..]
if files.len > 0 && files[0].starts_with('@') { if files.len > 0 && files[0].starts_with('@') {
lst_path := files[0].all_after('@') lst_path := files[0].all_after('@')
listed_files := os.read_file(lst_path)?.split('\n') listed_files := os.read_file(lst_path)!.split('\n')
process_files(listed_files)? process_files(listed_files)!
return return
} }
process_files(files)? process_files(files)!
} }
fn process_files(files []string) ? { fn process_files(files []string) ! {
mut pref := pref.new_preferences() mut pref := pref.new_preferences()
pref.is_fmt = true pref.is_fmt = true
pref.skip_warnings = true pref.skip_warnings = true
@ -31,7 +31,7 @@ fn process_files(files []string) ? {
continue continue
} }
sw.restart() sw.restart()
s := scanner.new_scanner_file(f, .skip_comments, pref)? s := scanner.new_scanner_file(f, .skip_comments, pref)!
f_us := sw.elapsed().microseconds() f_us := sw.elapsed().microseconds()
total_us += f_us total_us += f_us
total_bytes += s.text.len total_bytes += s.text.len

View File

@ -125,7 +125,7 @@ fn main() {
should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache') should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache')
context.is_bisect = fp.bool('bisect', `b`, false, 'Bisect mode. Use the current commit in the repo where oldv is.') context.is_bisect = fp.bool('bisect', `b`, false, 'Bisect mode. Use the current commit in the repo where oldv is.')
if !should_sync && !context.is_bisect { if !should_sync && !context.is_bisect {
fp.limit_free_args(1, 1)? fp.limit_free_args(1, 1)!
} }
//// ////
context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).') context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).')

View File

@ -194,7 +194,7 @@ fn main() {
fp.description(tool_description) fp.description(tool_description)
fp.arguments_description('COMMIT_BEFORE [COMMIT_AFTER]') fp.arguments_description('COMMIT_BEFORE [COMMIT_AFTER]')
fp.skip_executable() fp.skip_executable()
fp.limit_free_args(1, 2)? fp.limit_free_args(1, 2)!
context.vflags = fp.string('vflags', 0, '', 'Additional options to pass to the v commands, for example "-cc tcc"') context.vflags = fp.string('vflags', 0, '', 'Additional options to pass to the v commands, for example "-cc tcc"')
context.hyperfineopts = fp.string('hyperfine_options', 0, '', 'Additional options passed to hyperfine. context.hyperfineopts = fp.string('hyperfine_options', 0, '', 'Additional options passed to hyperfine.
${flag.space}For example on linux, you may want to pass: ${flag.space}For example on linux, you may want to pass:

View File

@ -143,19 +143,19 @@ const (
fn main() { fn main() {
mut context := Context{} mut context := Context{}
context.parse_options()? context.parse_options()!
context.run() context.run()
context.show_diff_summary() context.show_diff_summary()
} }
fn (mut context Context) parse_options() ? { fn (mut context Context) parse_options() ! {
mut fp := flag.new_flag_parser(os.args) mut fp := flag.new_flag_parser(os.args)
fp.application(os.file_name(os.executable())) fp.application(os.file_name(os.executable()))
fp.version('0.0.1') fp.version('0.0.1')
fp.description('Repeat command(s) and collect statistics. Note: you have to quote each command, if it contains spaces.') fp.description('Repeat command(s) and collect statistics. Note: you have to quote each command, if it contains spaces.')
fp.arguments_description('CMD1 CMD2 ...') fp.arguments_description('CMD1 CMD2 ...')
fp.skip_executable() fp.skip_executable()
fp.limit_free_args_to_at_least(1)? fp.limit_free_args_to_at_least(1)!
context.count = fp.int('count', `c`, 10, 'Repetition count.') context.count = fp.int('count', `c`, 10, 'Repetition count.')
context.series = fp.int('series', `s`, 2, 'Series count. `-s 2 -c 4 a b` => aaaabbbbaaaabbbb, while `-s 3 -c 2 a b` => aabbaabbaabb.') context.series = fp.int('series', `s`, 2, 'Series count. `-s 2 -c 4 a b` => aaaabbbbaaaabbbb, while `-s 3 -c 2 a b` => aabbaabbaabb.')
context.warmup = fp.int('warmup', `w`, 2, 'Warmup runs. These are done *only at the start*, and are ignored.') context.warmup = fp.int('warmup', `w`, 2, 'Warmup runs. These are done *only at the start*, and are ignored.')

View File

@ -60,16 +60,16 @@ fn (result MyResult) matches(gpattern string) MyResult {
return result return result
} }
fn create_test(tname string, tcontent string) ?string { fn create_test(tname string, tcontent string) !string {
tpath := os.join_path(tdir, tname) tpath := os.join_path(tdir, tname)
os.write_file(tpath, tcontent)? os.write_file(tpath, tcontent)!
eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent') eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent')
return os.quoted_path(tpath) return os.quoted_path(tpath)
} }
fn check_assert_continues_works() ? { fn check_assert_continues_works() ! {
os.chdir(tdir)? os.chdir(tdir)!
create_test('assert_continues_option_works_test.v', 'fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false }')? create_test('assert_continues_option_works_test.v', 'fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false }')!
result := check_fail('$vexe -assert continues assert_continues_option_works_test.v') result := check_fail('$vexe -assert continues assert_continues_option_works_test.v')
result.has('assert_continues_option_works_test.v:1: fn test_fail1') result.has('assert_continues_option_works_test.v:1: fn test_fail1')
result.has('assert_continues_option_works_test.v:2: fn test_fail1') result.has('assert_continues_option_works_test.v:2: fn test_fail1')
@ -77,7 +77,7 @@ fn check_assert_continues_works() ? {
result.has('assert_continues_option_works_test.v:5: fn test_fail2') result.has('assert_continues_option_works_test.v:5: fn test_fail2')
result.has('> assert 2 == 4').has('> assert 2 == 1').has('> assert 2 == 0') result.has('> assert 2 == 4').has('> assert 2 == 1').has('> assert 2 == 0')
// Check if a test function, tagged with [assert_continues], has the same behaviour, without needing additional options // Check if a test function, tagged with [assert_continues], has the same behaviour, without needing additional options
create_test('assert_continues_tag_works_test.v', '[assert_continues]fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false\n assert false }')? create_test('assert_continues_tag_works_test.v', '[assert_continues]fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false\n assert false }')!
tag_res := check_fail('$vexe assert_continues_tag_works_test.v') tag_res := check_fail('$vexe assert_continues_tag_works_test.v')
tag_res.has('assert_continues_tag_works_test.v:1: fn test_fail1') tag_res.has('assert_continues_tag_works_test.v:1: fn test_fail1')
tag_res.has('assert_continues_tag_works_test.v:2: fn test_fail1') tag_res.has('assert_continues_tag_works_test.v:2: fn test_fail1')
@ -113,23 +113,23 @@ fn main() {
os.chdir(os.wd_at_startup) or {} os.chdir(os.wd_at_startup) or {}
} }
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir') println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }')? ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }')!
if check_ok('$vexe $ok_fpath') != '' { if check_ok('$vexe $ok_fpath') != '' {
exit(1) exit(1)
} }
check_ok('$vexe test $ok_fpath').matches('*OK*a_single_ok_test.v*') check_ok('$vexe test $ok_fpath').matches('*OK*a_single_ok_test.v*')
check_ok('$vexe test "$tdir"').matches('*OK*a_single_ok_test.v*') check_ok('$vexe test "$tdir"').matches('*OK*a_single_ok_test.v*')
// //
fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }')? fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }')!
check_fail('$vexe $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail') check_fail('$vexe $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail')
check_fail('$vexe test $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail') check_fail('$vexe test $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail')
check_fail('$vexe test "$tdir"').has('> assert 1 == 2') check_fail('$vexe test "$tdir"').has('> assert 1 == 2')
rel_dir := os.join_path(tdir, rand.ulid()) rel_dir := os.join_path(tdir, rand.ulid())
os.mkdir(rel_dir)? os.mkdir(rel_dir)!
os.chdir(rel_dir)? os.chdir(rel_dir)!
relative_path := '..' + os.path_separator + 'a_single_ok_test.v' relative_path := '..' + os.path_separator + 'a_single_ok_test.v'
check_ok('$vexe test ${os.quoted_path(relative_path)}').has('OK').has('a_single_ok_test.v') check_ok('$vexe test ${os.quoted_path(relative_path)}').has('OK').has('a_single_ok_test.v')
// //
check_assert_continues_works()? check_assert_continues_works()!
println('> all done') println('> all done')
} }

View File

@ -16,9 +16,9 @@ fn main() {
} }
// Git clone c2v // Git clone c2v
if !os.exists(c2v_dir) { if !os.exists(c2v_dir) {
os.mkdir_all(vmodules)? os.mkdir_all(vmodules)!
println('C2V is not installed. Cloning C2V to $c2v_dir ...') println('C2V is not installed. Cloning C2V to $c2v_dir ...')
os.chdir(vmodules)? os.chdir(vmodules)!
res := os.execute('git clone https://github.com/vlang/c2v') res := os.execute('git clone https://github.com/vlang/c2v')
if res.exit_code != 0 { if res.exit_code != 0 {
eprintln('Failed to download C2V.') eprintln('Failed to download C2V.')
@ -27,7 +27,7 @@ fn main() {
} }
// Compile c2v // Compile c2v
if !os.exists(c2v_bin) { if !os.exists(c2v_bin) {
os.chdir(c2v_dir)? os.chdir(c2v_dir)!
println('Compiling c2v ...') println('Compiling c2v ...')
res2 := os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(c2v_bin)} -keepc -g -experimental .') res2 := os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(c2v_bin)} -keepc -g -experimental .')
if res2.exit_code != 0 { if res2.exit_code != 0 {
@ -42,7 +42,7 @@ fn main() {
} }
passed_args := util.args_quote_paths(os.args[2..]) passed_args := util.args_quote_paths(os.args[2..])
// println(passed_args) // println(passed_args)
os.chdir(os.wd_at_startup)? os.chdir(os.wd_at_startup)!
c2v_cmd := '${os.quoted_path(c2v_bin)} $passed_args' c2v_cmd := '${os.quoted_path(c2v_bin)} $passed_args'
res := os.system(c2v_cmd) res := os.system(c2v_cmd)
if res != 0 { if res != 0 {

View File

@ -44,7 +44,7 @@ fn main() {
for hf in hfields.split(',') { for hf in hfields.split(',') {
ctx.hide_names[hf] = true ctx.hide_names[hf] = true
} }
fp.limit_free_args_to_at_least(1)? fp.limit_free_args_to_at_least(1)!
rest_of_args := fp.remaining_parameters() rest_of_args := fp.remaining_parameters()
for vfile in rest_of_args { for vfile in rest_of_args {
file := get_abs_path(vfile) file := get_abs_path(vfile)

View File

@ -73,7 +73,7 @@ fn (context Context) file2v(bname string, fbytes []u8, bn_max int) string {
return sb.str() return sb.str()
} }
fn (context Context) bname_and_bytes(file string) ?(string, []u8) { fn (context Context) bname_and_bytes(file string) !(string, []u8) {
fname := os.file_name(file) fname := os.file_name(file)
fname_escaped := fname.replace_each(['.', '_', '-', '_']) fname_escaped := fname.replace_each(['.', '_', '-', '_'])
byte_name := '$context.prefix$fname_escaped'.to_lower() byte_name := '$context.prefix$fname_escaped'.to_lower()
@ -130,12 +130,12 @@ fn main() {
} }
max_bname := context.max_bname_len(file_byte_map.keys()) max_bname := context.max_bname_len(file_byte_map.keys())
if context.write_file.len > 0 { if context.write_file.len > 0 {
mut out_file := os.create(context.write_file)? mut out_file := os.create(context.write_file)!
out_file.write_string(context.header())? out_file.write_string(context.header())!
for bname, fbytes in file_byte_map { for bname, fbytes in file_byte_map {
out_file.write_string(context.file2v(bname, fbytes, max_bname))? out_file.write_string(context.file2v(bname, fbytes, max_bname))!
} }
out_file.write_string(context.footer())? out_file.write_string(context.footer())!
} else { } else {
print(context.header()) print(context.header())
for bname, fbytes in file_byte_map { for bname, fbytes in file_byte_map {

View File

@ -23,7 +23,7 @@ fn main() {
args_string := os.args[1..].join(' ') args_string := os.args[1..].join(' ')
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := os.dir(vexe) vroot := os.dir(vexe)
os.chdir(vroot)? os.chdir(vroot)!
folder := os.join_path('cmd', 'tools') folder := os.join_path('cmd', 'tools')
tfolder := os.join_path(vroot, 'cmd', 'tools') tfolder := os.join_path(vroot, 'cmd', 'tools')
main_label := 'Building $folder ...' main_label := 'Building $folder ...'
@ -47,7 +47,7 @@ fn main() {
exit(1) exit(1)
} }
// //
mut executables := os.ls(session.vtmp_dir)? mut executables := os.ls(session.vtmp_dir)!
executables.sort() executables.sort()
for texe in executables { for texe in executables {
tname := texe.replace(os.file_ext(texe), '') tname := texe.replace(os.file_ext(texe), '')

View File

@ -73,25 +73,25 @@ fn main() {
}, },
] ]
fn run_individual_test(case BumpTestCase) ? { fn run_individual_test(case BumpTestCase) ! {
test_file := os.join_path_single(tfolder, case.file_name) test_file := os.join_path_single(tfolder, case.file_name)
os.rm(test_file) or {} os.rm(test_file) or {}
os.write_file(test_file, case.contents)? os.write_file(test_file, case.contents)!
// //
os.execute_or_exit('${os.quoted_path(vexe)} bump --patch ${os.quoted_path(test_file)}') os.execute_or_exit('${os.quoted_path(vexe)} bump --patch ${os.quoted_path(test_file)}')
patch_lines := os.read_lines(test_file)? patch_lines := os.read_lines(test_file)!
assert patch_lines[case.line] == case.expected_patch assert patch_lines[case.line] == case.expected_patch
os.execute_or_exit('${os.quoted_path(vexe)} bump --minor ${os.quoted_path(test_file)}') os.execute_or_exit('${os.quoted_path(vexe)} bump --minor ${os.quoted_path(test_file)}')
minor_lines := os.read_lines(test_file)? minor_lines := os.read_lines(test_file)!
assert minor_lines[case.line] == case.expected_minor assert minor_lines[case.line] == case.expected_minor
os.execute_or_exit('${os.quoted_path(vexe)} bump --major ${os.quoted_path(test_file)}') os.execute_or_exit('${os.quoted_path(vexe)} bump --major ${os.quoted_path(test_file)}')
major_lines := os.read_lines(test_file)? major_lines := os.read_lines(test_file)!
assert major_lines[case.line] == case.expected_major assert major_lines[case.line] == case.expected_major
// //
os.rm(test_file)? os.rm(test_file)!
} }
fn test_all_bump_cases() { fn test_all_bump_cases() {

View File

@ -2,10 +2,10 @@ import os
const test_path = os.join_path(os.temp_dir(), 'v', 'vcreate_test') const test_path = os.join_path(os.temp_dir(), 'v', 'vcreate_test')
fn init_and_check() ? { fn init_and_check() ! {
os.execute_or_exit('${os.quoted_path(@VEXE)} init') os.execute_or_exit('${os.quoted_path(@VEXE)} init')
assert os.read_file('vcreate_test.v')? == [ assert os.read_file('vcreate_test.v')! == [
'module main\n', 'module main\n',
'fn main() {', 'fn main() {',
" println('Hello World!')", " println('Hello World!')",
@ -13,7 +13,7 @@ fn init_and_check() ? {
'', '',
].join_lines() ].join_lines()
assert os.read_file('v.mod')? == [ assert os.read_file('v.mod')! == [
'Module {', 'Module {',
" name: 'vcreate_test'", " name: 'vcreate_test'",
" description: ''", " description: ''",
@ -24,7 +24,7 @@ fn init_and_check() ? {
'', '',
].join_lines() ].join_lines()
assert os.read_file('.gitignore')? == [ assert os.read_file('.gitignore')! == [
'# Binaries for programs and plugins', '# Binaries for programs and plugins',
'main', 'main',
'vcreate_test', 'vcreate_test',
@ -37,7 +37,7 @@ fn init_and_check() ? {
'', '',
].join_lines() ].join_lines()
assert os.read_file('.gitattributes')? == [ assert os.read_file('.gitattributes')! == [
'*.v linguist-language=V text=auto eol=lf', '*.v linguist-language=V text=auto eol=lf',
'*.vv linguist-language=V text=auto eol=lf', '*.vv linguist-language=V text=auto eol=lf',
'*.vsh linguist-language=V text=auto eol=lf', '*.vsh linguist-language=V text=auto eol=lf',
@ -45,7 +45,7 @@ fn init_and_check() ? {
'', '',
].join_lines() ].join_lines()
assert os.read_file('.editorconfig')? == [ assert os.read_file('.editorconfig')! == [
'[*]', '[*]',
'charset = utf-8', 'charset = utf-8',
'end_of_line = lf', 'end_of_line = lf',
@ -59,28 +59,28 @@ fn init_and_check() ? {
].join_lines() ].join_lines()
} }
fn prepare_test_path() ? { fn prepare_test_path() ! {
os.rmdir_all(test_path) or {} os.rmdir_all(test_path) or {}
os.mkdir_all(test_path) or {} os.mkdir_all(test_path) or {}
os.chdir(test_path)? os.chdir(test_path)!
} }
fn test_v_init() { fn test_v_init() {
prepare_test_path()? prepare_test_path()!
init_and_check()? init_and_check()!
} }
fn test_v_init_in_git_dir() { fn test_v_init_in_git_dir() {
prepare_test_path()? prepare_test_path()!
os.execute_or_exit('git init .') os.execute_or_exit('git init .')
init_and_check()? init_and_check()!
} }
fn test_v_init_no_overwrite_gitignore() { fn test_v_init_no_overwrite_gitignore() {
prepare_test_path()? prepare_test_path()!
os.write_file('.gitignore', 'blah')? os.write_file('.gitignore', 'blah')!
os.execute_or_exit('${os.quoted_path(@VEXE)} init') os.execute_or_exit('${os.quoted_path(@VEXE)} init')
assert os.read_file('.gitignore')? == 'blah' assert os.read_file('.gitignore')! == 'blah'
} }
fn test_v_init_no_overwrite_gitattributes_and_editorconfig() { fn test_v_init_no_overwrite_gitattributes_and_editorconfig() {
@ -95,13 +95,13 @@ trim_trailing_whitespace = true
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4
' '
prepare_test_path()? prepare_test_path()!
os.write_file('.gitattributes', git_attributes_content)? os.write_file('.gitattributes', git_attributes_content)!
os.write_file('.editorconfig', editor_config_content)? os.write_file('.editorconfig', editor_config_content)!
os.execute_or_exit('${os.quoted_path(@VEXE)} init') os.execute_or_exit('${os.quoted_path(@VEXE)} init')
assert os.read_file('.gitattributes')? == git_attributes_content assert os.read_file('.gitattributes')! == git_attributes_content
assert os.read_file('.editorconfig')? == editor_config_content assert os.read_file('.editorconfig')! == editor_config_content
} }
fn testsuite_end() { fn testsuite_end() {

View File

@ -166,7 +166,7 @@ fn main() {
} }
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration') toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
arg_paths := fp.finalize()? arg_paths := fp.finalize()!
if show_help { if show_help {
println(fp.usage()) println(fp.usage())
exit(0) exit(0)
@ -179,7 +179,7 @@ fn main() {
} }
if !os.exists(tmp_dir) { if !os.exists(tmp_dir) {
os.mkdir_all(tmp_dir)? os.mkdir_all(tmp_dir)!
} }
opt.config = new_config(opt.root_path, toml_conf) or { panic(err) } opt.config = new_config(opt.root_path, toml_conf) or { panic(err) }
@ -202,7 +202,7 @@ fn main() {
eprintln('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`') eprintln('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
exit(1) exit(1)
} }
compare_screenshots(opt, gen_in_path, target_path)? compare_screenshots(opt, gen_in_path, target_path)!
} }
} }
@ -254,7 +254,7 @@ fn generate_screenshots(mut opt Options, output_path string) ! {
} }
} }
fn compare_screenshots(opt Options, output_path string, target_path string) ? { fn compare_screenshots(opt Options, output_path string, target_path string) ! {
mut fails := map[string]string{} mut fails := map[string]string{}
mut warns := map[string]string{} mut warns := map[string]string{}
for app_config in opt.config.apps { for app_config in opt.config.apps {
@ -306,14 +306,14 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
} }
first := fails.keys()[0] first := fails.keys()[0]
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.')) fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
os.cp(first, fail_copy)? os.cp(first, fail_copy)!
eprintln('First failed file `$first` is copied to `$fail_copy`') eprintln('First failed file `$first` is copied to `$fail_copy`')
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') + diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
'.diff.tif') '.diff.tif')
diff_copy := os.join_path(os.temp_dir(), 'diff.tif') diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
if os.is_file(diff_file) { if os.is_file(diff_file) {
os.cp(diff_file, diff_copy)? os.cp(diff_file, diff_copy)!
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`') eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
eprintln('Removing alpha channel from $diff_copy ...') eprintln('Removing alpha channel from $diff_copy ...')
final_fail_result_file := os.join_path(os.temp_dir(), 'diff.png') final_fail_result_file := os.join_path(os.temp_dir(), 'diff.png')

View File

@ -67,16 +67,16 @@ const json_enc = json2.Encoder{
escape_unicode: false escape_unicode: false
} }
fn (upd VlsUpdater) check_or_create_vls_folder() ? { fn (upd VlsUpdater) check_or_create_vls_folder() ! {
if !os.exists(vls_folder) { if !os.exists(vls_folder) {
upd.log('Creating .vls folder...') upd.log('Creating .vls folder...')
os.mkdir(vls_folder)? os.mkdir(vls_folder)!
} }
} }
fn (upd VlsUpdater) manifest_config() ?map[string]json2.Any { fn (upd VlsUpdater) manifest_config() !map[string]json2.Any {
manifest_buf := os.read_file(vls_manifest_path) or { '{}' } manifest_buf := os.read_file(vls_manifest_path) or { '{}' }
manifest_contents := json2.raw_decode(manifest_buf)?.as_map() manifest_contents := json2.raw_decode(manifest_buf)!.as_map()
return manifest_contents return manifest_contents
} }
@ -88,9 +88,9 @@ fn (upd VlsUpdater) exec_asset_file_name() string {
return 'vls_${os_name}_${arch + ext}' return 'vls_${os_name}_${arch + ext}'
} }
fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp time.Time) ? { fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp time.Time) ! {
upd.log('Updating permissions...') upd.log('Updating permissions...')
os.chmod(new_path, 755)? os.chmod(new_path, 755)!
upd.log('Updating vls.config.json...') upd.log('Updating vls.config.json...')
mut manifest := upd.manifest_config() or { mut manifest := upd.manifest_config() or {
@ -103,7 +103,7 @@ fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp
} }
} }
mut manifest_file := os.open_file(vls_manifest_path, 'w+')? mut manifest_file := os.open_file(vls_manifest_path, 'w+')!
defer { defer {
manifest_file.close() manifest_file.close()
} }
@ -112,31 +112,31 @@ fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp
manifest['last_updated'] = json2.Any(timestamp.format_ss()) manifest['last_updated'] = json2.Any(timestamp.format_ss())
manifest['from_source'] = json2.Any(from_source) manifest['from_source'] = json2.Any(from_source)
json_enc.encode_value(manifest, mut manifest_file)? json_enc.encode_value(manifest, mut manifest_file)!
} }
fn (upd VlsUpdater) init_download_prebuilt() ? { fn (upd VlsUpdater) init_download_prebuilt() ! {
if !os.exists(vls_cache_folder) { if !os.exists(vls_cache_folder) {
os.mkdir(vls_cache_folder)? os.mkdir(vls_cache_folder)!
} }
if os.exists(vls_bin_folder) { if os.exists(vls_bin_folder) {
os.rmdir_all(vls_bin_folder)? os.rmdir_all(vls_bin_folder)!
} }
os.mkdir(vls_bin_folder)? os.mkdir(vls_bin_folder)!
} }
fn (upd VlsUpdater) get_last_updated_at() ?time.Time { fn (upd VlsUpdater) get_last_updated_at() !time.Time {
if manifest := upd.manifest_config() { if manifest := upd.manifest_config() {
if 'last_updated' in manifest { if 'last_updated' in manifest {
return time.parse(manifest['last_updated'] or { '' }.str()) or { return none } return time.parse(manifest['last_updated'] or { '' }.str()) or { return error('none') }
} }
} }
return none return error('none')
} }
fn (upd VlsUpdater) download_prebuilt() ? { fn (upd VlsUpdater) download_prebuilt() ! {
mut has_last_updated_at := true mut has_last_updated_at := true
last_updated_at := upd.get_last_updated_at() or { last_updated_at := upd.get_last_updated_at() or {
has_last_updated_at = false has_last_updated_at = false
@ -147,14 +147,15 @@ fn (upd VlsUpdater) download_prebuilt() ? {
} }
upd.log('Finding prebuilt executables from GitHub release..') upd.log('Finding prebuilt executables from GitHub release..')
resp := http.get('https://api.github.com/repos/vlang/vls/releases')? resp := http.get('https://api.github.com/repos/vlang/vls/releases')!
releases_json := json2.raw_decode(resp.body)?.arr() releases_json := json2.raw_decode(resp.body)!.arr()
if releases_json.len == 0 { if releases_json.len == 0 {
return error('Unable to fetch latest VLS release data: No releases found.') return error('Unable to fetch latest VLS release data: No releases found.')
} }
latest_release := releases_json[0].as_map() latest_release := releases_json[0].as_map()
assets := latest_release['assets']?.arr() latest_assets := latest_release['assets'] or { return }
assets := latest_assets.arr()
mut checksum_asset_idx := -1 mut checksum_asset_idx := -1
mut exec_asset_idx := -1 mut exec_asset_idx := -1
@ -164,7 +165,8 @@ fn (upd VlsUpdater) download_prebuilt() ? {
for asset_idx, raw_asset in assets { for asset_idx, raw_asset in assets {
asset := raw_asset.as_map() asset := raw_asset.as_map()
match asset['name']?.str() { t_asset := asset['name'] or { return }
match t_asset.str() {
exp_asset_name { exp_asset_name {
exec_asset_idx = asset_idx exec_asset_idx = asset_idx
@ -196,13 +198,15 @@ fn (upd VlsUpdater) download_prebuilt() ? {
} }
upd.log('Executable found for this system. Downloading...') upd.log('Executable found for this system. Downloading...')
upd.init_download_prebuilt()? upd.init_download_prebuilt()!
http.download_file(exec_asset['browser_download_url']?.str(), exec_asset_file_path)? t_asset := exec_asset['browser_download_url'] or { return }
http.download_file(t_asset.str(), exec_asset_file_path)!
checksum_file_path := os.join_path(vls_cache_folder, 'checksums.txt') checksum_file_path := os.join_path(vls_cache_folder, 'checksums.txt')
checksum_file_asset := assets[checksum_asset_idx].as_map() checksum_file_asset := assets[checksum_asset_idx].as_map()
http.download_file(checksum_file_asset['browser_download_url']?.str(), checksum_file_path)? t_checksum_asset := checksum_file_asset['browser_download_url'] or { return }
checksums := os.read_file(checksum_file_path)?.split_into_lines() http.download_file(t_checksum_asset.str(), checksum_file_path)!
checksums := os.read_file(checksum_file_path)!.split_into_lines()
upd.log('Verifying checksum...') upd.log('Verifying checksum...')
for checksum_result in checksums { for checksum_result in checksums {
@ -217,7 +221,7 @@ fn (upd VlsUpdater) download_prebuilt() ? {
} }
new_exec_path := os.join_path(vls_bin_folder, exp_asset_name) new_exec_path := os.join_path(vls_bin_folder, exp_asset_name)
os.cp(exec_asset_file_path, new_exec_path)? os.cp(exec_asset_file_path, new_exec_path)!
upd.update_manifest(new_exec_path, false, asset_last_updated_at) or { upd.update_manifest(new_exec_path, false, asset_last_updated_at) or {
upd.log('Unable to update config but the executable was updated successfully.') upd.log('Unable to update config but the executable was updated successfully.')
} }
@ -231,12 +235,12 @@ fn (upd VlsUpdater) print_new_vls_version(new_vls_exec_path string) {
} }
} }
fn calculate_checksum(file_path string) ?string { fn calculate_checksum(file_path string) !string {
data := os.read_file(file_path)? data := os.read_file(file_path)!
return sha256.hexhash(data) return sha256.hexhash(data)
} }
fn (upd VlsUpdater) compile_from_source() ? { fn (upd VlsUpdater) compile_from_source() ! {
git := os.find_abs_path_of_executable('git') or { return error('Git not found.') } git := os.find_abs_path_of_executable('git') or { return error('Git not found.') }
if !os.exists(vls_src_folder) { if !os.exists(vls_src_folder) {
@ -280,22 +284,22 @@ fn (upd VlsUpdater) compile_from_source() ? {
upd.print_new_vls_version(exec_path) upd.print_new_vls_version(exec_path)
} }
fn (upd VlsUpdater) find_ls_path() ?string { fn (upd VlsUpdater) find_ls_path() !string {
manifest := upd.manifest_config()? manifest := upd.manifest_config()!
if 'server_path' in manifest { if 'server_path' in manifest {
server_path := manifest['server_path']? server_path := manifest['server_path'] or { return error('none') }
if server_path is string { if server_path is string {
if server_path.len == 0 { if server_path.len == 0 {
return none return error('none')
} }
return server_path return server_path
} }
} }
return none return error('none')
} }
fn (mut upd VlsUpdater) parse(mut fp flag.FlagParser) ? { fn (mut upd VlsUpdater) parse(mut fp flag.FlagParser) ! {
is_json := fp.bool('json', ` `, false, 'Print the output as JSON.') is_json := fp.bool('json', ` `, false, 'Print the output as JSON.')
if is_json { if is_json {
upd.output = .json upd.output = .json
@ -364,7 +368,7 @@ fn (mut upd VlsUpdater) parse(mut fp flag.FlagParser) ? {
fp.allow_unknown_args() fp.allow_unknown_args()
upd.args << fp.finalize() or { fp.remaining_parameters() } upd.args << fp.finalize() or { fp.remaining_parameters() }
} else { } else {
fp.finalize()? fp.finalize()!
} }
} }
@ -436,23 +440,23 @@ fn (upd VlsUpdater) check_installation() {
} }
} }
fn (upd VlsUpdater) run(fp flag.FlagParser) ? { fn (upd VlsUpdater) run(fp flag.FlagParser) ! {
if upd.is_check { if upd.is_check {
upd.check_installation() upd.check_installation()
} else if upd.setup_kind != .none_ { } else if upd.setup_kind != .none_ {
upd.check_or_create_vls_folder()? upd.check_or_create_vls_folder()!
match upd.update_source { match upd.update_source {
.github_releases { .github_releases {
upd.download_prebuilt() or { upd.download_prebuilt() or {
if err.code() == 100 { if err.code() == 100 {
upd.compile_from_source()? upd.compile_from_source()!
} }
return err return err
} }
} }
.git_repo { .git_repo {
upd.compile_from_source()? upd.compile_from_source()!
} }
} }
} else if upd.pass_to_ls { } else if upd.pass_to_ls {

View File

@ -133,7 +133,7 @@ fn (r &Repl) function_call(line string) (bool, FnType) {
// TODO(vincenzopalazzo) Remove this fancy check and add a regex // TODO(vincenzopalazzo) Remove this fancy check and add a regex
fn (r &Repl) is_function_call(line string) bool { fn (r &Repl) is_function_call(line string) bool {
return !line.starts_with('[') && line.contains('.') && line.contains('(') return !line.starts_with('[') && line.contains('.') && line.contains('(')
&& (line.ends_with(')') || line.ends_with('?')) && (line.ends_with(')') || line.ends_with('?') || line.ends_with('!'))
} }
// Convert the list of modules that we parsed already, // Convert the list of modules that we parsed already,

View File

@ -12,11 +12,11 @@ fn main() {
fp.version('0.0.1') fp.version('0.0.1')
fp.description('\nScan .v source files, and print the V tokens contained in them.') fp.description('\nScan .v source files, and print the V tokens contained in them.')
fp.arguments_description('PATH [PATH]...') fp.arguments_description('PATH [PATH]...')
fp.limit_free_args_to_at_least(1)? fp.limit_free_args_to_at_least(1)!
pref := pref.new_preferences() pref := pref.new_preferences()
mut all_paths := fp.remaining_parameters() mut all_paths := fp.remaining_parameters()
for path in all_paths { for path in all_paths {
mut scanner := scanner.new_scanner_file(path, .parse_comments, pref)? mut scanner := scanner.new_scanner_file(path, .parse_comments, pref)!
mut tok := token.Token{} mut tok := token.Token{}
for tok.kind != .eof { for tok.kind != .eof {
tok = scanner.scan() tok = scanner.scan()

View File

@ -15,7 +15,7 @@ fn main() {
short_v_name := vexe_name.all_before('.') short_v_name := vexe_name.all_before('.')
// //
recompilation.must_be_enabled(vroot, 'Please install V from source, to use `$vexe_name self` .') recompilation.must_be_enabled(vroot, 'Please install V from source, to use `$vexe_name self` .')
os.chdir(vroot)? os.chdir(vroot)!
os.setenv('VCOLORS', 'always', true) os.setenv('VCOLORS', 'always', true)
args := os.args[1..].filter(it != 'self') args := os.args[1..].filter(it != 'self')
jargs := args.join(' ') jargs := args.join(' ')
@ -60,7 +60,7 @@ fn list_folder(short_v_name string, bmessage string, message string) {
println(message) println(message)
} }
fn backup_old_version_and_rename_newer(short_v_name string) ?bool { fn backup_old_version_and_rename_newer(short_v_name string) !bool {
mut errors := []string{} mut errors := []string{}
short_v_file := if os.user_os() == 'windows' { '${short_v_name}.exe' } else { '$short_v_name' } short_v_file := if os.user_os() == 'windows' { '${short_v_name}.exe' } else { '$short_v_name' }
short_v2_file := if os.user_os() == 'windows' { 'v2.exe' } else { 'v2' } short_v2_file := if os.user_os() == 'windows' { 'v2.exe' } else { 'v2' }

View File

@ -11,7 +11,7 @@ fn main() {
$if windows { $if windows {
println('Setup freetype...') println('Setup freetype...')
vroot := os.dir(pref.vexe_path()) vroot := os.dir(pref.vexe_path())
os.chdir(vroot)? os.chdir(vroot)!
if os.is_dir(freetype_folder) { if os.is_dir(freetype_folder) {
println('Thirdparty "freetype" is already installed.') println('Thirdparty "freetype" is already installed.')
} else { } else {

View File

@ -122,7 +122,7 @@ fn shader_program_name(shader_file string) string {
} }
// validate_shader_file returns an error if `shader_file` isn't valid. // validate_shader_file returns an error if `shader_file` isn't valid.
fn validate_shader_file(shader_file string) ? { fn validate_shader_file(shader_file string) ! {
shader_program := os.read_lines(shader_file) or { shader_program := os.read_lines(shader_file) or {
return error('shader program at "$shader_file" could not be opened for reading') return error('shader program at "$shader_file" could not be opened for reading')
} }
@ -140,7 +140,7 @@ fn validate_shader_file(shader_file string) ? {
// compile_shaders compiles all `*.glsl` files found in `input_path` // compile_shaders compiles all `*.glsl` files found in `input_path`
// to their C header file representatives. // to their C header file representatives.
fn compile_shaders(opt Options, input_path string) ? { fn compile_shaders(opt Options, input_path string) ! {
mut path := os.real_path(input_path) mut path := os.real_path(input_path)
path = path.trim_right('/') path = path.trim_right('/')
if os.is_file(path) { if os.is_file(path) {
@ -172,12 +172,12 @@ fn compile_shaders(opt Options, input_path string) ? {
// Currently sokol-shdc allows for multiple --input flags // Currently sokol-shdc allows for multiple --input flags
// - but it's only the last entry that's actually compiled/used // - but it's only the last entry that's actually compiled/used
// Given this fact - we can only compile one '.glsl' file to one C '.h' header // Given this fact - we can only compile one '.glsl' file to one C '.h' header
compile_shader(co, shader_file)? compile_shader(co, shader_file)!
} }
} }
// compile_shader compiles `shader_file` to a C header file. // compile_shader compiles `shader_file` to a C header file.
fn compile_shader(opt CompileOptions, shader_file string) ? { fn compile_shader(opt CompileOptions, shader_file string) ! {
path := opt.invoke_path path := opt.invoke_path
// The output convetion, for now, is to use the name of the .glsl file // The output convetion, for now, is to use the name of the .glsl file
mut out_file := os.file_name(shader_file).all_before_last('.') + '.h' mut out_file := os.file_name(shader_file).all_before_last('.') + '.h'
@ -231,12 +231,12 @@ fn collect(path string, mut list []string) {
// ensure_external_tools returns nothing if the external // ensure_external_tools returns nothing if the external
// tools can be setup or is already in place. // tools can be setup or is already in place.
fn ensure_external_tools(opt Options) ? { fn ensure_external_tools(opt Options) ! {
if !os.exists(cache_dir) { if !os.exists(cache_dir) {
os.mkdir_all(cache_dir)? os.mkdir_all(cache_dir)!
} }
if opt.force_update { if opt.force_update {
download_shdc(opt)? download_shdc(opt)!
return return
} }
@ -250,7 +250,7 @@ fn ensure_external_tools(opt Options) ? {
return return
} }
download_shdc(opt)? download_shdc(opt)!
} }
// shdc_exe returns an absolute path to the `sokol-shdc` tool. // shdc_exe returns an absolute path to the `sokol-shdc` tool.
@ -261,7 +261,7 @@ fn shdc_exe() string {
} }
// download_shdc downloads the `sokol-shdc` tool to an OS specific cache directory. // download_shdc downloads the `sokol-shdc` tool to an OS specific cache directory.
fn download_shdc(opt Options) ? { fn download_shdc(opt Options) ! {
// We want to use the same, runtime, OS type as this tool is invoked on. // We want to use the same, runtime, OS type as this tool is invoked on.
download_url := shdc_urls[runtime_os] or { '' } download_url := shdc_urls[runtime_os] or { '' }
if download_url == '' { if download_url == '' {
@ -277,26 +277,26 @@ fn download_shdc(opt Options) ? {
} }
} }
if os.exists(file) { if os.exists(file) {
os.rm(file)? os.rm(file)!
} }
mut dtmp_file, dtmp_path := util.temp_file(util.TempFileOptions{ path: os.dir(file) })? mut dtmp_file, dtmp_path := util.temp_file(util.TempFileOptions{ path: os.dir(file) })!
dtmp_file.close() dtmp_file.close()
if opt.verbose { if opt.verbose {
eprintln('$tool_name downloading sokol-shdc from $download_url') eprintln('$tool_name downloading sokol-shdc from $download_url')
} }
http.download_file(download_url, dtmp_path) or { http.download_file(download_url, dtmp_path) or {
os.rm(dtmp_path)? os.rm(dtmp_path)!
return error('$tool_name failed to download sokol-shdc needed for shader compiling: $err') return error('$tool_name failed to download sokol-shdc needed for shader compiling: $err')
} }
// Make it executable // Make it executable
os.chmod(dtmp_path, 0o775)? os.chmod(dtmp_path, 0o775)!
// Move downloaded file in place // Move downloaded file in place
os.mv(dtmp_path, file)? os.mv(dtmp_path, file)!
if runtime_os in ['linux', 'macos'] { if runtime_os in ['linux', 'macos'] {
// Use the .exe file ending to minimize platform friction. // Use the .exe file ending to minimize platform friction.
os.mv(file, shdc)? os.mv(file, shdc)!
} }
// Update internal version file // Update internal version file
os.write_file(shdc_version_file, update_to_shdc_version)? os.write_file(shdc_version_file, update_to_shdc_version)!
} }

View File

@ -54,7 +54,7 @@ fn main() {
context.pref = &pref.Preferences{ context.pref = &pref.Preferences{
output_mode: .silent output_mode: .silent
} }
mut source := os.read_file(context.path)? mut source := os.read_file(context.path)!
source = source[..context.cut_index] source = source[..context.cut_index]
go fn (ms int) { go fn (ms int) {

View File

@ -6,7 +6,7 @@ import v.pref
fn main() { fn main() {
vexe := pref.vexe_path() vexe := pref.vexe_path()
vroot := os.dir(vexe) vroot := os.dir(vexe)
os.chdir(vroot)? os.chdir(vroot)!
os.setenv('VCOLORS', 'always', true) os.setenv('VCOLORS', 'always', true)
self_idx := os.args.index('tracev') self_idx := os.args.index('tracev')
args := os.args[1..self_idx] args := os.args[1..self_idx]

View File

@ -26,7 +26,7 @@ fn new_app() App {
fn main() { fn main() {
app := new_app() app := new_app()
recompilation.must_be_enabled(app.vroot, 'Please install V from source, to use `v up` .') recompilation.must_be_enabled(app.vroot, 'Please install V from source, to use `v up` .')
os.chdir(app.vroot)? os.chdir(app.vroot)!
println('Updating V...') println('Updating V...')
app.update_from_master() app.update_from_master()
v_hash := version.githash(false) v_hash := version.githash(false)

View File

@ -14,7 +14,7 @@ fn find_diff_cmd() string {
fn test_vet() { fn test_vet() {
vexe := os.getenv('VEXE') vexe := os.getenv('VEXE')
vroot := os.dir(vexe) vroot := os.dir(vexe)
os.chdir(vroot)? os.chdir(vroot)!
test_dir := 'cmd/tools/vvet/tests' test_dir := 'cmd/tools/vvet/tests'
tests := get_tests_in_dir(test_dir) tests := get_tests_in_dir(test_dir)
fails := check_path(vexe, test_dir, tests) fails := check_path(vexe, test_dir, tests)

View File

@ -318,7 +318,7 @@ fn main() {
fp.description('Collect all .v files needed for a compilation, then re-run the compilation when any of the source changes.') fp.description('Collect all .v files needed for a compilation, then re-run the compilation when any of the source changes.')
fp.arguments_description('[--silent] [--clear] [--ignore .db] [--add /path/to/a/file.v] [run] program.v') fp.arguments_description('[--silent] [--clear] [--ignore .db] [--add /path/to/a/file.v] [run] program.v')
fp.allow_unknown_args() fp.allow_unknown_args()
fp.limit_free_args_to_at_least(1)? fp.limit_free_args_to_at_least(1)!
context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.') context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.')
context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.') context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.')
context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.') context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.')

View File

@ -145,7 +145,7 @@ fn maybe_color(term_color fn (string) string, str string) string {
} }
} }
fn collect_v_files(path string, recursive bool) ?[]string { fn collect_v_files(path string, recursive bool) ![]string {
if path.len == 0 { if path.len == 0 {
return error('path cannot be empty') return error('path cannot be empty')
} }
@ -153,7 +153,7 @@ fn collect_v_files(path string, recursive bool) ?[]string {
return error('path does not exist or is not a directory') return error('path does not exist or is not a directory')
} }
mut all_files := []string{} mut all_files := []string{}
mut entries := os.ls(path)? mut entries := os.ls(path)!
mut local_path_separator := os.path_separator mut local_path_separator := os.path_separator
if path.ends_with(os.path_separator) { if path.ends_with(os.path_separator) {
local_path_separator = '' local_path_separator = ''
@ -161,7 +161,7 @@ fn collect_v_files(path string, recursive bool) ?[]string {
for entry in entries { for entry in entries {
file := path + local_path_separator + entry file := path + local_path_separator + entry
if os.is_dir(file) && !os.is_link(file) && recursive { if os.is_dir(file) && !os.is_link(file) && recursive {
all_files << collect_v_files(file, recursive)? all_files << collect_v_files(file, recursive)!
} else if os.exists(file) && (file.ends_with('.v') || file.ends_with('.vsh')) { } else if os.exists(file) && (file.ends_with('.v') || file.ends_with('.vsh')) {
all_files << file all_files << file
} }
@ -169,7 +169,7 @@ fn collect_v_files(path string, recursive bool) ?[]string {
return all_files return all_files
} }
fn resolve_module(path string) ?string { fn resolve_module(path string) !string {
if os.is_dir(path) { if os.is_dir(path) {
return path return path
} else if os.is_dir(os.join_path(vmod_dir, path)) { } else if os.is_dir(os.join_path(vmod_dir, path)) {

View File

@ -1901,8 +1901,8 @@ enum State {
} }
// write log file and return number of bytes written // write log file and return number of bytes written
fn write_log(s State) ?int { fn write_log(s State) !int {
mut f := os.create('log.txt')? mut f := os.create('log.txt')!
defer { defer {
f.close() f.close()
} }

View File

@ -5,9 +5,9 @@ import io
fn main() { fn main() {
// Make a new connection // Make a new connection
mut conn := net.dial_tcp('google.com:80')? mut conn := net.dial_tcp('google.com:80')!
// Simple http HEAD request for a file // Simple http HEAD request for a file
conn.write_string('GET /index.html HTTP/1.0\r\n\r\n')? conn.write_string('GET /index.html HTTP/1.0\r\n\r\n')!
// Wrap in a buffered reader // Wrap in a buffered reader
mut r := io.new_buffered_reader(reader: conn) mut r := io.new_buffered_reader(reader: conn)
for { for {

View File

@ -2,9 +2,9 @@ import net.http
import sync import sync
import time import time
fn vlang_time(mut wg sync.WaitGroup) ?string { fn vlang_time(mut wg sync.WaitGroup) !string {
start := time.ticks() start := time.ticks()
data := http.get('https://vlang.io/utc_now')? data := http.get('https://vlang.io/utc_now')!
finish := time.ticks() finish := time.ticks()
println('Finish getting time ${finish - start} ms') println('Finish getting time ${finish - start} ms')
println(data.body) println(data.body)
@ -12,9 +12,9 @@ fn vlang_time(mut wg sync.WaitGroup) ?string {
return data.body return data.body
} }
fn remote_ip(mut wg sync.WaitGroup) ?string { fn remote_ip(mut wg sync.WaitGroup) !string {
start := time.ticks() start := time.ticks()
data := http.get('https://api.ipify.org')? data := http.get('https://api.ipify.org')!
finish := time.ticks() finish := time.ticks()
println('Finish getting ip ${finish - start} ms') println('Finish getting ip ${finish - start} ms')
println(data.body) println(data.body)

View File

@ -10,9 +10,9 @@ type FNAdder = fn (int, int) int
fn main() { fn main() {
library_file_path := os.join_path(os.dir(@FILE), dl.get_libname('library')) library_file_path := os.join_path(os.dir(@FILE), dl.get_libname('library'))
handle := dl.open_opt(library_file_path, dl.rtld_lazy)? handle := dl.open_opt(library_file_path, dl.rtld_lazy)!
eprintln('handle: ${ptr_str(handle)}') eprintln('handle: ${ptr_str(handle)}')
f := FNAdder(dl.sym_opt(handle, 'add_1')?) f := FNAdder(dl.sym_opt(handle, 'add_1')!)
eprintln('f: ${ptr_str(f)}') eprintln('f: ${ptr_str(f)}')
res := f(1, 2) res := f(1, 2)
eprintln('res: $res') eprintln('res: $res')

View File

@ -34,5 +34,5 @@ fn main() {
mut server := Server{ mut server := Server{
handler: ExampleHandler{} handler: ExampleHandler{}
} }
server.listen_and_serve()? server.listen_and_serve()
} }

View File

@ -5,7 +5,7 @@ import os
const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`] const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`]
// Convert expression to Reverse Polish Notation. // Convert expression to Reverse Polish Notation.
fn expr_to_rev_pol(expr string) ?[]string { fn expr_to_rev_pol(expr string) ![]string {
if expr == '' { if expr == '' {
return error('err: empty expression') return error('err: empty expression')
} }
@ -63,7 +63,7 @@ fn expr_to_rev_pol(expr string) ?[]string {
} }
// Evaluate the result of Reverse Polish Notation. // Evaluate the result of Reverse Polish Notation.
fn eval_rev_pol(rev_pol []string) ?f64 { fn eval_rev_pol(rev_pol []string) !f64 {
mut stack := []f64{} mut stack := []f64{}
for item in rev_pol { for item in rev_pol {
if is_num_string(item) { if is_num_string(item) {

View File

@ -1,5 +1,5 @@
import net import net
conn := net.dial_tcp('[::1]:57000')? conn := net.dial_tcp('[::1]:57000')!
peer_addr := conn.peer_addr()? peer_addr := conn.peer_addr()!
println('$peer_addr') println('$peer_addr')

View File

@ -1,5 +1,5 @@
import net import net
conn := net.dial_tcp('google.com:80')? conn := net.dial_tcp('google.com:80')!
peer_addr := conn.peer_addr()? peer_addr := conn.peer_addr()!
println('$peer_addr') println('$peer_addr')

View File

@ -3,18 +3,18 @@ import io
fn main() { fn main() {
// Make a new connection // Make a new connection
mut conn := net.dial_tcp('google.com:80')? mut conn := net.dial_tcp('google.com:80')!
defer { defer {
conn.close() or {} conn.close() or {}
} }
println(' peer: ${conn.peer_addr()?}') println(' peer: ${conn.peer_addr()!}')
println('local: ${conn.addr()?}') println('local: ${conn.addr()!}')
// Simple http HEAD request for a file // Simple http HEAD request for a file
conn.write_string('HEAD /index.html HTTP/1.0\r\n\r\n')? conn.write_string('HEAD /index.html HTTP/1.0\r\n\r\n')!
// Read all the data that is waiting // Read all the data that is waiting
result := io.read_all(reader: conn)? result := io.read_all(reader: conn)!
// Cast to string and print result // Cast to string and print result
println(result.bytestr()) println(result.bytestr())
} }

View File

@ -2,9 +2,9 @@ import net.http
import sync import sync
import time import time
fn send_request(mut wg sync.WaitGroup) ?string { fn send_request(mut wg sync.WaitGroup) !string {
start := time.ticks() start := time.ticks()
data := http.get('https://google.com')? data := http.get('https://google.com')!
finish := time.ticks() finish := time.ticks()
println('Finish getting time ${finish - start} ms') println('Finish getting time ${finish - start} ms')
wg.done() wg.done()

View File

@ -12,7 +12,7 @@ fn main() {
mut buf := []u8{len: 100} mut buf := []u8{len: 100}
if is_server { if is_server {
println('UDP echo server, listening for udp packets on port: $port') println('UDP echo server, listening for udp packets on port: $port')
mut c := net.listen_udp(':$port')? mut c := net.listen_udp(':$port')!
for { for {
read, addr := c.read(mut buf) or { continue } read, addr := c.read(mut buf) or { continue }
println('received $read bytes from $addr') println('received $read bytes from $addr')
@ -23,7 +23,7 @@ fn main() {
} }
} else { } else {
println('UDP client, sending packets to port: ${port}.\nType `exit` to exit.') println('UDP client, sending packets to port: ${port}.\nType `exit` to exit.')
mut c := net.dial_udp('localhost:$port')? mut c := net.dial_udp('localhost:$port')!
for { for {
mut line := os.input('client > ') mut line := os.input('client > ')
match line { match line {
@ -36,8 +36,8 @@ fn main() {
} }
else {} else {}
} }
c.write_string(line)? c.write_string(line)!
read, _ := c.read(mut buf)? read, _ := c.read(mut buf)!
println('server : ' + buf[0..read].bytestr()) println('server : ' + buf[0..read].bytestr())
} }
} }

View File

@ -6,7 +6,7 @@ import sim.anim
import sim.args as simargs import sim.args as simargs
fn main() { fn main() {
args := simargs.parse_args(extra_workers: 1)? as simargs.ParallelArgs args := simargs.parse_args(extra_workers: 1)! as simargs.ParallelArgs
mut app := anim.new_app(args) mut app := anim.new_app(args)
mut workers := []thread{cap: args.workers} mut workers := []thread{cap: args.workers}
@ -27,7 +27,7 @@ fn main() {
workers << go sim.sim_worker(id, app.request_chan, [app.result_chan]) workers << go sim.sim_worker(id, app.request_chan, [app.result_chan])
} }
handle_request := fn [app] (request &sim.SimRequest) ? { handle_request := fn [app] (request &sim.SimRequest) ! {
app.request_chan <- request app.request_chan <- request
} }

View File

@ -7,11 +7,11 @@ import sim.args as simargs
import sim.img import sim.img
fn main() { fn main() {
args := simargs.parse_args(extra_workers: 2)? as simargs.ParallelArgs args := simargs.parse_args(extra_workers: 2)! as simargs.ParallelArgs
img_settings := img.image_settings_from_grid(args.grid) img_settings := img.image_settings_from_grid(args.grid)
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)? mut writer := img.ppm_writer_for_fname(args.filename, img_settings)!
mut app := anim.new_app(args) mut app := anim.new_app(args)
mut workers := []thread{cap: args.workers + 1} mut workers := []thread{cap: args.workers + 1}
@ -41,7 +41,7 @@ fn main() {
workers << go sim.sim_worker(id, app.request_chan, [app.result_chan, img_result_chan]) workers << go sim.sim_worker(id, app.request_chan, [app.result_chan, img_result_chan])
} }
handle_request := fn [app] (request &sim.SimRequest) ? { handle_request := fn [app] (request &sim.SimRequest) ! {
app.request_chan <- request app.request_chan <- request
} }

View File

@ -31,21 +31,21 @@ pub:
pub type SimArgs = ParallelArgs | SequentialArgs pub type SimArgs = ParallelArgs | SequentialArgs
pub fn parse_args(config ParserSettings) ?SimArgs { pub fn parse_args(config ParserSettings) !SimArgs {
if config.sequential { if config.sequential {
args := parse_sequential_args()? args := parse_sequential_args()!
return SimArgs(args) return SimArgs(args)
} else { } else {
args := parse_parallel_args(config.extra_workers)? args := parse_parallel_args(config.extra_workers)!
return SimArgs(args) return SimArgs(args)
} }
} }
fn parse_sequential_args() ?SequentialArgs { fn parse_sequential_args() !SequentialArgs {
mut fp := flag.new_flag_parser(os.args) mut fp := flag.new_flag_parser(os.args)
fp.application('vps') fp.application('vps')
fp.version('v0.1.0') fp.version('v0.1.0')
fp.limit_free_args(0, 0)? fp.limit_free_args(0, 0)!
fp.description('This is a pendulum simulation written in pure V') fp.description('This is a pendulum simulation written in pure V')
fp.skip_executable() fp.skip_executable()
@ -64,7 +64,7 @@ fn parse_sequential_args() ?SequentialArgs {
fp.finalize() or { fp.finalize() or {
println(fp.usage()) println(fp.usage())
return none return error('none')
} }
params := sim.sim_params( params := sim.sim_params(
@ -92,11 +92,11 @@ fn parse_sequential_args() ?SequentialArgs {
return args return args
} }
fn parse_parallel_args(extra_workers int) ?ParallelArgs { fn parse_parallel_args(extra_workers int) !ParallelArgs {
mut fp := flag.new_flag_parser(os.args) mut fp := flag.new_flag_parser(os.args)
fp.application('vps') fp.application('vps')
fp.version('v0.1.0') fp.version('v0.1.0')
fp.limit_free_args(0, 0)? fp.limit_free_args(0, 0)!
fp.description('This is a pendulum simulation written in pure V') fp.description('This is a pendulum simulation written in pure V')
fp.skip_executable() fp.skip_executable()
@ -117,7 +117,7 @@ fn parse_parallel_args(extra_workers int) ?ParallelArgs {
fp.finalize() or { fp.finalize() or {
println(fp.usage()) println(fp.usage())
return none return error('none')
} }
params := sim.sim_params( params := sim.sim_params(

View File

@ -39,34 +39,34 @@ mut:
cache_size int cache_size int
} }
pub fn ppm_writer_for_fname(fname string, settings ImageSettings) ?&PPMWriter { pub fn ppm_writer_for_fname(fname string, settings ImageSettings) !&PPMWriter {
mut writer := &PPMWriter{ mut writer := &PPMWriter{
cache_size: settings.cache_size cache_size: settings.cache_size
cache: []u8{cap: settings.cache_size} cache: []u8{cap: settings.cache_size}
} }
writer.start_for_file(fname, settings)? writer.start_for_file(fname, settings)!
return writer return writer
} }
pub fn (mut writer PPMWriter) start_for_file(fname string, settings ImageSettings) ? { pub fn (mut writer PPMWriter) start_for_file(fname string, settings ImageSettings) ! {
writer.file = os.create(fname)? writer.file = os.create(fname)!
writer.file.writeln('P6 $settings.width $settings.height 255')? writer.file.writeln('P6 $settings.width $settings.height 255')!
} }
pub fn (mut writer PPMWriter) handle_pixel(p gx.Color) ? { pub fn (mut writer PPMWriter) handle_pixel(p gx.Color) ! {
if writer.cache.len >= writer.cache_size { if writer.cache.len >= writer.cache_size {
writer.write()? writer.write()!
writer.flush()? writer.flush()!
} }
writer.cache << [p.r, p.g, p.b] writer.cache << [p.r, p.g, p.b]
} }
pub fn (mut writer PPMWriter) flush() ? { pub fn (mut writer PPMWriter) flush() ! {
writer.cache.clear() writer.cache.clear()
} }
pub fn (mut writer PPMWriter) write() ? { pub fn (mut writer PPMWriter) write() ! {
writer.file.write(writer.cache)? writer.file.write(writer.cache)!
} }
pub fn (mut writer PPMWriter) close() { pub fn (mut writer PPMWriter) close() {

View File

@ -29,7 +29,7 @@ pub fn new_image_writer(mut writer PPMWriter, settings ImageSettings) &ImageWrit
} }
} }
pub fn (mut iw ImageWritter) handle(result sim.SimResult) ?int { pub fn (mut iw ImageWritter) handle(result sim.SimResult) !int {
total_pixels := iw.settings.width * iw.settings.height total_pixels := iw.settings.width * iw.settings.height
// find the closest magnet // find the closest magnet
@ -46,7 +46,7 @@ pub fn (mut iw ImageWritter) handle(result sim.SimResult) ?int {
if iw.current_index == total_pixels { if iw.current_index == total_pixels {
iw.writer.write() or { panic('Could not write image') } iw.writer.write() or { panic('Could not write image') }
return none return error('none')
} }
return iw.current_index return iw.current_index

View File

@ -3,11 +3,11 @@ module sim
import benchmark import benchmark
import term import term
pub type SimRequestHandler = fn (request &SimRequest) ? pub type SimRequestHandler = fn (request &SimRequest) !
pub type SimStartHandler = fn () ? pub type SimStartHandler = fn () !
pub type SimFinishHandler = fn () ? pub type SimFinishHandler = fn () !
pub const ( pub const (
default_width = 600 default_width = 600

View File

@ -6,7 +6,7 @@ import sim.args as simargs
import sim.img import sim.img
fn main() { fn main() {
args := simargs.parse_args()? as simargs.ParallelArgs args := simargs.parse_args()! as simargs.ParallelArgs
img_settings := img.image_settings_from_grid(args.grid) img_settings := img.image_settings_from_grid(args.grid)
@ -17,7 +17,7 @@ fn main() {
request_chan := chan &sim.SimRequest{cap: args.workers} request_chan := chan &sim.SimRequest{cap: args.workers}
result_chan := chan &sim.SimResult{cap: args.workers} result_chan := chan &sim.SimResult{cap: args.workers}
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)? mut writer := img.ppm_writer_for_fname(args.filename, img_settings)!
mut image_writer := img.new_image_writer(mut writer, img_settings) mut image_writer := img.new_image_writer(mut writer, img_settings)
mut workers := []thread{cap: args.workers} mut workers := []thread{cap: args.workers}

View File

@ -6,14 +6,14 @@ import sim.args as simargs
import sim.img import sim.img
fn main() { fn main() {
args := simargs.parse_args(extra_workers: 1)? as simargs.ParallelArgs args := simargs.parse_args(extra_workers: 1)! as simargs.ParallelArgs
img_settings := img.image_settings_from_grid(args.grid) img_settings := img.image_settings_from_grid(args.grid)
request_chan := chan &sim.SimRequest{cap: args.workers} request_chan := chan &sim.SimRequest{cap: args.workers}
result_chan := chan &sim.SimResult{cap: args.workers} result_chan := chan &sim.SimResult{cap: args.workers}
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)? mut writer := img.ppm_writer_for_fname(args.filename, img_settings)!
mut workers := []thread{cap: args.workers + 1} mut workers := []thread{cap: args.workers + 1}
mut bmark := benchmark.start() mut bmark := benchmark.start()
@ -39,7 +39,7 @@ fn main() {
workers << go img.image_worker(mut writer, result_chan, img_settings) workers << go img.image_worker(mut writer, result_chan, img_settings)
handle_request := fn [request_chan] (request &sim.SimRequest) ? { handle_request := fn [request_chan] (request &sim.SimRequest) ! {
request_chan <- request request_chan <- request
} }

View File

@ -6,19 +6,19 @@ import sim.args as simargs
import sim.img import sim.img
fn main() { fn main() {
args := simargs.parse_args(sequential: true)? as simargs.SequentialArgs args := simargs.parse_args(sequential: true)! as simargs.SequentialArgs
mut bmark := benchmark.start() mut bmark := benchmark.start()
defer { defer {
bmark.measure(@FN) bmark.measure(@FN)
} }
mut writer := img.ppm_writer_for_fname(args.filename, img.image_settings_from_grid(args.grid))? mut writer := img.ppm_writer_for_fname(args.filename, img.image_settings_from_grid(args.grid))!
defer { defer {
writer.close() writer.close()
} }
handle_request := fn [mut writer] (request &sim.SimRequest) ? { handle_request := fn [mut writer] (request &sim.SimRequest) ! {
result := sim.compute_result(request) result := sim.compute_result(request)
pixel := img.compute_pixel(result) pixel := img.compute_pixel(result)
return writer.handle_pixel(pixel) return writer.handle_pixel(pixel)
@ -26,5 +26,5 @@ fn main() {
sim.run(args.params, grid: args.grid, on_request: sim.SimRequestHandler(handle_request)) sim.run(args.params, grid: args.grid, on_request: sim.SimRequestHandler(handle_request))
writer.write()? writer.write()!
} }

View File

@ -9,11 +9,11 @@ import net
// telnet 127.0.0.1 12345 // telnet 127.0.0.1 12345
fn main() { fn main() {
mut server := net.listen_tcp(.ip6, ':12345')? mut server := net.listen_tcp(.ip6, ':12345')!
laddr := server.addr()? laddr := server.addr()!
eprintln('Listen on $laddr ...') eprintln('Listen on $laddr ...')
for { for {
mut socket := server.accept()? mut socket := server.accept()!
go handle_client(mut socket) go handle_client(mut socket)
} }
} }

View File

@ -14,21 +14,21 @@ fn main() {
} }
// create TCP listener // create TCP listener
mut listener := net.listen_tcp(.ip, 'localhost:9001')? mut listener := net.listen_tcp(.ip, 'localhost:9001')!
defer { defer {
listener.close() or {} listener.close() or {}
} }
addr := listener.addr()? addr := listener.addr()!
eprintln('Listening on $addr') eprintln('Listening on $addr')
eprintln('Type `stop` to stop the server') eprintln('Type `stop` to stop the server')
// create file descriptor notifier // create file descriptor notifier
mut notifier := notify.new()? mut notifier := notify.new()!
defer { defer {
notifier.close() or {} notifier.close() or {}
} }
notifier.add(os.stdin().fd, .read)? notifier.add(os.stdin().fd, .read)!
notifier.add(listener.sock.handle, .read)? notifier.add(listener.sock.handle, .read)!
for { for {
for event in notifier.wait(time.infinite) { for event in notifier.wait(time.infinite) {

View File

@ -150,10 +150,10 @@ fn (item_list Item_list) get_file_path() string {
* Scan functions * Scan functions
* *
******************************************************************************/ ******************************************************************************/
fn (mut item_list Item_list) scan_folder(path string, in_index int) ? { fn (mut item_list Item_list) scan_folder(path string, in_index int) ! {
println('Scanning [$path]') println('Scanning [$path]')
mut folder_list := []string{} mut folder_list := []string{}
lst := os.ls(path)? lst := os.ls(path)!
// manage the single files // manage the single files
for c, x in lst { for c, x in lst {
@ -171,7 +171,7 @@ fn (mut item_list Item_list) scan_folder(path string, in_index int) ? {
if ext == .zip { if ext == .zip {
item.i_type = .zip item.i_type = .zip
item_list.lst << item item_list.lst << item
item_list.scan_zip(pt, item_list.lst.len - 1)? item_list.scan_zip(pt, item_list.lst.len - 1)!
continue continue
} }
if is_image(ext) == true { if is_image(ext) == true {
@ -194,7 +194,7 @@ fn (mut item_list Item_list) scan_folder(path string, in_index int) ? {
i_type: .folder i_type: .folder
} }
item_list.lst << item item_list.lst << item
item_list.scan_folder(pt, item_list.lst.len - 1)? item_list.scan_folder(pt, item_list.lst.len - 1)!
} }
// println(item_list.lst.len) // println(item_list.lst.len)
// println("==================================") // println("==================================")

View File

@ -11,14 +11,14 @@
import sokol.gfx import sokol.gfx
import szip import szip
fn (mut il Item_list) scan_zip(path string, in_index int) ? { fn (mut il Item_list) scan_zip(path string, in_index int) ! {
println('Scanning ZIP [$path]') println('Scanning ZIP [$path]')
mut zp := szip.open(path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)? mut zp := szip.open(path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)!
n_entries := zp.total()? n_entries := zp.total()!
// println(n_entries) // println(n_entries)
for index in 0 .. n_entries { for index in 0 .. n_entries {
zp.open_entry_by_index(index)? zp.open_entry_by_index(index)!
is_dir := zp.is_dir()? is_dir := zp.is_dir()!
name := zp.name() name := zp.name()
size := zp.size() size := zp.size()
// println("$index ${name} ${size:10} $is_dir") // println("$index ${name} ${size:10} $is_dir")
@ -47,7 +47,7 @@ fn (mut il Item_list) scan_zip(path string, in_index int) ? {
zp.close() zp.close()
} }
fn (mut app App) load_texture_from_zip() ?(gfx.Image, int, int) { fn (mut app App) load_texture_from_zip() !(gfx.Image, int, int) {
item := app.item_list.lst[app.item_list.item_index] item := app.item_list.lst[app.item_list.item_index]
// println("Load from zip [${item.path}]") // println("Load from zip [${item.path}]")
@ -58,15 +58,15 @@ fn (mut app App) load_texture_from_zip() ?(gfx.Image, int, int) {
} }
app.zip_index = item.container_index app.zip_index = item.container_index
// println("Opening the zip [${item.path}]") // println("Opening the zip [${item.path}]")
app.zip = szip.open(item.path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)? app.zip = szip.open(item.path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)!
} }
// println("Now get the image") // println("Now get the image")
app.zip.open_entry_by_index(item.container_item_index)? app.zip.open_entry_by_index(item.container_item_index)!
zip_entry_size := int(item.size) zip_entry_size := int(item.size)
app.resize_buf_if_needed(zip_entry_size) app.resize_buf_if_needed(zip_entry_size)
app.zip.read_entry_buf(app.mem_buf, app.mem_buf_size)? app.zip.read_entry_buf(app.mem_buf, app.mem_buf_size)!
app.zip.close_entry() app.zip.close_entry()
return app.load_texture_from_buffer(app.mem_buf, zip_entry_size) return app.load_texture_from_buffer(app.mem_buf, zip_entry_size)
} }

View File

@ -17,7 +17,7 @@ fn main() {
mut app := &App{} mut app := &App{}
app.serve_static('/favicon.ico', 'favicon.ico') app.serve_static('/favicon.ico', 'favicon.ico')
// Automatically make available known static mime types found in given directory. // Automatically make available known static mime types found in given directory.
os.chdir(os.dir(os.executable()))? os.chdir(os.dir(os.executable()))!
app.handle_static('assets', true) app.handle_static('assets', true)
vweb.run(app, port) vweb.run(app, port)
} }

View File

@ -8,7 +8,7 @@ import term
// it connects to the server who will broadcast your messages // it connects to the server who will broadcast your messages
// to all other connected clients // to all other connected clients
fn main() { fn main() {
mut ws := start_client()? mut ws := start_client()!
println(term.green('client $ws.id ready')) println(term.green('client $ws.id ready'))
println('Write message and enter to send...') println('Write message and enter to send...')
for { for {
@ -16,7 +16,7 @@ fn main() {
if line == '' { if line == '' {
break break
} }
ws.write_string(line)? ws.write_string(line)!
} }
ws.close(1000, 'normal') or { println(term.red('panicing $err')) } ws.close(1000, 'normal') or { println(term.red('panicing $err')) }
unsafe { unsafe {
@ -24,23 +24,23 @@ fn main() {
} }
} }
fn start_client() ?&websocket.Client { fn start_client() !&websocket.Client {
mut ws := websocket.new_client('ws://localhost:30000')? mut ws := websocket.new_client('ws://localhost:30000')!
// mut ws := websocket.new_client('wss://echo.websocket.org:443')? // mut ws := websocket.new_client('wss://echo.websocket.org:443')?
// use on_open_ref if you want to send any reference object // use on_open_ref if you want to send any reference object
ws.on_open(fn (mut ws websocket.Client) ? { ws.on_open(fn (mut ws websocket.Client) ! {
println(term.green('websocket connected to the server and ready to send messages...')) println(term.green('websocket connected to the server and ready to send messages...'))
}) })
// use on_error_ref if you want to send any reference object // use on_error_ref if you want to send any reference object
ws.on_error(fn (mut ws websocket.Client, err string) ? { ws.on_error(fn (mut ws websocket.Client, err string) ! {
println(term.red('error: $err')) println(term.red('error: $err'))
}) })
// use on_close_ref if you want to send any reference object // use on_close_ref if you want to send any reference object
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ? { ws.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
println(term.green('the connection to the server successfully closed')) println(term.green('the connection to the server successfully closed'))
}) })
// on new messages from other clients, display them in blue text // on new messages from other clients, display them in blue text
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? { ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
if msg.payload.len > 0 { if msg.payload.len > 0 {
message := msg.payload.bytestr() message := msg.payload.bytestr()
println(term.blue('$message')) println(term.blue('$message'))

View File

@ -6,24 +6,24 @@ import term
// this server accepts client connections and broadcast all messages to other connected clients // this server accepts client connections and broadcast all messages to other connected clients
fn main() { fn main() {
println('press ctrl-c to quit...') println('press ctrl-c to quit...')
start_server()? start_server()!
} }
fn start_server() ? { fn start_server() ! {
mut s := websocket.new_server(.ip6, 30000, '') mut s := websocket.new_server(.ip6, 30000, '')
// Make that in execution test time give time to execute at least one time // Make that in execution test time give time to execute at least one time
s.ping_interval = 100 s.ping_interval = 100
s.on_connect(fn (mut s websocket.ServerClient) ?bool { s.on_connect(fn (mut s websocket.ServerClient) !bool {
// Here you can look att the client info and accept or not accept // Here you can look att the client info and accept or not accept
// just returning a true/false // just returning a true/false
if s.resource_name != '/' { if s.resource_name != '/' {
return false return false
} }
return true return true
})? })!
// on_message_ref, broadcast all incoming messages to all clients except the one sent it // on_message_ref, broadcast all incoming messages to all clients except the one sent it
s.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut m websocket.Server) ? { s.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut m websocket.Server) ! {
// for _, cli in m.clients { // for _, cli in m.clients {
for i, _ in m.clients { for i, _ in m.clients {
mut c := m.clients[i] mut c := m.clients[i]
@ -33,7 +33,7 @@ fn start_server() ? {
} }
}, s) }, s)
s.on_close(fn (mut ws websocket.Client, code int, reason string) ? { s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
println(term.green('client ($ws.id) closed connection')) println(term.green('client ($ws.id) closed connection'))
}) })
s.listen() or { println(term.red('error on server listen: $err')) } s.listen() or { println(term.red('error on server listen: $err')) }

View File

@ -6,27 +6,27 @@ import net.websocket
fn main() { fn main() {
go start_server() go start_server()
time.sleep(100 * time.millisecond) time.sleep(100 * time.millisecond)
start_client()? start_client()!
} }
// start_server starts the websocket server, it receives messages // start_server starts the websocket server, it receives messages
// and send it back to the client that sent it // and send it back to the client that sent it
fn start_server() ? { fn start_server() ! {
mut s := websocket.new_server(.ip6, 30000, '') mut s := websocket.new_server(.ip6, 30000, '')
// Make that in execution test time give time to execute at least one time // Make that in execution test time give time to execute at least one time
s.ping_interval = 100 s.ping_interval = 100
s.on_connect(fn (mut s websocket.ServerClient) ?bool { s.on_connect(fn (mut s websocket.ServerClient) !bool {
// Here you can look att the client info and accept or not accept // Here you can look att the client info and accept or not accept
// just returning a true/false // just returning a true/false
if s.resource_name != '/' { if s.resource_name != '/' {
return false return false
} }
return true return true
})? })!
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? { s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
ws.write(msg.payload, msg.opcode) or { panic(err) } ws.write(msg.payload, msg.opcode) or { panic(err) }
}) })
s.on_close(fn (mut ws websocket.Client, code int, reason string) ? { s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
// println('client ($ws.id) closed connection') // println('client ($ws.id) closed connection')
}) })
s.listen() or { println('error on server listen: $err') } s.listen() or { println('error on server listen: $err') }
@ -37,23 +37,23 @@ fn start_server() ? {
// start_client starts the websocket client, it writes a message to // start_client starts the websocket client, it writes a message to
// the server and prints all the messages received // the server and prints all the messages received
fn start_client() ? { fn start_client() ! {
mut ws := websocket.new_client('ws://localhost:30000')? mut ws := websocket.new_client('ws://localhost:30000')!
// mut ws := websocket.new_client('wss://echo.websocket.org:443')? // mut ws := websocket.new_client('wss://echo.websocket.org:443')?
// use on_open_ref if you want to send any reference object // use on_open_ref if you want to send any reference object
ws.on_open(fn (mut ws websocket.Client) ? { ws.on_open(fn (mut ws websocket.Client) ! {
println('open!') println('open!')
}) })
// use on_error_ref if you want to send any reference object // use on_error_ref if you want to send any reference object
ws.on_error(fn (mut ws websocket.Client, err string) ? { ws.on_error(fn (mut ws websocket.Client, err string) ! {
println('error: $err') println('error: $err')
}) })
// use on_close_ref if you want to send any reference object // use on_close_ref if you want to send any reference object
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ? { ws.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
println('closed') println('closed')
}) })
// use on_message_ref if you want to send any reference object // use on_message_ref if you want to send any reference object
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? { ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
if msg.payload.len > 0 { if msg.payload.len > 0 {
message := msg.payload.bytestr() message := msg.payload.bytestr()
println('client got type: $msg.opcode payload:\n$message') println('client got type: $msg.opcode payload:\n$message')
@ -72,7 +72,7 @@ fn start_client() ? {
} }
} }
fn write_echo(mut ws websocket.Client) ? { fn write_echo(mut ws websocket.Client) ! {
message := 'echo this' message := 'echo this'
for i := 0; i <= 10; i++ { for i := 0; i <= 10; i++ {
// Server will send pings every 30 seconds // Server will send pings every 30 seconds

View File

@ -624,7 +624,7 @@ pub fn (s string) u64() u64 {
// This method directly exposes the `parse_int` function from `strconv` // This method directly exposes the `parse_int` function from `strconv`
// as a method on `string`. For more advanced features, // as a method on `string`. For more advanced features,
// consider calling `strconv.common_parse_int` directly. // consider calling `strconv.common_parse_int` directly.
pub fn (s string) parse_uint(_base int, _bit_size int) ?u64 { pub fn (s string) parse_uint(_base int, _bit_size int) !u64 {
return strconv.parse_uint(s, _base, _bit_size) return strconv.parse_uint(s, _base, _bit_size)
} }
@ -644,7 +644,7 @@ pub fn (s string) parse_uint(_base int, _bit_size int) ?u64 {
// This method directly exposes the `parse_uint` function from `strconv` // This method directly exposes the `parse_uint` function from `strconv`
// as a method on `string`. For more advanced features, // as a method on `string`. For more advanced features,
// consider calling `strconv.common_parse_uint` directly. // consider calling `strconv.common_parse_uint` directly.
pub fn (s string) parse_int(_base int, _bit_size int) ?i64 { pub fn (s string) parse_int(_base int, _bit_size int) !i64 {
return strconv.parse_int(s, _base, _bit_size) return strconv.parse_int(s, _base, _bit_size)
} }

View File

@ -28,7 +28,7 @@ pub fn get_libname(libname string) string {
// open_opt - loads the dynamic shared object. // open_opt - loads the dynamic shared object.
// Unlike open, open_opt return an option. // Unlike open, open_opt return an option.
pub fn open_opt(filename string, flags int) ?voidptr { pub fn open_opt(filename string, flags int) !voidptr {
shared_object_handle := open(filename, flags) shared_object_handle := open(filename, flags)
if shared_object_handle == 0 { if shared_object_handle == 0 {
e := dlerror() e := dlerror()
@ -39,7 +39,7 @@ pub fn open_opt(filename string, flags int) ?voidptr {
// sym_opt returns the address of a symbol in a given shared object, if found. // sym_opt returns the address of a symbol in a given shared object, if found.
// Unlike sym, sym_opt returns an option. // Unlike sym, sym_opt returns an option.
pub fn sym_opt(shared_object_handle voidptr, symbol string) ?voidptr { pub fn sym_opt(shared_object_handle voidptr, symbol string) !voidptr {
sym_handle := sym(shared_object_handle, symbol) sym_handle := sym(shared_object_handle, symbol)
if sym_handle == 0 { if sym_handle == 0 {
e := dlerror() e := dlerror()

View File

@ -71,7 +71,7 @@ pub fn (af []Flag) str() string {
// That structure is created with `mut parser := flag.new_flag_parser(os.args)`, // That structure is created with `mut parser := flag.new_flag_parser(os.args)`,
// The returned instance can be further customised by calling various methods, // The returned instance can be further customised by calling various methods,
// for specifying the accepted options and their values. The user should finally // for specifying the accepted options and their values. The user should finally
// call `rest := parser.finalize()?` to get the rest of the non optional arguments // call `rest := parser.finalize()!` to get the rest of the non optional arguments
// (if there are any left). // (if there are any left).
pub struct FlagParser { pub struct FlagParser {
pub: pub:
@ -278,7 +278,7 @@ fn (mut fs FlagParser) parse_value(longhand string, shorthand u8) []string {
// special: it is allowed to define bool flags without value // special: it is allowed to define bool flags without value
// -> '--flag' is parsed as true // -> '--flag' is parsed as true
// -> '--flag' is equal to '--flag=true' // -> '--flag' is equal to '--flag=true'
fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) ?string { fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) !string {
{ {
full := '--$longhand' full := '--$longhand'
for i, arg in fs.args { for i, arg in fs.args {
@ -317,7 +317,7 @@ fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) ?string {
// bool_opt returns an option with the bool value of the given command line flag, named `name`. // bool_opt returns an option with the bool value of the given command line flag, named `name`.
// It returns an error, when the flag is not given by the user. // It returns an error, when the flag is not given by the user.
// This version supports abbreviations. // This version supports abbreviations.
pub fn (mut fs FlagParser) bool_opt(name string, abbr u8, usage string) ?bool { pub fn (mut fs FlagParser) bool_opt(name string, abbr u8, usage string) !bool {
mut res := false mut res := false
{ {
fs.add_flag(name, abbr, usage, '<bool>') fs.add_flag(name, abbr, usage, '<bool>')
@ -354,7 +354,7 @@ pub fn (mut fs FlagParser) int_multi(name string, abbr u8, usage string) []int {
// int_opt returns an option with the integer value, associated with the flag in `name`. // int_opt returns an option with the integer value, associated with the flag in `name`.
// When the flag is not given by the user, it returns an error. // When the flag is not given by the user, it returns an error.
// This version supports abbreviations. // This version supports abbreviations.
pub fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string) ?int { pub fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string) !int {
mut res := 0 mut res := 0
{ {
fs.add_flag(name, abbr, usage, '<int>') fs.add_flag(name, abbr, usage, '<int>')
@ -393,7 +393,7 @@ pub fn (mut fs FlagParser) float_multi(name string, abbr u8, usage string) []f64
// float_opt returns an option with the floating point value, associated with the flag in `name`. // float_opt returns an option with the floating point value, associated with the flag in `name`.
// When the flag is not given by the user, it returns an error. // When the flag is not given by the user, it returns an error.
// This version supports abbreviations. // This version supports abbreviations.
pub fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string) ?f64 { pub fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string) !f64 {
mut res := 0.0 mut res := 0.0
{ {
fs.add_flag(name, abbr, usage, '<float>') fs.add_flag(name, abbr, usage, '<float>')
@ -426,7 +426,7 @@ pub fn (mut fs FlagParser) string_multi(name string, abbr u8, usage string) []st
// string_opt returns an option with the string value, associated with the flag in `name`. // string_opt returns an option with the string value, associated with the flag in `name`.
// When the flag is not given by the user, it returns an error. // When the flag is not given by the user, it returns an error.
// This version supports abbreviations. // This version supports abbreviations.
pub fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string) ?string { pub fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string) !string {
mut res := '' mut res := ''
{ {
fs.add_flag(name, abbr, usage, '<string>') fs.add_flag(name, abbr, usage, '<string>')
@ -451,7 +451,7 @@ pub fn (mut fs FlagParser) string(name string, abbr u8, sdefault string, usage s
// limit_free_args_to_at_least restricts the list of free arguments (non options) to be // limit_free_args_to_at_least restricts the list of free arguments (non options) to be
// at least `n` in length. If the user gives less free arguments to the program, // at least `n` in length. If the user gives less free arguments to the program,
// the parser will return an error. // the parser will return an error.
pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ? { pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ! {
if n > flag.max_args_number { if n > flag.max_args_number {
return error('flag.limit_free_args_to_at_least expect n to be smaller than $flag.max_args_number') return error('flag.limit_free_args_to_at_least expect n to be smaller than $flag.max_args_number')
} }
@ -464,7 +464,7 @@ pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ? {
// limit_free_args_to_exactly restricts the list of free arguments (non options) to be // limit_free_args_to_exactly restricts the list of free arguments (non options) to be
// at exactly `n` in length. If the user gives more or less free arguments to the program, // at exactly `n` in length. If the user gives more or less free arguments to the program,
// the parser will return an error. // the parser will return an error.
pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ? { pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ! {
if n > flag.max_args_number { if n > flag.max_args_number {
return error('flag.limit_free_args_to_exactly expect n to be smaller than $flag.max_args_number') return error('flag.limit_free_args_to_exactly expect n to be smaller than $flag.max_args_number')
} }
@ -478,7 +478,7 @@ pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ? {
// limit_free_args restricts the list of free arguments (non options) to be between // limit_free_args restricts the list of free arguments (non options) to be between
// `min` and `max` in length. If the user gives more or less free arguments to the program, // `min` and `max` in length. If the user gives more or less free arguments to the program,
// the parser will return an error. // the parser will return an error.
pub fn (mut fs FlagParser) limit_free_args(min int, max int) ? { pub fn (mut fs FlagParser) limit_free_args(min int, max int) ! {
if min > max { if min > max {
return error('flag.limit_free_args expect min < max, got $min >= $max') return error('flag.limit_free_args expect min < max, got $min >= $max')
} }
@ -578,7 +578,7 @@ pub fn (fs FlagParser) usage() string {
// find_existing_flag looks up the given flag by name, and returns // find_existing_flag looks up the given flag by name, and returns
// it, if it was found in the FlagParser. If it was not, it returns an error. // it, if it was found in the FlagParser. If it was not, it returns an error.
fn (mut fs FlagParser) find_existing_flag(fname string) ?Flag { fn (mut fs FlagParser) find_existing_flag(fname string) !Flag {
for f in fs.flags { for f in fs.flags {
if f.name == fname { if f.name == fname {
return f return f
@ -614,7 +614,7 @@ fn (mut fs FlagParser) handle_builtin_options() {
// The remaining arguments are returned in the same order they are // The remaining arguments are returned in the same order they are
// defined on the command line. If additional flags are found, i.e. // defined on the command line. If additional flags are found, i.e.
// (things starting with '--' or '-'), it returns an error. // (things starting with '--' or '-'), it returns an error.
pub fn (mut fs FlagParser) finalize() ?[]string { pub fn (mut fs FlagParser) finalize() ![]string {
fs.handle_builtin_options() fs.handle_builtin_options()
mut remaining := fs.args.clone() mut remaining := fs.args.clone()
if !fs.allow_unknown_args { if !fs.allow_unknown_args {

View File

@ -153,9 +153,9 @@ fn test_finalize_returns_error_for_unknown_flags_short() {
assert finalized.len < 0 // expect error to be returned assert finalized.len < 0 // expect error to be returned
} }
fn test_allow_to_build_usage_message() ? { fn test_allow_to_build_usage_message() {
mut fp := flag.new_flag_parser([]) mut fp := flag.new_flag_parser([])
fp.limit_free_args(1, 4)? fp.limit_free_args(1, 4)!
fp.application('flag_tool') fp.application('flag_tool')
fp.version('v0.0.0') fp.version('v0.0.0')
fp.description('some short information about this tool') fp.description('some short information about this tool')
@ -194,9 +194,9 @@ fn test_if_no_options_given_usage_message_does_not_contain_options() {
assert !fp.usage().contains('Options:') assert !fp.usage().contains('Options:')
} }
fn test_free_args_could_be_limited() ? { fn test_free_args_could_be_limited() {
mut fp1 := flag.new_flag_parser(['a', 'b', 'c']) mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
fp1.limit_free_args(1, 4)? fp1.limit_free_args(1, 4)!
args := fp1.finalize() or { args := fp1.finalize() or {
assert false assert false
return return
@ -206,9 +206,9 @@ fn test_free_args_could_be_limited() ? {
assert args[2] == 'c' assert args[2] == 'c'
} }
fn test_error_for_to_few_free_args() ? { fn test_error_for_to_few_free_args() {
mut fp1 := flag.new_flag_parser(['a', 'b', 'c']) mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
fp1.limit_free_args(5, 6)? fp1.limit_free_args(5, 6)!
args := fp1.finalize() or { args := fp1.finalize() or {
assert err.msg().starts_with('Expected at least 5 arguments') assert err.msg().starts_with('Expected at least 5 arguments')
return return
@ -216,9 +216,9 @@ fn test_error_for_to_few_free_args() ? {
assert args.len < 0 // expect an error and need to use args assert args.len < 0 // expect an error and need to use args
} }
fn test_error_for_to_much_free_args() ? { fn test_error_for_to_much_free_args() {
mut fp1 := flag.new_flag_parser(['a', 'b', 'c']) mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
fp1.limit_free_args(1, 2)? fp1.limit_free_args(1, 2)!
args := fp1.finalize() or { args := fp1.finalize() or {
assert err.msg().starts_with('Expected at most 2 arguments') assert err.msg().starts_with('Expected at most 2 arguments')
return return
@ -226,9 +226,9 @@ fn test_error_for_to_much_free_args() ? {
assert args.len < 0 // expect an error and need to use args assert args.len < 0 // expect an error and need to use args
} }
fn test_could_expect_no_free_args() ? { fn test_could_expect_no_free_args() {
mut fp1 := flag.new_flag_parser(['a']) mut fp1 := flag.new_flag_parser(['a'])
fp1.limit_free_args(0, 0)? fp1.limit_free_args(0, 0)!
args := fp1.finalize() or { args := fp1.finalize() or {
assert err.msg().starts_with('Expected no arguments') assert err.msg().starts_with('Expected no arguments')
return return
@ -383,7 +383,7 @@ fn test_optional_flags() {
assert b == 'some_default_value' assert b == 'some_default_value'
} }
fn test_dashdash_acts_as_parser_full_stop() ? { fn test_dashdash_acts_as_parser_full_stop() {
mut fp := flag.new_flag_parser(['-b', '5', '--', '-d', '-x', '-b', '4', '-a', '-c', 'hello', mut fp := flag.new_flag_parser(['-b', '5', '--', '-d', '-x', '-b', '4', '-a', '-c', 'hello',
'some', 'other', 'parameters']) 'some', 'other', 'parameters'])
a := fp.bool_opt('a-bool-flag', `a`, '') or { false } a := fp.bool_opt('a-bool-flag', `a`, '') or { false }
@ -392,17 +392,17 @@ fn test_dashdash_acts_as_parser_full_stop() ? {
assert a == false assert a == false
assert b == 5 assert b == 5
assert c == 'default' assert c == 'default'
args := fp.finalize()? args := fp.finalize()!
assert args.len > 0 assert args.len > 0
assert args[0] != '--' assert args[0] != '--'
assert args == ['-d', '-x', '-b', '4', '-a', '-c', 'hello', 'some', 'other', 'parameters'] assert args == ['-d', '-x', '-b', '4', '-a', '-c', 'hello', 'some', 'other', 'parameters']
} }
fn test_dashdash_acts_as_parser_full_stop_dashdash_at_end() ? { fn test_dashdash_acts_as_parser_full_stop_dashdash_at_end() {
mut fp := flag.new_flag_parser(['-b', '5', '-b', '4', 'other', 'params', '--']) mut fp := flag.new_flag_parser(['-b', '5', '-b', '4', 'other', 'params', '--'])
b := fp.int_multi('an-int-flag', `b`, '') b := fp.int_multi('an-int-flag', `b`, '')
assert b == [5, 4] assert b == [5, 4]
args := fp.finalize()? args := fp.finalize()!
assert args.len > 0 assert args.len > 0
} }

View File

@ -107,9 +107,9 @@ pub fn (r BufferedReader) end_of_stream() bool {
// read_line attempts to read a line from the buffered reader // read_line attempts to read a line from the buffered reader
// it will read until it finds a new line character (\n) or // it will read until it finds a new line character (\n) or
// the end of stream // the end of stream
pub fn (mut r BufferedReader) read_line() ?string { pub fn (mut r BufferedReader) read_line() !string {
if r.end_of_stream { if r.end_of_stream {
return none return error('none')
} }
mut line := []u8{} mut line := []u8{}
for { for {
@ -119,7 +119,7 @@ pub fn (mut r BufferedReader) read_line() ?string {
// We are at the end of the stream // We are at the end of the stream
if line.len == 0 { if line.len == 0 {
// we had nothing so return nothing // we had nothing so return nothing
return none return error('none')
} }
return line.bytestr() return line.bytestr()
} }
@ -144,5 +144,5 @@ pub fn (mut r BufferedReader) read_line() ?string {
line << r.buf[r.offset..i] line << r.buf[r.offset..i]
r.offset = i r.offset = i
} }
return none return error('none')
} }

View File

@ -4,7 +4,7 @@ const (
buf_max_len = 1024 buf_max_len = 1024
) )
pub fn cp(mut src Reader, mut dst Writer) ? { pub fn cp(mut src Reader, mut dst Writer) ! {
mut buf := []u8{len: io.buf_max_len} mut buf := []u8{len: io.buf_max_len}
for { for {
len := src.read(mut buf) or { break } len := src.read(mut buf) or { break }

View File

@ -1,13 +1,13 @@
import io import io
import os import os
fn test_cp() ? { fn test_cp() {
mut f := os.open(@FILE) or { panic(err) } mut f := os.open(@FILE) or { panic(err) }
defer { defer {
f.close() f.close()
} }
mut r := io.new_buffered_reader(reader: f) mut r := io.new_buffered_reader(reader: f)
mut stdout := os.stdout() mut stdout := os.stdout()
io.cp(mut r, mut stdout)? io.cp(mut r, mut stdout)!
assert true assert true
} }

View File

@ -21,9 +21,9 @@ fn (mut b Buf) read(mut buf []u8) !int {
return n return n
} }
fn (mut w Writ) write(buf []u8) ?int { fn (mut w Writ) write(buf []u8) !int {
if buf.len <= 0 { if buf.len <= 0 {
return none return error('none')
} }
w.bytes << buf w.bytes << buf
return buf.len return buf.len

View File

@ -22,9 +22,9 @@ pub mut:
// written. If any writer fails to write the full length an error is returned // written. If any writer fails to write the full length an error is returned
// and writing to other writers stops. If any writer returns an error the error // and writing to other writers stops. If any writer returns an error the error
// is returned immediately and writing to other writers stops. // is returned immediately and writing to other writers stops.
pub fn (mut m MultiWriter) write(buf []u8) ?int { pub fn (mut m MultiWriter) write(buf []u8) !int {
for mut w in m.writers { for mut w in m.writers {
n := w.write(buf)? n := w.write(buf)!
if n != buf.len { if n != buf.len {
return error('io: incomplete write to writer of MultiWriter') return error('io: incomplete write to writer of MultiWriter')
} }

View File

@ -43,7 +43,7 @@ pub mut:
bytes []u8 bytes []u8
} }
fn (mut w TestWriter) write(buf []u8) ?int { fn (mut w TestWriter) write(buf []u8) !int {
w.bytes << buf w.bytes << buf
return buf.len return buf.len
} }
@ -53,7 +53,7 @@ pub mut:
bytes []u8 bytes []u8
} }
fn (mut w TestIncompleteWriter) write(buf []u8) ?int { fn (mut w TestIncompleteWriter) write(buf []u8) !int {
b := buf[..buf.len - 1] b := buf[..buf.len - 1]
w.bytes << b w.bytes << b
return b.len return b.len
@ -61,6 +61,6 @@ fn (mut w TestIncompleteWriter) write(buf []u8) ?int {
struct TestErrorWriter {} struct TestErrorWriter {}
fn (mut w TestErrorWriter) write(buf []u8) ?int { fn (mut w TestErrorWriter) write(buf []u8) !int {
return error('error writer errored') return error('error writer errored')
} }

View File

@ -44,7 +44,7 @@ mut:
// read_all reads all bytes from a reader until either a 0 length read // read_all reads all bytes from a reader until either a 0 length read
// or if read_to_end_of_stream is true then the end of the stream (`none`) // or if read_to_end_of_stream is true then the end of the stream (`none`)
pub fn read_all(config ReadAllConfig) ?[]u8 { pub fn read_all(config ReadAllConfig) ![]u8 {
mut r := config.reader mut r := config.reader
read_till_eof := config.read_to_end_of_stream read_till_eof := config.read_to_end_of_stream
@ -65,11 +65,11 @@ pub fn read_all(config ReadAllConfig) ?[]u8 {
// read_any reads any available bytes from a reader // read_any reads any available bytes from a reader
// (until the reader returns a read of 0 length) // (until the reader returns a read of 0 length)
pub fn read_any(mut r Reader) ?[]u8 { pub fn read_any(mut r Reader) ![]u8 {
mut b := []u8{len: io.read_all_len} mut b := []u8{len: io.read_all_len}
mut read := 0 mut read := 0
for { for {
new_read := r.read(mut b[read..]) or { return none } new_read := r.read(mut b[read..]) or { return error('none') }
read += new_read read += new_read
if new_read == 0 { if new_read == 0 {
break break
@ -83,5 +83,5 @@ pub fn read_any(mut r Reader) ?[]u8 {
// RandomReader represents a stream of data that can be read from at a random location // RandomReader represents a stream of data that can be read from at a random location
pub interface RandomReader { pub interface RandomReader {
read_from(pos u64, mut buf []u8) ?int read_from(pos u64, mut buf []u8) !int
} }

View File

@ -18,7 +18,7 @@ pub fn (mut r ReaderWriterImpl) read(mut buf []u8) !int {
return r.r.read(mut buf) return r.r.read(mut buf)
} }
pub fn (mut r ReaderWriterImpl) write(buf []u8) ?int { pub fn (mut r ReaderWriterImpl) write(buf []u8) !int {
return r.w.write(buf) return r.w.write(buf)
} }

View File

@ -14,7 +14,7 @@ pub struct TempFileOptions {
} }
// temp_file returns an uniquely named, open, writable, `os.File` and it's path // temp_file returns an uniquely named, open, writable, `os.File` and it's path
pub fn temp_file(tfo TempFileOptions) ?(os.File, string) { pub fn temp_file(tfo TempFileOptions) !(os.File, string) {
mut d := tfo.path mut d := tfo.path
if d == '' { if d == '' {
d = os.temp_dir() d = os.temp_dir()
@ -47,7 +47,7 @@ pub struct TempDirOptions {
} }
// temp_dir returns an uniquely named, writable, directory path // temp_dir returns an uniquely named, writable, directory path
pub fn temp_dir(tdo TempFileOptions) ?string { pub fn temp_dir(tdo TempFileOptions) !string {
mut d := tdo.path mut d := tdo.path
if d == '' { if d == '' {
d = os.temp_dir() d = os.temp_dir()

View File

@ -3,11 +3,11 @@ module io
// Writer represents a stream of data that can be wrote to // Writer represents a stream of data that can be wrote to
pub interface Writer { pub interface Writer {
mut: mut:
write(buf []u8) ?int write(buf []u8) !int
} }
// RandomWriter represents a stream of data that can be wrote to // RandomWriter represents a stream of data that can be wrote to
// at a random pos // at a random pos
pub interface RandomWriter { pub interface RandomWriter {
write_to(pos u64, buf []u8) ?int write_to(pos u64, buf []u8) !int
} }

View File

@ -44,15 +44,15 @@ fn new_ip(port u16, addr [4]u8) Addr {
return a return a
} }
fn temp_unix() ?Addr { fn temp_unix() !Addr {
// create a temp file to get a filename // create a temp file to get a filename
// close it // close it
// remove it // remove it
// then reuse the filename // then reuse the filename
mut file, filename := util.temp_file()? mut file, filename := util.temp_file()!
file.close() file.close()
os.rm(filename)? os.rm(filename)!
addrs := resolve_addrs(filename, .unix, .udp)? addrs := resolve_addrs(filename, .unix, .udp)!
return addrs[0] return addrs[0]
} }
@ -114,7 +114,7 @@ fn (a Addr) len() u32 {
} }
} }
pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ?[]Addr { pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ![]Addr {
match family { match family {
.ip, .ip6, .unspec { .ip, .ip6, .unspec {
return resolve_ipaddrs(addr, family, @type) return resolve_ipaddrs(addr, family, @type)
@ -143,9 +143,9 @@ pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ?[]Addr {
} }
} }
pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ?[]Addr { pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ![]Addr {
if addr.len == 0 { if addr.len == 0 {
return none return error('none')
} }
// Use a small heuristic to figure out what address family this is // Use a small heuristic to figure out what address family this is
@ -160,8 +160,8 @@ pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ?[]Addr {
return resolve_addrs(addr, .unix, @type) return resolve_addrs(addr, .unix, @type)
} }
pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ?[]Addr { pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr {
address, port := split_address(addr)? address, port := split_address(addr)!
if addr[0] == `:` { if addr[0] == `:` {
match family { match family {
@ -191,10 +191,10 @@ pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ?[]Addr {
// This might look silly but is recommended by MSDN // This might look silly but is recommended by MSDN
$if windows { $if windows {
socket_error(0 - C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results))? socket_error(0 - C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results))!
} $else { } $else {
x := C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results) x := C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results)
wrap_error(x)? wrap_error(x)!
} }
defer { defer {

View File

@ -17,18 +17,18 @@ pub const no_timeout = time.Duration(0)
pub const infinite_timeout = time.infinite pub const infinite_timeout = time.infinite
// Shutdown shutsdown a socket and closes it // Shutdown shutsdown a socket and closes it
fn shutdown(handle int) ? { fn shutdown(handle int) ! {
$if windows { $if windows {
C.shutdown(handle, C.SD_BOTH) C.shutdown(handle, C.SD_BOTH)
socket_error(C.closesocket(handle))? socket_error(C.closesocket(handle))!
} $else { } $else {
C.shutdown(handle, C.SHUT_RDWR) C.shutdown(handle, C.SHUT_RDWR)
socket_error(C.close(handle))? socket_error(C.close(handle))!
} }
} }
// Select waits for an io operation (specified by parameter `test`) to be available // Select waits for an io operation (specified by parameter `test`) to be available
fn @select(handle int, test Select, timeout time.Duration) ?bool { fn @select(handle int, test Select, timeout time.Duration) !bool {
set := C.fd_set{} set := C.fd_set{}
C.FD_ZERO(&set) C.FD_ZERO(&set)
@ -52,13 +52,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
match test { match test {
.read { .read {
socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))? socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
} }
.write { .write {
socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))? socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
} }
.except { .except {
socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))? socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
} }
} }
@ -66,7 +66,7 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
} }
[inline] [inline]
fn select_deadline(handle int, test Select, deadline time.Time) ?bool { fn select_deadline(handle int, test Select, deadline time.Time) !bool {
// if we have a 0 deadline here then the timeout that was passed was infinite... // if we have a 0 deadline here then the timeout that was passed was infinite...
infinite := deadline.unix_time() == 0 infinite := deadline.unix_time() == 0
for infinite || time.now() <= deadline { for infinite || time.now() <= deadline {
@ -89,7 +89,7 @@ fn select_deadline(handle int, test Select, deadline time.Time) ?bool {
} }
// wait_for_common wraps the common wait code // wait_for_common wraps the common wait code
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ! {
// Convert timeouts to deadlines // Convert timeouts to deadlines
real_deadline := if timeout == net.infinite_timeout { real_deadline := if timeout == net.infinite_timeout {
time.unix(0) time.unix(0)
@ -104,7 +104,7 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
time.now().add(timeout) time.now().add(timeout)
} }
ready := select_deadline(handle, test, real_deadline)? ready := select_deadline(handle, test, real_deadline)!
if ready { if ready {
return return
@ -114,11 +114,11 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
} }
// wait_for_write waits for a write io operation to be available // wait_for_write waits for a write io operation to be available
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? { fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ! {
return wait_for_common(handle, deadline, timeout, .write) return wait_for_common(handle, deadline, timeout, .write)
} }
// wait_for_read waits for a read io operation to be available // wait_for_read waits for a read io operation to be available
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? { fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ! {
return wait_for_common(handle, deadline, timeout, .read) return wait_for_common(handle, deadline, timeout, .read)
} }

View File

@ -21,11 +21,11 @@ pub const (
err_connection_refused = error_with_code('net: connection refused', errors_base + 10) err_connection_refused = error_with_code('net: connection refused', errors_base + 10)
) )
pub fn socket_error_message(potential_code int, s string) ?int { pub fn socket_error_message(potential_code int, s string) !int {
return socket_error(potential_code) or { return error('$err.msg(); $s') } return socket_error(potential_code) or { return error('$err.msg(); $s') }
} }
pub fn socket_error(potential_code int) ?int { pub fn socket_error(potential_code int) !int {
$if windows { $if windows {
if potential_code < 0 { if potential_code < 0 {
last_error_int := C.WSAGetLastError() last_error_int := C.WSAGetLastError()
@ -43,7 +43,7 @@ pub fn socket_error(potential_code int) ?int {
return potential_code return potential_code
} }
pub fn wrap_error(error_code int) ? { pub fn wrap_error(error_code int) ! {
if error_code == 0 { if error_code == 0 {
return return
} }
@ -59,17 +59,17 @@ pub fn wrap_error(error_code int) ? {
// connection termination and returns none // connection termination and returns none
// e.g. res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))? // e.g. res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
[inline] [inline]
fn wrap_read_result(result int) ?int { fn wrap_read_result(result int) !int {
if result == 0 { if result == 0 {
return none return error('none')
} }
return result return result
} }
[inline] [inline]
fn wrap_write_result(result int) ?int { fn wrap_write_result(result int) !int {
if result == 0 { if result == 0 {
return none return error('none')
} }
return result return result
} }

View File

@ -42,7 +42,7 @@ mut:
port int port int
} }
fn (mut dtp DTP) read() ?[]u8 { fn (mut dtp DTP) read() ![]u8 {
mut data := []u8{} mut data := []u8{}
mut buf := []u8{len: 1024} mut buf := []u8{len: 1024}
for { for {
@ -75,15 +75,15 @@ pub fn new() FTP {
return f return f
} }
fn (mut zftp FTP) write(data string) ?int { fn (mut zftp FTP) write(data string) !int {
$if debug { $if debug {
println('FTP.v >>> $data') println('FTP.v >>> $data')
} }
return zftp.conn.write('$data\r\n'.bytes()) return zftp.conn.write('$data\r\n'.bytes())
} }
fn (mut zftp FTP) read() ?(int, string) { fn (mut zftp FTP) read() !(int, string) {
mut data := zftp.reader.read_line()? mut data := zftp.reader.read_line()!
$if debug { $if debug {
println('FTP.v <<< $data') println('FTP.v <<< $data')
} }
@ -93,7 +93,7 @@ fn (mut zftp FTP) read() ?(int, string) {
code := data[..3].int() code := data[..3].int()
if data[3] == `-` { if data[3] == `-` {
for { for {
data = zftp.reader.read_line()? data = zftp.reader.read_line()!
if data[..3].int() == code && data[3] != `-` { if data[..3].int() == code && data[3] != `-` {
break break
} }
@ -103,10 +103,10 @@ fn (mut zftp FTP) read() ?(int, string) {
} }
// connect establishes an FTP connection to the host at `ip` port 21. // connect establishes an FTP connection to the host at `ip` port 21.
pub fn (mut zftp FTP) connect(ip string) ?bool { pub fn (mut zftp FTP) connect(ip string) !bool {
zftp.conn = net.dial_tcp('$ip:21')? zftp.conn = net.dial_tcp('$ip:21')!
zftp.reader = io.new_buffered_reader(reader: zftp.conn) zftp.reader = io.new_buffered_reader(reader: zftp.conn)
code, _ := zftp.read()? code, _ := zftp.read()!
if code == ftp.connected { if code == ftp.connected {
return true return true
} }
@ -114,14 +114,14 @@ pub fn (mut zftp FTP) connect(ip string) ?bool {
} }
// login sends the "USER `user`" and "PASS `passwd`" commands to the remote host. // login sends the "USER `user`" and "PASS `passwd`" commands to the remote host.
pub fn (mut zftp FTP) login(user string, passwd string) ?bool { pub fn (mut zftp FTP) login(user string, passwd string) !bool {
zftp.write('USER $user') or { zftp.write('USER $user') or {
$if debug { $if debug {
println('ERROR sending user') println('ERROR sending user')
} }
return false return false
} }
mut code, _ := zftp.read()? mut code, _ := zftp.read()!
if code == ftp.logged_in { if code == ftp.logged_in {
return true return true
} }
@ -134,7 +134,7 @@ pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
} }
return false return false
} }
code, _ = zftp.read()? code, _ = zftp.read()!
if code == ftp.logged_in { if code == ftp.logged_in {
return true return true
} }
@ -142,15 +142,15 @@ pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
} }
// close closes the FTP connection. // close closes the FTP connection.
pub fn (mut zftp FTP) close() ? { pub fn (mut zftp FTP) close() ! {
zftp.write('QUIT')? zftp.write('QUIT')!
zftp.conn.close()? zftp.conn.close()!
} }
// pwd returns the current working directory on the remote host for the logged in user. // pwd returns the current working directory on the remote host for the logged in user.
pub fn (mut zftp FTP) pwd() ?string { pub fn (mut zftp FTP) pwd() !string {
zftp.write('PWD')? zftp.write('PWD')!
_, data := zftp.read()? _, data := zftp.read()!
spl := data.split('"') // " spl := data.split('"') // "
if spl.len >= 2 { if spl.len >= 2 {
return spl[1] return spl[1]
@ -159,9 +159,9 @@ pub fn (mut zftp FTP) pwd() ?string {
} }
// cd changes the current working directory to the specified remote directory `dir`. // cd changes the current working directory to the specified remote directory `dir`.
pub fn (mut zftp FTP) cd(dir string) ? { pub fn (mut zftp FTP) cd(dir string) ! {
zftp.write('CWD $dir') or { return } zftp.write('CWD $dir') or { return }
mut code, mut data := zftp.read()? mut code, mut data := zftp.read()!
match int(code) { match int(code) {
ftp.denied { ftp.denied {
$if debug { $if debug {
@ -169,7 +169,7 @@ pub fn (mut zftp FTP) cd(dir string) ? {
} }
} }
ftp.complete { ftp.complete {
code, data = zftp.read()? code, data = zftp.read()!
} }
else {} else {}
} }
@ -178,7 +178,7 @@ pub fn (mut zftp FTP) cd(dir string) ? {
} }
} }
fn new_dtp(msg string) ?&DTP { fn new_dtp(msg string) !&DTP {
if !is_dtp_message_valid(msg) { if !is_dtp_message_valid(msg) {
return error('Bad message') return error('Bad message')
} }
@ -194,32 +194,32 @@ fn new_dtp(msg string) ?&DTP {
return dtp return dtp
} }
fn (mut zftp FTP) pasv() ?&DTP { fn (mut zftp FTP) pasv() !&DTP {
zftp.write('PASV')? zftp.write('PASV')!
code, data := zftp.read()? code, data := zftp.read()!
$if debug { $if debug {
println('pass: $data') println('pass: $data')
} }
if code != ftp.passive_mode { if code != ftp.passive_mode {
return error('pasive mode not allowed') return error('pasive mode not allowed')
} }
dtp := new_dtp(data)? dtp := new_dtp(data)!
return dtp return dtp
} }
// dir returns a list of the files in the current working directory. // dir returns a list of the files in the current working directory.
pub fn (mut zftp FTP) dir() ?[]string { pub fn (mut zftp FTP) dir() ![]string {
mut dtp := zftp.pasv() or { return error('Cannot establish data connection') } mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
zftp.write('LIST')? zftp.write('LIST')!
code, _ := zftp.read()? code, _ := zftp.read()!
if code == ftp.denied { if code == ftp.denied {
return error('`LIST` denied') return error('`LIST` denied')
} }
if code != ftp.open_data_connection { if code != ftp.open_data_connection {
return error('Data channel empty') return error('Data channel empty')
} }
list_dir := dtp.read()? list_dir := dtp.read()!
result, _ := zftp.read()? result, _ := zftp.read()!
if result != ftp.close_data_connection { if result != ftp.close_data_connection {
println('`LIST` not ok') println('`LIST` not ok')
} }
@ -235,17 +235,17 @@ pub fn (mut zftp FTP) dir() ?[]string {
} }
// get retrieves `file` from the remote host. // get retrieves `file` from the remote host.
pub fn (mut zftp FTP) get(file string) ?[]u8 { pub fn (mut zftp FTP) get(file string) ![]u8 {
mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') } mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
zftp.write('RETR $file')? zftp.write('RETR $file')!
code, _ := zftp.read()? code, _ := zftp.read()!
if code == ftp.denied { if code == ftp.denied {
return error('Permission denied') return error('Permission denied')
} }
if code != ftp.open_data_connection { if code != ftp.open_data_connection {
return error('Data connection not ready') return error('Data connection not ready')
} }
blob := dtp.read()? blob := dtp.read()!
dtp.close() dtp.close()
return blob return blob
} }

View File

@ -11,17 +11,17 @@ fn test_ftp_cleint() {
ftp_client_test_inside() or { panic(err) } ftp_client_test_inside() or { panic(err) }
} }
fn ftp_client_test_inside() ? { fn ftp_client_test_inside() ! {
mut zftp := ftp.new() mut zftp := ftp.new()
// eprintln(zftp) // eprintln(zftp)
defer { defer {
zftp.close() or { panic(err) } zftp.close() or { panic(err) }
} }
connect_result := zftp.connect('ftp.redhat.com')? connect_result := zftp.connect('ftp.redhat.com')!
assert connect_result assert connect_result
login_result := zftp.login('ftp', 'ftp')? login_result := zftp.login('ftp', 'ftp')!
assert login_result assert login_result
pwd := zftp.pwd()? pwd := zftp.pwd()!
assert pwd.len > 0 assert pwd.len > 0
zftp.cd('/') or { zftp.cd('/') or {
assert false assert false

View File

@ -6,14 +6,14 @@ module http
import net.ssl import net.ssl
import strings import strings
fn (req &Request) ssl_do(port int, method Method, host_name string, path string) ?Response { fn (req &Request) ssl_do(port int, method Method, host_name string, path string) !Response {
mut ssl_conn := ssl.new_ssl_conn( mut ssl_conn := ssl.new_ssl_conn(
verify: req.verify verify: req.verify
cert: req.cert cert: req.cert
cert_key: req.cert_key cert_key: req.cert_key
validate: req.validate validate: req.validate
in_memory_verification: req.in_memory_verification in_memory_verification: req.in_memory_verification
)? )!
ssl_conn.dial(host_name, port) or { return err } ssl_conn.dial(host_name, port) or { return err }
req_headers := req.build_request_headers(method, host_name, path) req_headers := req.build_request_headers(method, host_name, path)
@ -38,7 +38,7 @@ fn (req &Request) ssl_do(port int, method Method, host_name string, path string)
} }
unsafe { content.write_ptr(bp, len) } unsafe { content.write_ptr(bp, len) }
} }
ssl_conn.shutdown()? ssl_conn.shutdown()!
response_text := content.str() response_text := content.str()
$if trace_http_response ? { $if trace_http_response ? {
eprintln('< $response_text') eprintln('< $response_text')

View File

@ -13,7 +13,7 @@ $if gcboehm ? {
fn C.new_tls_context() C.TlsContext fn C.new_tls_context() C.TlsContext
fn (req &Request) ssl_do(port int, method Method, host_name string, path string) ?Response { fn (req &Request) ssl_do(port int, method Method, host_name string, path string) !Response {
mut ctx := C.new_tls_context() mut ctx := C.new_tls_context()
C.vschannel_init(&ctx) C.vschannel_init(&ctx)
mut buff := unsafe { malloc_noscan(C.vsc_init_resp_buff_size) } mut buff := unsafe { malloc_noscan(C.vsc_init_resp_buff_size) }

View File

@ -294,7 +294,7 @@ pub fn is_cookie_domain_name(_s string) bool {
return ok return ok
} }
fn parse_cookie_value(_raw string, allow_double_quote bool) ?string { fn parse_cookie_value(_raw string, allow_double_quote bool) !string {
mut raw := _raw mut raw := _raw
// Strip the quotes, if present // Strip the quotes, if present
if allow_double_quote && raw.len > 1 && raw[0] == `"` && raw[raw.len - 1] == `"` { if allow_double_quote && raw.len > 1 && raw[0] == `"` && raw[raw.len - 1] == `"` {
@ -320,7 +320,7 @@ fn is_cookie_name_valid(name string) bool {
return true return true
} }
fn parse_cookie(line string) ?Cookie { fn parse_cookie(line string) !Cookie {
mut parts := line.trim_space().split(';') mut parts := line.trim_space().split(';')
if parts.len == 1 && parts[0] == '' { if parts.len == 1 && parts[0] == '' {
return error('malformed cookie') return error('malformed cookie')

View File

@ -7,7 +7,7 @@ import os
// download_file retrieves a document from the URL `url`, // download_file retrieves a document from the URL `url`,
// and saves it in the output file path `out_file_path`. // and saves it in the output file path `out_file_path`.
pub fn download_file(url string, out_file_path string) ? { pub fn download_file(url string, out_file_path string) ! {
$if debug_http ? { $if debug_http ? {
println('http.download_file url=$url out_file_path=$out_file_path') println('http.download_file url=$url out_file_path=$out_file_path')
} }
@ -18,7 +18,7 @@ pub fn download_file(url string, out_file_path string) ? {
$if debug_http ? { $if debug_http ? {
println('http.download_file saving $s.body.len bytes') println('http.download_file saving $s.body.len bytes')
} }
os.write_file(out_file_path, s.body)? os.write_file(out_file_path, s.body)!
} }
// TODO: implement download_file_with_progress // TODO: implement download_file_with_progress

View File

@ -363,9 +363,9 @@ pub fn new_header_from_map(kvs map[CommonHeader]string) Header {
} }
// new_custom_header_from_map creates a Header from string key value pairs // new_custom_header_from_map creates a Header from string key value pairs
pub fn new_custom_header_from_map(kvs map[string]string) ?Header { pub fn new_custom_header_from_map(kvs map[string]string) !Header {
mut h := new_header() mut h := new_header()
h.add_custom_map(kvs)? h.add_custom_map(kvs)!
return h return h
} }
@ -378,8 +378,8 @@ pub fn (mut h Header) add(key CommonHeader, value string) {
// add_custom appends a value to a custom header key. This function will // add_custom appends a value to a custom header key. This function will
// return an error if the key contains invalid header characters. // return an error if the key contains invalid header characters.
pub fn (mut h Header) add_custom(key string, value string) ? { pub fn (mut h Header) add_custom(key string, value string) ! {
is_valid(key)? is_valid(key)!
h.data[key] << value h.data[key] << value
h.add_key(key) h.add_key(key)
} }
@ -392,9 +392,9 @@ pub fn (mut h Header) add_map(kvs map[CommonHeader]string) {
} }
// add_custom_map appends the value for each custom header key. // add_custom_map appends the value for each custom header key.
pub fn (mut h Header) add_custom_map(kvs map[string]string) ? { pub fn (mut h Header) add_custom_map(kvs map[string]string) ! {
for k, v in kvs { for k, v in kvs {
h.add_custom(k, v)? h.add_custom(k, v)!
} }
} }
@ -410,8 +410,8 @@ pub fn (mut h Header) set(key CommonHeader, value string) {
// function will clear any other values that exist for the header. This // function will clear any other values that exist for the header. This
// function will return an error if the key contains invalid header // function will return an error if the key contains invalid header
// characters. // characters.
pub fn (mut h Header) set_custom(key string, value string) ? { pub fn (mut h Header) set_custom(key string, value string) ! {
is_valid(key)? is_valid(key)!
h.data[key] = [value] h.data[key] = [value]
h.add_key(key) h.add_key(key)
} }
@ -479,37 +479,37 @@ pub fn (h Header) contains_custom(key string, flags HeaderQueryConfig) bool {
// get gets the first value for the CommonHeader, or none if the key // get gets the first value for the CommonHeader, or none if the key
// does not exist. // does not exist.
pub fn (h Header) get(key CommonHeader) ?string { pub fn (h Header) get(key CommonHeader) !string {
return h.get_custom(key.str()) return h.get_custom(key.str())
} }
// get_custom gets the first value for the custom header, or none if // get_custom gets the first value for the custom header, or none if
// the key does not exist. // the key does not exist.
pub fn (h Header) get_custom(key string, flags HeaderQueryConfig) ?string { pub fn (h Header) get_custom(key string, flags HeaderQueryConfig) !string {
mut data_key := key mut data_key := key
if !flags.exact { if !flags.exact {
// get the first key from key metadata // get the first key from key metadata
k := key.to_lower() k := key.to_lower()
if h.keys[k].len == 0 { if h.keys[k].len == 0 {
return none return error('none')
} }
data_key = h.keys[k][0] data_key = h.keys[k][0]
} }
if h.data[data_key].len == 0 { if h.data[data_key].len == 0 {
return none return error('none')
} }
return h.data[data_key][0] return h.data[data_key][0]
} }
// starting_with gets the first header starting with key, or none if // starting_with gets the first header starting with key, or none if
// the key does not exist. // the key does not exist.
pub fn (h Header) starting_with(key string) ?string { pub fn (h Header) starting_with(key string) !string {
for k, _ in h.data { for k, _ in h.data {
if k.starts_with(key) { if k.starts_with(key) {
return k return k
} }
} }
return none return error('none')
} }
// values gets all values for the CommonHeader. // values gets all values for the CommonHeader.
@ -642,7 +642,7 @@ pub fn (err HeaderKeyError) code() int {
} }
// is_valid checks if the header token contains all valid bytes // is_valid checks if the header token contains all valid bytes
fn is_valid(header string) ? { fn is_valid(header string) ! {
for _, c in header { for _, c in header {
if int(c) >= 128 || !is_token(c) { if int(c) >= 128 || !is_token(c) {
return IError(HeaderKeyError{ return IError(HeaderKeyError{
@ -676,7 +676,7 @@ pub fn (h Header) str() string {
} }
// parse_headers parses a newline delimited string into a Header struct // parse_headers parses a newline delimited string into a Header struct
fn parse_headers(s string) ?Header { fn parse_headers(s string) !Header {
mut h := new_header() mut h := new_header()
mut last_key := '' mut last_key := ''
mut last_value := '' mut last_value := ''
@ -689,15 +689,15 @@ fn parse_headers(s string) ?Header {
last_value += ' ${line.trim(' \t')}' last_value += ' ${line.trim(' \t')}'
continue continue
} else if last_key != '' { } else if last_key != '' {
h.add_custom(last_key, last_value)? h.add_custom(last_key, last_value)!
} }
last_key, last_value = parse_header(line)? last_key, last_value = parse_header(line)!
} }
h.add_custom(last_key, last_value)? h.add_custom(last_key, last_value)!
return h return h
} }
fn parse_header(s string) ?(string, string) { fn parse_header(s string) !(string, string) {
if !s.contains(':') { if !s.contains(':') {
return error('missing colon in header') return error('missing colon in header')
} }

View File

@ -31,7 +31,7 @@ pub mut:
allow_redirect bool = true // whether to allow redirect allow_redirect bool = true // whether to allow redirect
} }
pub fn new_request(method Method, url_ string, data string) ?Request { pub fn new_request(method Method, url_ string, data string) !Request {
url := if method == .get && !url_.contains('?') { url_ + '?' + data } else { url_ } url := if method == .get && !url_.contains('?') { url_ + '?' + data } else { url_ }
// println('new req() method=$method url="$url" dta="$data"') // println('new req() method=$method url="$url" dta="$data"')
return Request{ return Request{
@ -47,12 +47,12 @@ pub fn new_request(method Method, url_ string, data string) ?Request {
} }
// get sends a GET HTTP request to the URL // get sends a GET HTTP request to the URL
pub fn get(url string) ?Response { pub fn get(url string) !Response {
return fetch(method: .get, url: url) return fetch(method: .get, url: url)
} }
// post sends a POST HTTP request to the URL with a string data // post sends a POST HTTP request to the URL with a string data
pub fn post(url string, data string) ?Response { pub fn post(url string, data string) !Response {
return fetch( return fetch(
method: .post method: .post
url: url url: url
@ -62,7 +62,7 @@ pub fn post(url string, data string) ?Response {
} }
// post_json sends a POST HTTP request to the URL with a JSON data // post_json sends a POST HTTP request to the URL with a JSON data
pub fn post_json(url string, data string) ?Response { pub fn post_json(url string, data string) !Response {
return fetch( return fetch(
method: .post method: .post
url: url url: url
@ -72,7 +72,7 @@ pub fn post_json(url string, data string) ?Response {
} }
// post_form sends a POST HTTP request to the URL with X-WWW-FORM-URLENCODED data // post_form sends a POST HTTP request to the URL with X-WWW-FORM-URLENCODED data
pub fn post_form(url string, data map[string]string) ?Response { pub fn post_form(url string, data map[string]string) !Response {
return fetch( return fetch(
method: .post method: .post
url: url url: url
@ -90,7 +90,7 @@ pub mut:
} }
// post_multipart_form sends a POST HTTP request to the URL with multipart form data // post_multipart_form sends a POST HTTP request to the URL with multipart form data
pub fn post_multipart_form(url string, conf PostMultipartFormConfig) ?Response { pub fn post_multipart_form(url string, conf PostMultipartFormConfig) !Response {
body, boundary := multipart_form_body(conf.form, conf.files) body, boundary := multipart_form_body(conf.form, conf.files)
mut header := conf.header mut header := conf.header
header.set(.content_type, 'multipart/form-data; boundary="$boundary"') header.set(.content_type, 'multipart/form-data; boundary="$boundary"')
@ -103,7 +103,7 @@ pub fn post_multipart_form(url string, conf PostMultipartFormConfig) ?Response {
} }
// put sends a PUT HTTP request to the URL with a string data // put sends a PUT HTTP request to the URL with a string data
pub fn put(url string, data string) ?Response { pub fn put(url string, data string) !Response {
return fetch( return fetch(
method: .put method: .put
url: url url: url
@ -113,7 +113,7 @@ pub fn put(url string, data string) ?Response {
} }
// patch sends a PATCH HTTP request to the URL with a string data // patch sends a PATCH HTTP request to the URL with a string data
pub fn patch(url string, data string) ?Response { pub fn patch(url string, data string) !Response {
return fetch( return fetch(
method: .patch method: .patch
url: url url: url
@ -123,17 +123,17 @@ pub fn patch(url string, data string) ?Response {
} }
// head sends a HEAD HTTP request to the URL // head sends a HEAD HTTP request to the URL
pub fn head(url string) ?Response { pub fn head(url string) !Response {
return fetch(method: .head, url: url) return fetch(method: .head, url: url)
} }
// delete sends a DELETE HTTP request to the URL // delete sends a DELETE HTTP request to the URL
pub fn delete(url string) ?Response { pub fn delete(url string) !Response {
return fetch(method: .delete, url: url) return fetch(method: .delete, url: url)
} }
// fetch sends an HTTP request to the URL with the given method and configurations // fetch sends an HTTP request to the URL with the given method and configurations
pub fn fetch(config FetchConfig) ?Response { pub fn fetch(config FetchConfig) !Response {
if config.url == '' { if config.url == '' {
return error('http.fetch: empty url') return error('http.fetch: empty url')
} }
@ -154,7 +154,7 @@ pub fn fetch(config FetchConfig) ?Response {
in_memory_verification: config.in_memory_verification in_memory_verification: config.in_memory_verification
allow_redirect: config.allow_redirect allow_redirect: config.allow_redirect
} }
res := req.do()? res := req.do()!
return res return res
} }
@ -176,14 +176,14 @@ pub fn url_encode_form_data(data map[string]string) string {
} }
[deprecated: 'use fetch()'] [deprecated: 'use fetch()']
fn fetch_with_method(method Method, _config FetchConfig) ?Response { fn fetch_with_method(method Method, _config FetchConfig) !Response {
mut config := _config mut config := _config
config.method = method config.method = method
return fetch(config) return fetch(config)
} }
fn build_url_from_fetch(config FetchConfig) ?string { fn build_url_from_fetch(config FetchConfig) !string {
mut url := urllib.parse(config.url)? mut url := urllib.parse(config.url)!
if config.params.len == 0 { if config.params.len == 0 {
return url.str() return url.str()
} }

View File

@ -14,7 +14,7 @@ struct HttpbinResponseBody {
url string url string
} }
fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response { fn http_fetch_mock(_methods []string, _config FetchConfig) ![]Response {
url := 'https://httpbin.org/' url := 'https://httpbin.org/'
methods := if _methods.len == 0 { ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'] } else { _methods } methods := if _methods.len == 0 { ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'] } else { _methods }
mut config := _config mut config := _config
@ -23,7 +23,7 @@ fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
for method in methods { for method in methods {
lmethod := method.to_lower() lmethod := method.to_lower()
config.method = method_from_str(method) config.method = method_from_str(method)
res := fetch(FetchConfig{ ...config, url: url + lmethod })? res := fetch(FetchConfig{ ...config, url: url + lmethod })!
// TODO // TODO
// body := json.decode(HttpbinResponseBody,res.body)? // body := json.decode(HttpbinResponseBody,res.body)?
result << res result << res
@ -75,12 +75,12 @@ fn test_http_fetch_with_params() {
} }
} }
fn test_http_fetch_with_headers() ? { fn test_http_fetch_with_headers() ! {
$if !network ? { $if !network ? {
return return
} }
mut header := new_header() mut header := new_header()
header.add_custom('Test-Header', 'hello world')? header.add_custom('Test-Header', 'hello world')!
responses := http_fetch_mock([], responses := http_fetch_mock([],
header: header header: header
) or { panic(err) } ) or { panic(err) }

View File

@ -48,12 +48,12 @@ pub fn (mut req Request) add_header(key CommonHeader, val string) {
// add_custom_header adds the key and value of an HTTP request header // add_custom_header adds the key and value of an HTTP request header
// This method may fail if the key contains characters that are not permitted // This method may fail if the key contains characters that are not permitted
pub fn (mut req Request) add_custom_header(key string, val string) ? { pub fn (mut req Request) add_custom_header(key string, val string) ! {
return req.header.add_custom(key, val) return req.header.add_custom(key, val)
} }
// do will send the HTTP request and returns `http.Response` as soon as the response is recevied // do will send the HTTP request and returns `http.Response` as soon as the response is recevied
pub fn (req &Request) do() ?Response { pub fn (req &Request) do() !Response {
mut url := urllib.parse(req.url) or { return error('http.Request.do: invalid url $req.url') } mut url := urllib.parse(req.url) or { return error('http.Request.do: invalid url $req.url') }
mut rurl := url mut rurl := url
mut resp := Response{} mut resp := Response{}
@ -62,7 +62,7 @@ pub fn (req &Request) do() ?Response {
if no_redirects == max_redirects { if no_redirects == max_redirects {
return error('http.request.do: maximum number of redirects reached ($max_redirects)') return error('http.request.do: maximum number of redirects reached ($max_redirects)')
} }
qresp := req.method_and_url_to_response(req.method, rurl)? qresp := req.method_and_url_to_response(req.method, rurl)!
resp = qresp resp = qresp
if !req.allow_redirect { if !req.allow_redirect {
break break
@ -88,7 +88,7 @@ pub fn (req &Request) do() ?Response {
return resp return resp
} }
fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) ?Response { fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) !Response {
host_name := url.hostname() host_name := url.hostname()
scheme := url.scheme scheme := url.scheme
p := url.escaped_path().trim_left('/') p := url.escaped_path().trim_left('/')
@ -105,11 +105,11 @@ fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) ?Res
// println('fetch $method, $scheme, $host_name, $nport, $path ') // println('fetch $method, $scheme, $host_name, $nport, $path ')
if scheme == 'https' { if scheme == 'https' {
// println('ssl_do( $nport, $method, $host_name, $path )') // println('ssl_do( $nport, $method, $host_name, $path )')
res := req.ssl_do(nport, method, host_name, path)? res := req.ssl_do(nport, method, host_name, path)!
return res return res
} else if scheme == 'http' { } else if scheme == 'http' {
// println('http_do( $nport, $method, $host_name, $path )') // println('http_do( $nport, $method, $host_name, $path )')
res := req.http_do('$host_name:$nport', method, path)? res := req.http_do('$host_name:$nport', method, path)!
return res return res
} }
return error('http.request.method_and_url_to_response: unsupported scheme: "$scheme"') return error('http.request.method_and_url_to_response: unsupported scheme: "$scheme"')
@ -151,19 +151,19 @@ fn (req &Request) build_request_cookies_header() string {
return 'Cookie: ' + cookie.join('; ') + '\r\n' return 'Cookie: ' + cookie.join('; ') + '\r\n'
} }
fn (req &Request) http_do(host string, method Method, path string) ?Response { fn (req &Request) http_do(host string, method Method, path string) !Response {
host_name, _ := net.split_address(host)? host_name, _ := net.split_address(host)!
s := req.build_request_headers(method, host_name, path) s := req.build_request_headers(method, host_name, path)
mut client := net.dial_tcp(host)? mut client := net.dial_tcp(host)!
client.set_read_timeout(req.read_timeout) client.set_read_timeout(req.read_timeout)
client.set_write_timeout(req.write_timeout) client.set_write_timeout(req.write_timeout)
// TODO this really needs to be exposed somehow // TODO this really needs to be exposed somehow
client.write(s.bytes())? client.write(s.bytes())!
$if trace_http_request ? { $if trace_http_request ? {
eprintln('> $s') eprintln('> $s')
} }
mut bytes := io.read_all(reader: client)? mut bytes := io.read_all(reader: client)!
client.close()? client.close()!
response_text := bytes.bytestr() response_text := bytes.bytestr()
$if trace_http_response ? { $if trace_http_response ? {
eprintln('< $response_text') eprintln('< $response_text')
@ -178,8 +178,8 @@ pub fn (req &Request) referer() string {
// parse_request parses a raw HTTP request into a Request object. // parse_request parses a raw HTTP request into a Request object.
// See also: `parse_request_head`, which parses only the headers. // See also: `parse_request_head`, which parses only the headers.
pub fn parse_request(mut reader io.BufferedReader) ?Request { pub fn parse_request(mut reader io.BufferedReader) !Request {
mut request := parse_request_head(mut reader)? mut request := parse_request_head(mut reader)!
// body // body
mut body := []u8{} mut body := []u8{}
@ -199,18 +199,18 @@ pub fn parse_request(mut reader io.BufferedReader) ?Request {
} }
// parse_request_head parses *only* the header of a raw HTTP request into a Request object // parse_request_head parses *only* the header of a raw HTTP request into a Request object
pub fn parse_request_head(mut reader io.BufferedReader) ?Request { pub fn parse_request_head(mut reader io.BufferedReader) !Request {
// request line // request line
mut line := reader.read_line()? mut line := reader.read_line()!
method, target, version := parse_request_line(line)? method, target, version := parse_request_line(line)!
// headers // headers
mut header := new_header() mut header := new_header()
line = reader.read_line()? line = reader.read_line()!
for line != '' { for line != '' {
key, value := parse_header(line)? key, value := parse_header(line)!
header.add_custom(key, value)? header.add_custom(key, value)!
line = reader.read_line()? line = reader.read_line()!
} }
header.coerce(canonicalize: true) header.coerce(canonicalize: true)
@ -228,13 +228,13 @@ pub fn parse_request_head(mut reader io.BufferedReader) ?Request {
} }
} }
fn parse_request_line(s string) ?(Method, urllib.URL, Version) { fn parse_request_line(s string) !(Method, urllib.URL, Version) {
words := s.split(' ') words := s.split(' ')
if words.len != 3 { if words.len != 3 {
return error('malformed request line') return error('malformed request line')
} }
method := method_from_str(words[0]) method := method_from_str(words[0])
target := urllib.parse(words[1])? target := urllib.parse(words[1])!
version := version_from_str(words[2]) version := version_from_str(words[2])
if version == .unknown { if version == .unknown {
return error('unsupported version') return error('unsupported version')

View File

@ -178,7 +178,7 @@ fn test_parse_large_body() {
body := 'A'.repeat(101) // greater than max_bytes body := 'A'.repeat(101) // greater than max_bytes
req := 'GET / HTTP/1.1\r\nContent-Length: $body.len\r\n\r\n$body' req := 'GET / HTTP/1.1\r\nContent-Length: $body.len\r\n\r\n$body'
mut reader_ := reader(req) mut reader_ := reader(req)
result := parse_request(mut reader_)? result := parse_request(mut reader_)!
assert result.data.len == body.len assert result.data.len == body.len
assert result.data == body assert result.data == body
} }

View File

@ -35,11 +35,11 @@ pub fn (resp Response) bytestr() string {
} }
// Parse a raw HTTP response into a Response object // Parse a raw HTTP response into a Response object
pub fn parse_response(resp string) ?Response { pub fn parse_response(resp string) !Response {
version, status_code, status_msg := parse_status_line(resp.all_before('\n'))? version, status_code, status_msg := parse_status_line(resp.all_before('\n'))!
// Build resp header map and separate the body // Build resp header map and separate the body
start_idx, end_idx := find_headers_range(resp)? start_idx, end_idx := find_headers_range(resp)!
header := parse_headers(resp.substr(start_idx, end_idx))? header := parse_headers(resp.substr(start_idx, end_idx))!
mut body := resp.substr(end_idx, resp.len) mut body := resp.substr(end_idx, resp.len)
if header.get(.transfer_encoding) or { '' } == 'chunked' { if header.get(.transfer_encoding) or { '' } == 'chunked' {
body = chunked.decode(body) body = chunked.decode(body)
@ -56,7 +56,7 @@ pub fn parse_response(resp string) ?Response {
// parse_status_line parses the first HTTP response line into the HTTP // parse_status_line parses the first HTTP response line into the HTTP
// version, status code, and reason phrase // version, status code, and reason phrase
fn parse_status_line(line string) ?(string, int, string) { fn parse_status_line(line string) !(string, int, string) {
if line.len < 5 || line[..5].to_lower() != 'http/' { if line.len < 5 || line[..5].to_lower() != 'http/' {
return error('response does not start with HTTP/') return error('response does not start with HTTP/')
} }
@ -73,7 +73,7 @@ fn parse_status_line(line string) ?(string, int, string) {
for digit in digits { for digit in digits {
strconv.atoi(digit) or { return error('HTTP version must contain only integers') } strconv.atoi(digit) or { return error('HTTP version must contain only integers') }
} }
return version, strconv.atoi(data[1])?, data[2] return version, strconv.atoi(data[1])!, data[2]
} }
// cookies parses the Set-Cookie headers into Cookie objects // cookies parses the Set-Cookie headers into Cookie objects
@ -138,7 +138,7 @@ pub fn new_response(conf ResponseConfig) Response {
// index of the headers in the string, including the trailing newlines. This // index of the headers in the string, including the trailing newlines. This
// helper function expects the first line in `data` to be the HTTP status line // helper function expects the first line in `data` to be the HTTP status line
// (HTTP/1.1 200 OK). // (HTTP/1.1 200 OK).
fn find_headers_range(data string) ?(int, int) { fn find_headers_range(data string) !(int, int) {
start_idx := data.index('\n') or { return error('no start index found') } + 1 start_idx := data.index('\n') or { return error('no start index found') } + 1
mut count := 0 mut count := 0
for i := start_idx; i < data.len; i++ { for i := start_idx; i < data.len; i++ {

View File

@ -26,7 +26,7 @@ fn test_response_bytestr() {
// check_headers is a helper function for asserting all expected headers // check_headers is a helper function for asserting all expected headers
// are found because rendered header order is not guaranteed. The check // are found because rendered header order is not guaranteed. The check
// is O(n^2) which is fine for small lists. // is O(n^2) which is fine for small lists.
fn check_headers(expected []string, found []string) ? { fn check_headers(expected []string, found []string) ! {
assert expected.len == found.len assert expected.len == found.len
for header in expected { for header in expected {
if !found.contains(header) { if !found.contains(header) {

View File

@ -34,11 +34,14 @@ pub mut:
accept_timeout time.Duration = 30 * time.second accept_timeout time.Duration = 30 * time.second
} }
pub fn (mut s Server) listen_and_serve() ? { pub fn (mut s Server) listen_and_serve() {
if s.handler is DebugHandler { if s.handler is DebugHandler {
eprintln('Server handler not set, using debug handler') eprintln('Server handler not set, using debug handler')
} }
s.listener = net.listen_tcp(.ip6, ':$s.port')? s.listener = net.listen_tcp(.ip6, ':$s.port') or {
eprintln('Listening on :$s.port failed')
return
}
s.listener.set_accept_timeout(s.accept_timeout) s.listener.set_accept_timeout(s.accept_timeout)
eprintln('Listening on :$s.port') eprintln('Listening on :$s.port')
s.state = .running s.state = .running

View File

@ -11,7 +11,7 @@ fn test_server_stop() {
server.stop() server.stop()
assert server.status() == .stopped assert server.status() == .stopped
assert watch.elapsed() < 100 * time.millisecond assert watch.elapsed() < 100 * time.millisecond
t.wait()? t.wait()
assert watch.elapsed() < 999 * time.millisecond assert watch.elapsed() < 999 * time.millisecond
} }
@ -26,7 +26,7 @@ fn test_server_close() {
server.close() server.close()
assert server.status() == .closed assert server.status() == .closed
assert watch.elapsed() < 100 * time.millisecond assert watch.elapsed() < 100 * time.millisecond
t.wait()? t.wait()
assert watch.elapsed() < 999 * time.millisecond assert watch.elapsed() < 999 * time.millisecond
} }
@ -71,19 +71,19 @@ fn test_server_custom_handler() {
for server.status() != .running { for server.status() != .running {
time.sleep(10 * time.millisecond) time.sleep(10 * time.millisecond)
} }
x := http.fetch(url: 'http://localhost:$cport/endpoint?abc=xyz', data: 'my data')? x := http.fetch(url: 'http://localhost:$cport/endpoint?abc=xyz', data: 'my data')!
assert x.body == 'my data, /endpoint?abc=xyz' assert x.body == 'my data, /endpoint?abc=xyz'
assert x.status_code == 200 assert x.status_code == 200
assert x.http_version == '1.1' assert x.http_version == '1.1'
y := http.fetch(url: 'http://localhost:$cport/another/endpoint', data: 'abcde')? y := http.fetch(url: 'http://localhost:$cport/another/endpoint', data: 'abcde')!
assert y.body == 'abcde, /another/endpoint' assert y.body == 'abcde, /another/endpoint'
assert y.status_code == 200 assert y.status_code == 200
assert y.status() == .ok assert y.status() == .ok
assert y.http_version == '1.1' assert y.http_version == '1.1'
// //
http.fetch(url: 'http://localhost:$cport/something/else')? http.fetch(url: 'http://localhost:$cport/something/else')!
server.stop() server.stop()
t.wait()? t.wait()
assert handler.counter == 3 assert handler.counter == 3
assert handler.oks == 2 assert handler.oks == 2
assert handler.not_founds == 1 assert handler.not_founds == 1

View File

@ -52,7 +52,7 @@ pub struct SSLConnectConfig {
} }
// new_ssl_conn returns a new SSLConn with the given config. // new_ssl_conn returns a new SSLConn with the given config.
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn { pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
mut conn := &SSLConn{ mut conn := &SSLConn{
config: config config: config
} }
@ -68,7 +68,7 @@ enum Select {
} }
// shutdown terminates the ssl connection and does cleanup // shutdown terminates the ssl connection and does cleanup
pub fn (mut s SSLConn) shutdown() ? { pub fn (mut s SSLConn) shutdown() ! {
if !s.opened { if !s.opened {
return error('ssl connection not open') return error('ssl connection not open')
} }
@ -82,16 +82,16 @@ pub fn (mut s SSLConn) shutdown() ? {
if s.owns_socket { if s.owns_socket {
$if windows { $if windows {
C.shutdown(s.handle, C.SD_BOTH) C.shutdown(s.handle, C.SD_BOTH)
net.socket_error(C.closesocket(s.handle))? net.socket_error(C.closesocket(s.handle))!
} $else { } $else {
C.shutdown(s.handle, C.SHUT_RDWR) C.shutdown(s.handle, C.SHUT_RDWR)
net.socket_error(C.close(s.handle))? net.socket_error(C.close(s.handle))!
} }
} }
} }
// connect to server using mbedtls // connect to server using mbedtls
fn (mut s SSLConn) init() ? { fn (mut s SSLConn) init() ! {
C.mbedtls_net_init(&s.server_fd) C.mbedtls_net_init(&s.server_fd)
C.mbedtls_ssl_init(&s.ssl) C.mbedtls_ssl_init(&s.ssl)
C.mbedtls_ssl_config_init(&s.conf) C.mbedtls_ssl_config_init(&s.conf)
@ -157,7 +157,7 @@ fn (mut s SSLConn) init() ? {
} }
// connect sets up an ssl connection on an existing TCP connection // connect sets up an ssl connection on an existing TCP connection
pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? { pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ! {
if s.opened { if s.opened {
return error('ssl connection already open') return error('ssl connection already open')
} }
@ -183,7 +183,7 @@ pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? {
} }
// dial opens an ssl connection on hostname:port // dial opens an ssl connection on hostname:port
pub fn (mut s SSLConn) dial(hostname string, port int) ? { pub fn (mut s SSLConn) dial(hostname string, port int) ! {
s.owns_socket = true s.owns_socket = true
if s.opened { if s.opened {
return error('ssl connection already open') return error('ssl connection already open')
@ -216,7 +216,7 @@ pub fn (mut s SSLConn) dial(hostname string, port int) ? {
} }
// socket_read_into_ptr reads `len` bytes into `buf` // socket_read_into_ptr reads `len` bytes into `buf`
pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int { pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) !int {
mut res := 0 mut res := 0
for { for {
res = C.mbedtls_ssl_read(&s.ssl, buf_ptr, len) res = C.mbedtls_ssl_read(&s.ssl, buf_ptr, len)
@ -227,13 +227,13 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
} else { } else {
match res { match res {
C.MBEDTLS_ERR_SSL_WANT_READ { C.MBEDTLS_ERR_SSL_WANT_READ {
ready := @select(s.handle, .read, s.duration)? ready := @select(s.handle, .read, s.duration)!
if !ready { if !ready {
return net.err_timed_out return net.err_timed_out
} }
} }
C.MBEDTLS_ERR_SSL_WANT_WRITE { C.MBEDTLS_ERR_SSL_WANT_WRITE {
ready := @select(s.handle, .write, s.duration)? ready := @select(s.handle, .write, s.duration)!
if !ready { if !ready {
return net.err_timed_out return net.err_timed_out
} }
@ -257,7 +257,7 @@ pub fn (mut s SSLConn) read(mut buffer []u8) !int {
} }
// write_ptr writes `len` bytes from `bytes` to the ssl connection // write_ptr writes `len` bytes from `bytes` to the ssl connection
pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int { pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) !int {
unsafe { unsafe {
mut ptr_base := bytes mut ptr_base := bytes
mut total_sent := 0 mut total_sent := 0
@ -269,7 +269,7 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
match sent { match sent {
C.MBEDTLS_ERR_SSL_WANT_READ { C.MBEDTLS_ERR_SSL_WANT_READ {
for { for {
ready := @select(s.handle, .read, s.duration)? ready := @select(s.handle, .read, s.duration)!
if ready { if ready {
break break
} }
@ -278,7 +278,7 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
} }
C.MBEDTLS_ERR_SSL_WANT_WRITE { C.MBEDTLS_ERR_SSL_WANT_WRITE {
for { for {
ready := @select(s.handle, .write, s.duration)? ready := @select(s.handle, .write, s.duration)!
if ready { if ready {
break break
} }
@ -297,12 +297,12 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
} }
// write writes data from `bytes` to the ssl connection // write writes data from `bytes` to the ssl connection
pub fn (mut s SSLConn) write(bytes []u8) ?int { pub fn (mut s SSLConn) write(bytes []u8) !int {
return s.write_ptr(&u8(bytes.data), bytes.len) return s.write_ptr(&u8(bytes.data), bytes.len)
} }
// write_string writes a string to the ssl connection // write_string writes a string to the ssl connection
pub fn (mut s SSLConn) write_string(str string) ?int { pub fn (mut s SSLConn) write_string(str string) !int {
return s.write_ptr(str.str, str.len) return s.write_ptr(str.str, str.len)
} }
@ -313,7 +313,7 @@ This is basically a copy of Emily socket implementation of select.
*/ */
// Select waits for an io operation (specified by parameter `test`) to be available // Select waits for an io operation (specified by parameter `test`) to be available
fn @select(handle int, test Select, timeout time.Duration) ?bool { fn @select(handle int, test Select, timeout time.Duration) !bool {
set := C.fd_set{} set := C.fd_set{}
C.FD_ZERO(&set) C.FD_ZERO(&set)
@ -336,13 +336,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
match test { match test {
.read { .read {
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))? net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
} }
.write { .write {
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))? net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
} }
.except { .except {
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))? net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
} }
} }

View File

@ -1,7 +1,7 @@
module openssl module openssl
// ssl_error returns non error ssl code or error if unrecoverable and we should panic // ssl_error returns non error ssl code or error if unrecoverable and we should panic
fn ssl_error(ret int, ssl voidptr) ?SSLError { fn ssl_error(ret int, ssl voidptr) !SSLError {
res := C.SSL_get_error(ssl, ret) res := C.SSL_get_error(ssl, ret)
match unsafe { SSLError(res) } { match unsafe { SSLError(res) } {
.ssl_error_syscall { .ssl_error_syscall {

View File

@ -28,7 +28,7 @@ pub struct SSLConnectConfig {
} }
// new_ssl_conn instance an new SSLCon struct // new_ssl_conn instance an new SSLCon struct
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn { pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
mut conn := &SSLConn{ mut conn := &SSLConn{
config: config config: config
sslctx: 0 sslctx: 0
@ -47,7 +47,7 @@ enum Select {
} }
// shutdown closes the ssl connection and does cleanup // shutdown closes the ssl connection and does cleanup
pub fn (mut s SSLConn) shutdown() ? { pub fn (mut s SSLConn) shutdown() ! {
if s.ssl != 0 { if s.ssl != 0 {
mut res := 0 mut res := 0
for { for {
@ -100,15 +100,15 @@ pub fn (mut s SSLConn) shutdown() ? {
if s.owns_socket { if s.owns_socket {
$if windows { $if windows {
C.shutdown(s.handle, C.SD_BOTH) C.shutdown(s.handle, C.SD_BOTH)
net.socket_error(C.closesocket(s.handle))? net.socket_error(C.closesocket(s.handle))!
} $else { } $else {
C.shutdown(s.handle, C.SHUT_RDWR) C.shutdown(s.handle, C.SHUT_RDWR)
net.socket_error(C.close(s.handle))? net.socket_error(C.close(s.handle))!
} }
} }
} }
fn (mut s SSLConn) init() ? { fn (mut s SSLConn) init() ! {
s.sslctx = unsafe { C.SSL_CTX_new(C.SSLv23_client_method()) } s.sslctx = unsafe { C.SSL_CTX_new(C.SSLv23_client_method()) }
if s.sslctx == 0 { if s.sslctx == 0 {
return error("Couldn't get ssl context") return error("Couldn't get ssl context")
@ -136,13 +136,13 @@ fn (mut s SSLConn) init() ? {
cert = os.temp_dir() + '/v_cert' + now cert = os.temp_dir() + '/v_cert' + now
cert_key = os.temp_dir() + '/v_cert_key' + now cert_key = os.temp_dir() + '/v_cert_key' + now
if s.config.verify != '' { if s.config.verify != '' {
os.write_file(verify, s.config.verify)? os.write_file(verify, s.config.verify)!
} }
if s.config.cert != '' { if s.config.cert != '' {
os.write_file(cert, s.config.cert)? os.write_file(cert, s.config.cert)!
} }
if s.config.cert_key != '' { if s.config.cert_key != '' {
os.write_file(cert_key, s.config.cert_key)? os.write_file(cert_key, s.config.cert_key)!
} }
} }
if s.config.verify != '' { if s.config.verify != '' {
@ -175,7 +175,7 @@ fn (mut s SSLConn) init() ? {
} }
// connect to server using OpenSSL // connect to server using OpenSSL
pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? { pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ! {
s.handle = tcp_conn.sock.handle s.handle = tcp_conn.sock.handle
s.duration = tcp_conn.read_timeout() s.duration = tcp_conn.read_timeout()
@ -192,7 +192,7 @@ pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? {
} }
// dial opens an ssl connection on hostname:port // dial opens an ssl connection on hostname:port
pub fn (mut s SSLConn) dial(hostname string, port int) ? { pub fn (mut s SSLConn) dial(hostname string, port int) ! {
s.owns_socket = true s.owns_socket = true
mut tcp_conn := net.dial_tcp('$hostname:$port') or { return err } mut tcp_conn := net.dial_tcp('$hostname:$port') or { return err }
$if macos { $if macos {
@ -201,14 +201,14 @@ pub fn (mut s SSLConn) dial(hostname string, port int) ? {
s.connect(mut tcp_conn, hostname) or { return err } s.connect(mut tcp_conn, hostname) or { return err }
} }
fn (mut s SSLConn) complete_connect() ? { fn (mut s SSLConn) complete_connect() ! {
for { for {
mut res := C.SSL_connect(voidptr(s.ssl)) mut res := C.SSL_connect(voidptr(s.ssl))
if res != 1 { if res != 1 {
err_res := ssl_error(res, s.ssl)? err_res := ssl_error(res, s.ssl)!
if err_res == .ssl_error_want_read { if err_res == .ssl_error_want_read {
for { for {
ready := @select(s.handle, .read, s.duration)? ready := @select(s.handle, .read, s.duration)!
if ready { if ready {
break break
} }
@ -216,7 +216,7 @@ fn (mut s SSLConn) complete_connect() ? {
continue continue
} else if err_res == .ssl_error_want_write { } else if err_res == .ssl_error_want_write {
for { for {
ready := @select(s.handle, .write, s.duration)? ready := @select(s.handle, .write, s.duration)!
if ready { if ready {
break break
} }
@ -232,10 +232,10 @@ fn (mut s SSLConn) complete_connect() ? {
for { for {
mut res := C.SSL_do_handshake(voidptr(s.ssl)) mut res := C.SSL_do_handshake(voidptr(s.ssl))
if res != 1 { if res != 1 {
err_res := ssl_error(res, s.ssl)? err_res := ssl_error(res, s.ssl)!
if err_res == .ssl_error_want_read { if err_res == .ssl_error_want_read {
for { for {
ready := @select(s.handle, .read, s.duration)? ready := @select(s.handle, .read, s.duration)!
if ready { if ready {
break break
} }
@ -243,7 +243,7 @@ fn (mut s SSLConn) complete_connect() ? {
continue continue
} else if err_res == .ssl_error_want_write { } else if err_res == .ssl_error_want_write {
for { for {
ready := @select(s.handle, .write, s.duration)? ready := @select(s.handle, .write, s.duration)!
if ready { if ready {
break break
} }
@ -267,7 +267,7 @@ fn (mut s SSLConn) complete_connect() ? {
} }
} }
pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int { pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) !int {
mut res := 0 mut res := 0
for { for {
res = C.SSL_read(voidptr(s.ssl), buf_ptr, len) res = C.SSL_read(voidptr(s.ssl), buf_ptr, len)
@ -276,16 +276,16 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
} else if res == 0 { } else if res == 0 {
return IError(io.Eof{}) return IError(io.Eof{})
} else { } else {
err_res := ssl_error(res, s.ssl)? err_res := ssl_error(res, s.ssl)!
match err_res { match err_res {
.ssl_error_want_read { .ssl_error_want_read {
ready := @select(s.handle, .read, s.duration)? ready := @select(s.handle, .read, s.duration)!
if !ready { if !ready {
return net.err_timed_out return net.err_timed_out
} }
} }
.ssl_error_want_write { .ssl_error_want_write {
ready := @select(s.handle, .write, s.duration)? ready := @select(s.handle, .write, s.duration)!
if !ready { if !ready {
return net.err_timed_out return net.err_timed_out
} }
@ -308,7 +308,7 @@ pub fn (mut s SSLConn) read(mut buffer []u8) !int {
} }
// write_ptr writes `len` bytes from `bytes` to the ssl connection // write_ptr writes `len` bytes from `bytes` to the ssl connection
pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int { pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) !int {
unsafe { unsafe {
mut ptr_base := bytes mut ptr_base := bytes
mut total_sent := 0 mut total_sent := 0
@ -317,17 +317,17 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
remaining := len - total_sent remaining := len - total_sent
mut sent := C.SSL_write(voidptr(s.ssl), ptr, remaining) mut sent := C.SSL_write(voidptr(s.ssl), ptr, remaining)
if sent <= 0 { if sent <= 0 {
err_res := ssl_error(sent, s.ssl)? err_res := ssl_error(sent, s.ssl)!
if err_res == .ssl_error_want_read { if err_res == .ssl_error_want_read {
for { for {
ready := @select(s.handle, .read, s.duration)? ready := @select(s.handle, .read, s.duration)!
if ready { if ready {
break break
} }
} }
} else if err_res == .ssl_error_want_write { } else if err_res == .ssl_error_want_write {
for { for {
ready := @select(s.handle, .write, s.duration)? ready := @select(s.handle, .write, s.duration)!
if ready { if ready {
break break
} }
@ -345,12 +345,12 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
} }
// write writes data from `bytes` to the ssl connection // write writes data from `bytes` to the ssl connection
pub fn (mut s SSLConn) write(bytes []u8) ?int { pub fn (mut s SSLConn) write(bytes []u8) !int {
return s.write_ptr(&u8(bytes.data), bytes.len) return s.write_ptr(&u8(bytes.data), bytes.len)
} }
// write_string writes a string to the ssl connection // write_string writes a string to the ssl connection
pub fn (mut s SSLConn) write_string(str string) ?int { pub fn (mut s SSLConn) write_string(str string) !int {
return s.write_ptr(str.str, str.len) return s.write_ptr(str.str, str.len)
} }
@ -364,7 +364,7 @@ This is basically a copy of Emily socket implementation of select.
// } // }
// Select waits for an io operation (specified by parameter `test`) to be available // Select waits for an io operation (specified by parameter `test`) to be available
fn @select(handle int, test Select, timeout time.Duration) ?bool { fn @select(handle int, test Select, timeout time.Duration) !bool {
set := C.fd_set{} set := C.fd_set{}
C.FD_ZERO(&set) C.FD_ZERO(&set)
@ -387,13 +387,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
match test { match test {
.read { .read {
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))? net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
} }
.write { .write {
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))? net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
} }
.except { .except {
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))? net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
} }
} }

View File

@ -59,7 +59,7 @@ pub struct Mail {
} }
// new_client returns a new SMTP client and connects to it // new_client returns a new SMTP client and connects to it
pub fn new_client(config Client) ?&Client { pub fn new_client(config Client) !&Client {
if config.ssl && config.starttls { if config.ssl && config.starttls {
return error('Can not use both implicit SSL and STARTTLS') return error('Can not use both implicit SSL and STARTTLS')
} }
@ -67,12 +67,12 @@ pub fn new_client(config Client) ?&Client {
mut c := &Client{ mut c := &Client{
...config ...config
} }
c.reconnect()? c.reconnect()!
return c return c
} }
// reconnect reconnects to the SMTP server if the connection was closed // reconnect reconnects to the SMTP server if the connection was closed
pub fn (mut c Client) reconnect() ? { pub fn (mut c Client) reconnect() ! {
if c.is_open { if c.is_open {
return error('Already connected to server') return error('Already connected to server')
} }
@ -81,7 +81,7 @@ pub fn (mut c Client) reconnect() ? {
c.conn = conn c.conn = conn
if c.ssl { if c.ssl {
c.connect_ssl()? c.connect_ssl()!
} else { } else {
c.reader = io.new_buffered_reader(reader: c.conn) c.reader = io.new_buffered_reader(reader: c.conn)
} }
@ -98,7 +98,7 @@ pub fn (mut c Client) reconnect() ? {
} }
// send sends an email // send sends an email
pub fn (mut c Client) send(config Mail) ? { pub fn (mut c Client) send(config Mail) ! {
if !c.is_open { if !c.is_open {
return error('Disconnected from server') return error('Disconnected from server')
} }
@ -113,20 +113,20 @@ pub fn (mut c Client) send(config Mail) ? {
} }
// quit closes the connection to the server // quit closes the connection to the server
pub fn (mut c Client) quit() ? { pub fn (mut c Client) quit() ! {
c.send_str('QUIT\r\n')? c.send_str('QUIT\r\n')!
c.expect_reply(.close)? c.expect_reply(.close)!
if c.encrypted { if c.encrypted {
c.ssl_conn.shutdown()? c.ssl_conn.shutdown()!
} else { } else {
c.conn.close()? c.conn.close()!
} }
c.is_open = false c.is_open = false
c.encrypted = false c.encrypted = false
} }
fn (mut c Client) connect_ssl() ? { fn (mut c Client) connect_ssl() ! {
c.ssl_conn = ssl.new_ssl_conn()? c.ssl_conn = ssl.new_ssl_conn()!
c.ssl_conn.connect(mut c.conn, c.server) or { c.ssl_conn.connect(mut c.conn, c.server) or {
return error('Connecting to server using OpenSSL failed: $err') return error('Connecting to server using OpenSSL failed: $err')
} }
@ -136,10 +136,10 @@ fn (mut c Client) connect_ssl() ? {
} }
// expect_reply checks if the SMTP server replied with the expected reply code // expect_reply checks if the SMTP server replied with the expected reply code
fn (mut c Client) expect_reply(expected ReplyCode) ? { fn (mut c Client) expect_reply(expected ReplyCode) ! {
mut str := '' mut str := ''
for { for {
str = c.reader.read_line()? str = c.reader.read_line()!
if str.len < 4 { if str.len < 4 {
return error('Invalid SMTP response: $str') return error('Invalid SMTP response: $str')
} }
@ -167,7 +167,7 @@ fn (mut c Client) expect_reply(expected ReplyCode) ? {
} }
[inline] [inline]
fn (mut c Client) send_str(s string) ? { fn (mut c Client) send_str(s string) ! {
$if smtp_debug ? { $if smtp_debug ? {
eprintln('\n\n[SEND START]') eprintln('\n\n[SEND START]')
eprint(s.trim_space()) eprint(s.trim_space())
@ -175,27 +175,27 @@ fn (mut c Client) send_str(s string) ? {
} }
if c.encrypted { if c.encrypted {
c.ssl_conn.write(s.bytes())? c.ssl_conn.write(s.bytes())!
} else { } else {
c.conn.write(s.bytes())? c.conn.write(s.bytes())!
} }
} }
[inline] [inline]
fn (mut c Client) send_ehlo() ? { fn (mut c Client) send_ehlo() ! {
c.send_str('EHLO $c.server\r\n')? c.send_str('EHLO $c.server\r\n')!
c.expect_reply(.action_ok)? c.expect_reply(.action_ok)!
} }
[inline] [inline]
fn (mut c Client) send_starttls() ? { fn (mut c Client) send_starttls() ! {
c.send_str('STARTTLS\r\n')? c.send_str('STARTTLS\r\n')!
c.expect_reply(.ready)? c.expect_reply(.ready)!
c.connect_ssl()? c.connect_ssl()!
} }
[inline] [inline]
fn (mut c Client) send_auth() ? { fn (mut c Client) send_auth() ! {
if c.username.len == 0 { if c.username.len == 0 {
return return
} }
@ -206,28 +206,28 @@ fn (mut c Client) send_auth() ? {
sb.write_string(c.password) sb.write_string(c.password)
a := sb.str() a := sb.str()
auth := 'AUTH PLAIN ${base64.encode_str(a)}\r\n' auth := 'AUTH PLAIN ${base64.encode_str(a)}\r\n'
c.send_str(auth)? c.send_str(auth)!
c.expect_reply(.auth_ok)? c.expect_reply(.auth_ok)!
} }
fn (mut c Client) send_mailfrom(from string) ? { fn (mut c Client) send_mailfrom(from string) ! {
c.send_str('MAIL FROM: <$from>\r\n')? c.send_str('MAIL FROM: <$from>\r\n')!
c.expect_reply(.action_ok)? c.expect_reply(.action_ok)!
} }
fn (mut c Client) send_mailto(to string) ? { fn (mut c Client) send_mailto(to string) ! {
for rcpt in to.split(';') { for rcpt in to.split(';') {
c.send_str('RCPT TO: <$rcpt>\r\n')? c.send_str('RCPT TO: <$rcpt>\r\n')!
c.expect_reply(.action_ok)? c.expect_reply(.action_ok)!
} }
} }
fn (mut c Client) send_data() ? { fn (mut c Client) send_data() ! {
c.send_str('DATA\r\n')? c.send_str('DATA\r\n')!
c.expect_reply(.mail_start)? c.expect_reply(.mail_start)!
} }
fn (mut c Client) send_body(cfg Mail) ? { fn (mut c Client) send_body(cfg Mail) ! {
is_html := cfg.body_type == .html is_html := cfg.body_type == .html
date := cfg.date.custom_format('ddd, D MMM YYYY HH:mm ZZ') date := cfg.date.custom_format('ddd, D MMM YYYY HH:mm ZZ')
nonascii_subject := cfg.subject.bytes().any(it < u8(` `) || it > u8(`~`)) nonascii_subject := cfg.subject.bytes().any(it < u8(` `) || it > u8(`~`))
@ -253,6 +253,6 @@ fn (mut c Client) send_body(cfg Mail) ? {
sb.write_string('\r\n\r\n') sb.write_string('\r\n\r\n')
sb.write_string(base64.encode_str(cfg.body)) sb.write_string(base64.encode_str(cfg.body))
sb.write_string('\r\n.\r\n') sb.write_string('\r\n.\r\n')
c.send_str(sb.str())? c.send_str(sb.str())!
c.expect_reply(.action_ok)? c.expect_reply(.action_ok)!
} }

View File

@ -6,6 +6,6 @@ pub:
} }
// address gets the address of a socket // address gets the address of a socket
pub fn (s &Socket) address() ?Addr { pub fn (s &Socket) address() !Addr {
return addr_from_socket_handle(s.handle) return addr_from_socket_handle(s.handle)
} }

View File

@ -12,7 +12,7 @@ pub struct SSLConnectConfig {
} }
// new_ssl_conn returns a new SSLConn with the given config. // new_ssl_conn returns a new SSLConn with the given config.
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn { pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
c := openssl.new_ssl_conn(config.SSLConnectConfig) or { return err } c := openssl.new_ssl_conn(config.SSLConnectConfig) or { return err }
return &SSLConn{c} return &SSLConn{c}
} }

View File

@ -12,7 +12,7 @@ pub struct SSLConnectConfig {
} }
// new_ssl_conn returns a new SSLConn with the given config. // new_ssl_conn returns a new SSLConn with the given config.
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn { pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
c := mbedtls.new_ssl_conn(config.SSLConnectConfig) or { return err } c := mbedtls.new_ssl_conn(config.SSLConnectConfig) or { return err }
return &SSLConn{c} return &SSLConn{c}
} }

View File

@ -21,7 +21,7 @@ mut:
is_blocking bool is_blocking bool
} }
pub fn dial_tcp(address string) ?&TcpConn { pub fn dial_tcp(address string) !&TcpConn {
addrs := resolve_addrs_fuzzy(address, .tcp) or { addrs := resolve_addrs_fuzzy(address, .tcp) or {
return error('$err.msg(); could not resolve address $address in dial_tcp') return error('$err.msg(); could not resolve address $address in dial_tcp')
} }
@ -64,7 +64,7 @@ pub fn dial_tcp(address string) ?&TcpConn {
} }
// bind local address and dial. // bind local address and dial.
pub fn dial_tcp_with_bind(saddr string, laddr string) ?&TcpConn { pub fn dial_tcp_with_bind(saddr string, laddr string) !&TcpConn {
addrs := resolve_addrs_fuzzy(saddr, .tcp) or { addrs := resolve_addrs_fuzzy(saddr, .tcp) or {
return error('$err.msg(); could not resolve address $saddr in dial_tcp_with_bind') return error('$err.msg(); could not resolve address $saddr in dial_tcp_with_bind')
} }
@ -94,15 +94,15 @@ pub fn dial_tcp_with_bind(saddr string, laddr string) ?&TcpConn {
return error('dial_tcp_with_bind failed for address $saddr') return error('dial_tcp_with_bind failed for address $saddr')
} }
pub fn (mut c TcpConn) close() ? { pub fn (mut c TcpConn) close() ! {
$if trace_tcp ? { $if trace_tcp ? {
eprintln(' TcpConn.close | c.sock.handle: ${c.sock.handle:6}') eprintln(' TcpConn.close | c.sock.handle: ${c.sock.handle:6}')
} }
c.sock.close()? c.sock.close()!
} }
pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int { pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int {
mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))? mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
$if trace_tcp ? { $if trace_tcp ? {
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
} }
@ -115,8 +115,8 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int {
} }
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_read()? c.wait_for_read()!
res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))? res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
$if trace_tcp ? { $if trace_tcp ? {
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
} }
@ -128,9 +128,9 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int {
} }
return socket_error(res) return socket_error(res)
} else { } else {
wrap_error(code)? wrap_error(code)!
} }
return none return error('none')
} }
pub fn (c TcpConn) read(mut buf []u8) !int { pub fn (c TcpConn) read(mut buf []u8) !int {
@ -142,15 +142,15 @@ pub fn (c TcpConn) read(mut buf []u8) !int {
} }
} }
pub fn (mut c TcpConn) read_deadline() ?time.Time { pub fn (mut c TcpConn) read_deadline() !time.Time {
if c.read_deadline.unix == 0 { if c.read_deadline.unix == 0 {
return c.read_deadline return c.read_deadline
} }
return none return error('none')
} }
// write_ptr blocks and attempts to write all data // write_ptr blocks and attempts to write all data
pub fn (mut c TcpConn) write_ptr(b &u8, len int) ?int { pub fn (mut c TcpConn) write_ptr(b &u8, len int) !int {
$if trace_tcp ? { $if trace_tcp ? {
eprintln( eprintln(
'>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + '>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
@ -173,10 +173,10 @@ pub fn (mut c TcpConn) write_ptr(b &u8, len int) ?int {
if sent < 0 { if sent < 0 {
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_write()? c.wait_for_write()!
continue continue
} else { } else {
wrap_error(code)? wrap_error(code)!
} }
} }
total_sent += sent total_sent += sent
@ -186,12 +186,12 @@ pub fn (mut c TcpConn) write_ptr(b &u8, len int) ?int {
} }
// write blocks and attempts to write all data // write blocks and attempts to write all data
pub fn (mut c TcpConn) write(bytes []u8) ?int { pub fn (mut c TcpConn) write(bytes []u8) !int {
return c.write_ptr(bytes.data, bytes.len) return c.write_ptr(bytes.data, bytes.len)
} }
// write_string blocks and attempts to write all data // write_string blocks and attempts to write all data
pub fn (mut c TcpConn) write_string(s string) ?int { pub fn (mut c TcpConn) write_string(s string) !int {
return c.write_ptr(s.str, s.len) return c.write_ptr(s.str, s.len)
} }
@ -199,11 +199,11 @@ pub fn (mut c TcpConn) set_read_deadline(deadline time.Time) {
c.read_deadline = deadline c.read_deadline = deadline
} }
pub fn (mut c TcpConn) write_deadline() ?time.Time { pub fn (mut c TcpConn) write_deadline() !time.Time {
if c.write_deadline.unix == 0 { if c.write_deadline.unix == 0 {
return c.write_deadline return c.write_deadline
} }
return none return error('none')
} }
pub fn (mut c TcpConn) set_write_deadline(deadline time.Time) { pub fn (mut c TcpConn) set_write_deadline(deadline time.Time) {
@ -227,31 +227,31 @@ pub fn (mut c TcpConn) set_write_timeout(t time.Duration) {
} }
[inline] [inline]
pub fn (c TcpConn) wait_for_read() ? { pub fn (c TcpConn) wait_for_read() ! {
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout) return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
} }
[inline] [inline]
pub fn (mut c TcpConn) wait_for_write() ? { pub fn (mut c TcpConn) wait_for_write() ! {
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout) return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
} }
pub fn (c &TcpConn) peer_addr() ?Addr { pub fn (c &TcpConn) peer_addr() !Addr {
mut addr := Addr{ mut addr := Addr{
addr: AddrData{ addr: AddrData{
Ip6: Ip6{} Ip6: Ip6{}
} }
} }
mut size := sizeof(Addr) mut size := sizeof(Addr)
socket_error_message(C.getpeername(c.sock.handle, voidptr(&addr), &size), 'peer_addr failed')? socket_error_message(C.getpeername(c.sock.handle, voidptr(&addr), &size), 'peer_addr failed')!
return addr return addr
} }
pub fn (c &TcpConn) peer_ip() ?string { pub fn (c &TcpConn) peer_ip() !string {
return c.peer_addr()?.str() return c.peer_addr()!.str()
} }
pub fn (c &TcpConn) addr() ?Addr { pub fn (c &TcpConn) addr() !Addr {
return c.sock.address() return c.sock.address()
} }
@ -268,7 +268,7 @@ mut:
accept_deadline time.Time accept_deadline time.Time
} }
pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener { pub fn listen_tcp(family AddrFamily, saddr string) !&TcpListener {
s := new_tcp_socket(family) or { return error('$err.msg(); could not create new socket') } s := new_tcp_socket(family) or { return error('$err.msg(); could not create new socket') }
addrs := resolve_addrs(saddr, family, .tcp) or { addrs := resolve_addrs(saddr, family, .tcp) or {
@ -280,8 +280,8 @@ pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener {
// cast to the correct type // cast to the correct type
alen := addr.len() alen := addr.len()
socket_error_message(C.bind(s.handle, voidptr(&addr), alen), 'binding to $saddr failed')? socket_error_message(C.bind(s.handle, voidptr(&addr), alen), 'binding to $saddr failed')!
socket_error_message(C.listen(s.handle, 128), 'listening on $saddr failed')? socket_error_message(C.listen(s.handle, 128), 'listening on $saddr failed')!
return &TcpListener{ return &TcpListener{
sock: s sock: s
accept_deadline: no_deadline accept_deadline: no_deadline
@ -289,19 +289,19 @@ pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener {
} }
} }
pub fn (mut l TcpListener) accept() ?&TcpConn { pub fn (mut l TcpListener) accept() !&TcpConn {
$if trace_tcp ? { $if trace_tcp ? {
eprintln(' TcpListener.accept | l.sock.handle: ${l.sock.handle:6}') eprintln(' TcpListener.accept | l.sock.handle: ${l.sock.handle:6}')
} }
mut new_handle := C.accept(l.sock.handle, 0, 0) mut new_handle := C.accept(l.sock.handle, 0, 0)
if new_handle <= 0 { if new_handle <= 0 {
l.wait_for_accept()? l.wait_for_accept()!
new_handle = C.accept(l.sock.handle, 0, 0) new_handle = C.accept(l.sock.handle, 0, 0)
if new_handle == -1 || new_handle == 0 { if new_handle == -1 || new_handle == 0 {
return error('accept failed') return error('accept failed')
} }
} }
new_sock := tcp_socket_from_handle(new_handle)? new_sock := tcp_socket_from_handle(new_handle)!
$if trace_tcp ? { $if trace_tcp ? {
eprintln(' TcpListener.accept | << new_sock.handle: ${new_sock.handle:6}') eprintln(' TcpListener.accept | << new_sock.handle: ${new_sock.handle:6}')
} }
@ -312,7 +312,7 @@ pub fn (mut l TcpListener) accept() ?&TcpConn {
} }
} }
pub fn (c &TcpListener) accept_deadline() ?time.Time { pub fn (c &TcpListener) accept_deadline() !time.Time {
if c.accept_deadline.unix != 0 { if c.accept_deadline.unix != 0 {
return c.accept_deadline return c.accept_deadline
} }
@ -331,15 +331,15 @@ pub fn (mut c TcpListener) set_accept_timeout(t time.Duration) {
c.accept_timeout = t c.accept_timeout = t
} }
pub fn (mut c TcpListener) wait_for_accept() ? { pub fn (mut c TcpListener) wait_for_accept() ! {
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout) return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
} }
pub fn (mut c TcpListener) close() ? { pub fn (mut c TcpListener) close() ! {
c.sock.close()? c.sock.close()!
} }
pub fn (c &TcpListener) addr() ?Addr { pub fn (c &TcpListener) addr() !Addr {
return c.sock.address() return c.sock.address()
} }
@ -347,8 +347,8 @@ struct TcpSocket {
Socket Socket
} }
fn new_tcp_socket(family AddrFamily) ?TcpSocket { fn new_tcp_socket(family AddrFamily) !TcpSocket {
handle := socket_error(C.socket(family, SocketType.tcp, 0))? handle := socket_error(C.socket(family, SocketType.tcp, 0))!
mut s := TcpSocket{ mut s := TcpSocket{
handle: handle handle: handle
} }
@ -362,20 +362,20 @@ fn new_tcp_socket(family AddrFamily) ?TcpSocket {
// TODO(emily): // TODO(emily):
// Move this to its own function on the socket // Move this to its own function on the socket
s.set_option_int(.reuse_addr, 1)? s.set_option_int(.reuse_addr, 1)!
$if !net_blocking_sockets ? { $if !net_blocking_sockets ? {
$if windows { $if windows {
t := u32(1) // true t := u32(1) // true
socket_error(C.ioctlsocket(handle, fionbio, &t))? socket_error(C.ioctlsocket(handle, fionbio, &t))!
} $else { } $else {
socket_error(C.fcntl(handle, C.F_SETFL, C.fcntl(handle, C.F_GETFL) | C.O_NONBLOCK))? socket_error(C.fcntl(handle, C.F_SETFL, C.fcntl(handle, C.F_GETFL) | C.O_NONBLOCK))!
} }
} }
return s return s
} }
fn tcp_socket_from_handle(sockfd int) ?TcpSocket { fn tcp_socket_from_handle(sockfd int) !TcpSocket {
mut s := TcpSocket{ mut s := TcpSocket{
handle: sockfd handle: sockfd
} }
@ -383,22 +383,22 @@ fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
eprintln(' tcp_socket_from_handle | s.handle: ${s.handle:6}') eprintln(' tcp_socket_from_handle | s.handle: ${s.handle:6}')
} }
// s.set_option_bool(.reuse_addr, true)? // s.set_option_bool(.reuse_addr, true)?
s.set_option_int(.reuse_addr, 1)? s.set_option_int(.reuse_addr, 1)!
s.set_dualstack(true) or { s.set_dualstack(true) or {
// Not ipv6, we dont care // Not ipv6, we dont care
} }
$if !net_blocking_sockets ? { $if !net_blocking_sockets ? {
$if windows { $if windows {
t := u32(1) // true t := u32(1) // true
socket_error(C.ioctlsocket(sockfd, fionbio, &t))? socket_error(C.ioctlsocket(sockfd, fionbio, &t))!
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK))? socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK))!
} }
} }
return s return s
} }
pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ? { pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ! {
// TODO reenable when this `in` operation works again // TODO reenable when this `in` operation works again
// if opt !in opts_can_set { // if opt !in opts_can_set {
// return err_option_not_settable // return err_option_not_settable
@ -407,21 +407,21 @@ pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ? {
// return err_option_wrong_type // return err_option_wrong_type
// } // }
x := int(value) x := int(value)
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))? socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))!
} }
pub fn (mut s TcpSocket) set_dualstack(on bool) ? { pub fn (mut s TcpSocket) set_dualstack(on bool) ! {
x := int(!on) x := int(!on)
socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x, socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x,
sizeof(int)))? sizeof(int)))!
} }
pub fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) ? { pub fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) ! {
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &value, sizeof(int)))? socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &value, sizeof(int)))!
} }
// bind a local rddress for TcpSocket // bind a local rddress for TcpSocket
pub fn (mut s TcpSocket) bind(addr string) ? { pub fn (mut s TcpSocket) bind(addr string) ! {
addrs := resolve_addrs(addr, AddrFamily.ip, .tcp) or { addrs := resolve_addrs(addr, AddrFamily.ip, .tcp) or {
return error('$err.msg(); could not resolve address $addr') return error('$err.msg(); could not resolve address $addr')
} }
@ -436,11 +436,11 @@ pub fn (mut s TcpSocket) bind(addr string) ? {
} }
} }
fn (mut s TcpSocket) close() ? { fn (mut s TcpSocket) close() ! {
return shutdown(s.handle) return shutdown(s.handle)
} }
fn (mut s TcpSocket) @select(test Select, timeout time.Duration) ?bool { fn (mut s TcpSocket) @select(test Select, timeout time.Duration) !bool {
return @select(s.handle, test, timeout) return @select(s.handle, test, timeout)
} }
@ -448,7 +448,7 @@ const (
connect_timeout = 5 * time.second connect_timeout = 5 * time.second
) )
fn (mut s TcpSocket) connect(a Addr) ? { fn (mut s TcpSocket) connect(a Addr) ! {
$if !net_blocking_sockets ? { $if !net_blocking_sockets ? {
res := C.connect(s.handle, voidptr(&a), a.len()) res := C.connect(s.handle, voidptr(&a), a.len())
if res == 0 { if res == 0 {
@ -467,7 +467,7 @@ fn (mut s TcpSocket) connect(a Addr) ? {
// determine whether connect() completed successfully (SO_ERROR is zero) or // determine whether connect() completed successfully (SO_ERROR is zero) or
// unsuccessfully (SO_ERROR is one of the usual error codes listed here, // unsuccessfully (SO_ERROR is one of the usual error codes listed here,
// ex plaining the reason for the failure). // ex plaining the reason for the failure).
write_result := s.@select(.write, net.connect_timeout)? write_result := s.@select(.write, net.connect_timeout)!
err := 0 err := 0
len := sizeof(err) len := sizeof(err)
xyz := C.getsockopt(s.handle, C.SOL_SOCKET, C.SO_ERROR, &err, &len) xyz := C.getsockopt(s.handle, C.SOL_SOCKET, C.SO_ERROR, &err, &len)
@ -476,17 +476,17 @@ fn (mut s TcpSocket) connect(a Addr) ? {
} }
if write_result { if write_result {
if xyz == 0 { if xyz == 0 {
wrap_error(err)? wrap_error(err)!
return return
} }
return return
} }
return err_timed_out return err_timed_out
} }
wrap_error(ecode)? wrap_error(ecode)!
return return
} $else { } $else {
x := C.connect(s.handle, voidptr(&a), a.len()) x := C.connect(s.handle, voidptr(&a), a.len())
socket_error(x)? socket_error(x)!
} }
} }

View File

@ -22,14 +22,14 @@ pub fn (mut con TcpConn) get_blocking() bool {
// when state is true, or non blocking (false). // when state is true, or non blocking (false).
// The default for `net` tcp connections is the non blocking mode. // The default for `net` tcp connections is the non blocking mode.
// Calling .read_line will set the connection to blocking mode. // Calling .read_line will set the connection to blocking mode.
pub fn (mut con TcpConn) set_blocking(state bool) ? { pub fn (mut con TcpConn) set_blocking(state bool) ! {
con.is_blocking = state con.is_blocking = state
$if windows { $if windows {
mut t := u32(0) mut t := u32(0)
if !con.is_blocking { if !con.is_blocking {
t = 1 t = 1
} }
socket_error(C.ioctlsocket(con.sock.handle, fionbio, &t))? socket_error(C.ioctlsocket(con.sock.handle, fionbio, &t))!
} $else { } $else {
mut flags := C.fcntl(con.sock.handle, C.F_GETFL, 0) mut flags := C.fcntl(con.sock.handle, C.F_GETFL, 0)
if state { if state {
@ -37,7 +37,7 @@ pub fn (mut con TcpConn) set_blocking(state bool) ? {
} else { } else {
flags |= C.O_NONBLOCK flags |= C.O_NONBLOCK
} }
socket_error(C.fcntl(con.sock.handle, C.F_SETFL, flags))? socket_error(C.fcntl(con.sock.handle, C.F_SETFL, flags))!
} }
} }

View File

@ -27,8 +27,8 @@ mut:
write_timeout time.Duration write_timeout time.Duration
} }
pub fn dial_udp(raddr string) ?&UdpConn { pub fn dial_udp(raddr string) !&UdpConn {
addrs := resolve_addrs_fuzzy(raddr, .udp)? addrs := resolve_addrs_fuzzy(raddr, .udp)!
for addr in addrs { for addr in addrs {
// create a local socket for this // create a local socket for this
@ -43,7 +43,7 @@ pub fn dial_udp(raddr string) ?&UdpConn {
} }
} }
return none return error('none')
} }
// pub fn dial_udp(laddr string, raddr string) ?&UdpConn { // pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
@ -58,46 +58,46 @@ pub fn dial_udp(raddr string) ?&UdpConn {
// } // }
// } // }
pub fn (mut c UdpConn) write_ptr(b &u8, len int) ?int { pub fn (mut c UdpConn) write_ptr(b &u8, len int) !int {
remote := c.sock.remote() or { return err_no_udp_remote } remote := c.sock.remote() or { return err_no_udp_remote }
return c.write_to_ptr(remote, b, len) return c.write_to_ptr(remote, b, len)
} }
pub fn (mut c UdpConn) write(buf []u8) ?int { pub fn (mut c UdpConn) write(buf []u8) !int {
return c.write_ptr(buf.data, buf.len) return c.write_ptr(buf.data, buf.len)
} }
pub fn (mut c UdpConn) write_string(s string) ?int { pub fn (mut c UdpConn) write_string(s string) !int {
return c.write_ptr(s.str, s.len) return c.write_ptr(s.str, s.len)
} }
pub fn (mut c UdpConn) write_to_ptr(addr Addr, b &u8, len int) ?int { pub fn (mut c UdpConn) write_to_ptr(addr Addr, b &u8, len int) !int {
res := C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len()) res := C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len())
if res >= 0 { if res >= 0 {
return res return res
} }
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_write()? c.wait_for_write()!
socket_error(C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len()))? socket_error(C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len()))!
} else { } else {
wrap_error(code)? wrap_error(code)!
} }
return none return error('none')
} }
// write_to blocks and writes the buf to the remote addr specified // write_to blocks and writes the buf to the remote addr specified
pub fn (mut c UdpConn) write_to(addr Addr, buf []u8) ?int { pub fn (mut c UdpConn) write_to(addr Addr, buf []u8) !int {
return c.write_to_ptr(addr, buf.data, buf.len) return c.write_to_ptr(addr, buf.data, buf.len)
} }
// write_to_string blocks and writes the buf to the remote addr specified // write_to_string blocks and writes the buf to the remote addr specified
pub fn (mut c UdpConn) write_to_string(addr Addr, s string) ?int { pub fn (mut c UdpConn) write_to_string(addr Addr, s string) !int {
return c.write_to_ptr(addr, s.str, s.len) return c.write_to_ptr(addr, s.str, s.len)
} }
// read reads from the socket into buf up to buf.len returning the number of bytes read // read reads from the socket into buf up to buf.len returning the number of bytes read
pub fn (mut c UdpConn) read(mut buf []u8) ?(int, Addr) { pub fn (mut c UdpConn) read(mut buf []u8) !(int, Addr) {
mut addr := Addr{ mut addr := Addr{
addr: AddrData{ addr: AddrData{
Ip6: Ip6{} Ip6: Ip6{}
@ -105,40 +105,40 @@ pub fn (mut c UdpConn) read(mut buf []u8) ?(int, Addr) {
} }
len := sizeof(Addr) len := sizeof(Addr)
mut res := wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len, mut res := wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len,
0, voidptr(&addr), &len))? 0, voidptr(&addr), &len))!
if res > 0 { if res > 0 {
return res, addr return res, addr
} }
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_read()? c.wait_for_read()!
// same setup as in tcp // same setup as in tcp
res = wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len, 0, res = wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len, 0,
voidptr(&addr), &len))? voidptr(&addr), &len))!
res2 := socket_error(res)? res2 := socket_error(res)!
return res2, addr return res2, addr
} else { } else {
wrap_error(code)? wrap_error(code)!
} }
return none return error('none')
} }
pub fn (c &UdpConn) read_deadline() ?time.Time { pub fn (c &UdpConn) read_deadline() !time.Time {
if c.read_deadline.unix == 0 { if c.read_deadline.unix == 0 {
return c.read_deadline return c.read_deadline
} }
return none return error('none')
} }
pub fn (mut c UdpConn) set_read_deadline(deadline time.Time) { pub fn (mut c UdpConn) set_read_deadline(deadline time.Time) {
c.read_deadline = deadline c.read_deadline = deadline
} }
pub fn (c &UdpConn) write_deadline() ?time.Time { pub fn (c &UdpConn) write_deadline() !time.Time {
if c.write_deadline.unix == 0 { if c.write_deadline.unix == 0 {
return c.write_deadline return c.write_deadline
} }
return none return error('none')
} }
pub fn (mut c UdpConn) set_write_deadline(deadline time.Time) { pub fn (mut c UdpConn) set_write_deadline(deadline time.Time) {
@ -162,12 +162,12 @@ pub fn (mut c UdpConn) set_write_timeout(t time.Duration) {
} }
[inline] [inline]
pub fn (mut c UdpConn) wait_for_read() ? { pub fn (mut c UdpConn) wait_for_read() ! {
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout) return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
} }
[inline] [inline]
pub fn (mut c UdpConn) wait_for_write() ? { pub fn (mut c UdpConn) wait_for_write() ! {
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout) return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
} }
@ -176,27 +176,27 @@ pub fn (c &UdpConn) str() string {
return 'UdpConn' return 'UdpConn'
} }
pub fn (mut c UdpConn) close() ? { pub fn (mut c UdpConn) close() ! {
return c.sock.close() return c.sock.close()
} }
pub fn listen_udp(laddr string) ?&UdpConn { pub fn listen_udp(laddr string) !&UdpConn {
addrs := resolve_addrs_fuzzy(laddr, .udp)? addrs := resolve_addrs_fuzzy(laddr, .udp)!
// TODO(emily): // TODO(emily):
// here we are binding to the first address // here we are binding to the first address
// and that is probably not ideal // and that is probably not ideal
addr := addrs[0] addr := addrs[0]
return &UdpConn{ return &UdpConn{
sock: new_udp_socket(addr)? sock: new_udp_socket(addr)!
read_timeout: net.udp_default_read_timeout read_timeout: net.udp_default_read_timeout
write_timeout: net.udp_default_write_timeout write_timeout: net.udp_default_write_timeout
} }
} }
fn new_udp_socket(local_addr Addr) ?&UdpSocket { fn new_udp_socket(local_addr Addr) !&UdpSocket {
family := local_addr.family() family := local_addr.family()
sockfd := socket_error(C.socket(family, SocketType.udp, 0))? sockfd := socket_error(C.socket(family, SocketType.udp, 0))!
mut s := &UdpSocket{ mut s := &UdpSocket{
handle: sockfd handle: sockfd
l: local_addr l: local_addr
@ -207,28 +207,28 @@ fn new_udp_socket(local_addr Addr) ?&UdpSocket {
} }
} }
s.set_option_bool(.reuse_addr, true)? s.set_option_bool(.reuse_addr, true)!
if family == .ip6 { if family == .ip6 {
s.set_dualstack(true)? s.set_dualstack(true)!
} }
$if !net_blocking_sockets ? { $if !net_blocking_sockets ? {
// NOTE: refer to comments in tcp.v // NOTE: refer to comments in tcp.v
$if windows { $if windows {
t := u32(1) // true t := u32(1) // true
socket_error(C.ioctlsocket(sockfd, fionbio, &t))? socket_error(C.ioctlsocket(sockfd, fionbio, &t))!
} $else { } $else {
socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK))? socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK))!
} }
} }
// cast to the correct type // cast to the correct type
socket_error(C.bind(s.handle, voidptr(&local_addr), local_addr.len()))? socket_error(C.bind(s.handle, voidptr(&local_addr), local_addr.len()))!
return s return s
} }
fn new_udp_socket_for_remote(raddr Addr) ?&UdpSocket { fn new_udp_socket_for_remote(raddr Addr) !&UdpSocket {
// Invent a sutible local address for this remote addr // Invent a sutible local address for this remote addr
// Appease compiler // Appease compiler
mut addr := Addr{ mut addr := Addr{
@ -246,20 +246,20 @@ fn new_udp_socket_for_remote(raddr Addr) ?&UdpSocket {
addr = new_ip6(0, addr_ip6_any) addr = new_ip6(0, addr_ip6_any)
} }
.unix { .unix {
addr = temp_unix()? addr = temp_unix()!
} }
else { else {
panic('Invalid family') panic('Invalid family')
} }
} }
mut sock := new_udp_socket(addr)? mut sock := new_udp_socket(addr)!
sock.has_r = true sock.has_r = true
sock.r = raddr sock.r = raddr
return sock return sock
} }
pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ? { pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ! {
// TODO reenable when this `in` operation works again // TODO reenable when this `in` operation works again
// if opt !in opts_can_set { // if opt !in opts_can_set {
// return err_option_not_settable // return err_option_not_settable
@ -268,26 +268,26 @@ pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ? {
// return err_option_wrong_type // return err_option_wrong_type
// } // }
x := int(value) x := int(value)
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))? socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))!
} }
pub fn (mut s UdpSocket) set_dualstack(on bool) ? { pub fn (mut s UdpSocket) set_dualstack(on bool) ! {
x := int(!on) x := int(!on)
socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x, socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x,
sizeof(int)))? sizeof(int)))!
} }
fn (mut s UdpSocket) close() ? { fn (mut s UdpSocket) close() ! {
return shutdown(s.handle) return shutdown(s.handle)
} }
fn (mut s UdpSocket) @select(test Select, timeout time.Duration) ?bool { fn (mut s UdpSocket) @select(test Select, timeout time.Duration) !bool {
return @select(s.handle, test, timeout) return @select(s.handle, test, timeout)
} }
fn (s &UdpSocket) remote() ?Addr { fn (s &UdpSocket) remote() !Addr {
if s.has_r { if s.has_r {
return s.r return s.r
} }
return none return error('none')
} }

View File

@ -24,7 +24,7 @@ fn echo_server(mut c net.UdpConn) {
const server_addr = '127.0.0.1:40003' const server_addr = '127.0.0.1:40003'
fn echo() ? { fn echo() ! {
mut c := net.dial_udp(server_addr) or { panic('could not net.dial_udp: $err') } mut c := net.dial_udp(server_addr) or { panic('could not net.dial_udp: $err') }
defer { defer {
c.close() or {} c.close() or {}
@ -48,7 +48,7 @@ fn echo() ? {
println('Got "$buf.bytestr()"') println('Got "$buf.bytestr()"')
c.close()? c.close()!
} }
fn test_udp() { fn test_udp() {

View File

@ -12,18 +12,18 @@ fn C.SUN_LEN(ptr &C.sockaddr_un) int
fn C.strncpy(&char, &char, int) fn C.strncpy(&char, &char, int)
// Shutdown shutsdown a socket and closes it // Shutdown shutsdown a socket and closes it
fn shutdown(handle int) ? { fn shutdown(handle int) ! {
$if windows { $if windows {
C.shutdown(handle, C.SD_BOTH) C.shutdown(handle, C.SD_BOTH)
net.socket_error(C.closesocket(handle))? net.socket_error(C.closesocket(handle))!
} $else { } $else {
C.shutdown(handle, C.SHUT_RDWR) C.shutdown(handle, C.SHUT_RDWR)
net.socket_error(C.close(handle))? net.socket_error(C.close(handle))!
} }
} }
// Select waits for an io operation (specified by parameter `test`) to be available // Select waits for an io operation (specified by parameter `test`) to be available
fn @select(handle int, test Select, timeout time.Duration) ?bool { fn @select(handle int, test Select, timeout time.Duration) !bool {
set := C.fd_set{} set := C.fd_set{}
C.FD_ZERO(&set) C.FD_ZERO(&set)
@ -47,13 +47,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
match test { match test {
.read { .read {
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))? net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
} }
.write { .write {
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))? net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
} }
.except { .except {
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))? net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
} }
} }
@ -61,13 +61,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
} }
// wait_for_common wraps the common wait code // wait_for_common wraps the common wait code
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? { fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ! {
if deadline.unix == 0 { if deadline.unix == 0 {
// do not accept negative timeout // do not accept negative timeout
if timeout < 0 { if timeout < 0 {
return net.err_timed_out return net.err_timed_out
} }
ready := @select(handle, test, timeout)? ready := @select(handle, test, timeout)!
if ready { if ready {
return return
} }
@ -82,7 +82,7 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
return net.err_timed_out return net.err_timed_out
} }
ready := @select(handle, test, d_timeout)? ready := @select(handle, test, d_timeout)!
if ready { if ready {
return return
} }
@ -90,12 +90,12 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
} }
// wait_for_write waits for a write io operation to be available // wait_for_write waits for a write io operation to be available
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? { fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ! {
return wait_for_common(handle, deadline, timeout, .write) return wait_for_common(handle, deadline, timeout, .write)
} }
// wait_for_read waits for a read io operation to be available // wait_for_read waits for a read io operation to be available
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? { fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ! {
return wait_for_common(handle, deadline, timeout, .read) return wait_for_common(handle, deadline, timeout, .read)
} }
@ -120,9 +120,9 @@ const (
) )
[inline] [inline]
fn wrap_read_result(result int) ?int { fn wrap_read_result(result int) !int {
if result != 0 { if result != 0 {
return result return result
} }
return none return error('none')
} }

View File

@ -40,23 +40,23 @@ fn error_code() int {
return C.errno return C.errno
} }
fn new_stream_socket() ?StreamSocket { fn new_stream_socket() !StreamSocket {
sockfd := net.socket_error(C.socket(net.AddrFamily.unix, net.SocketType.tcp, 0))? sockfd := net.socket_error(C.socket(net.AddrFamily.unix, net.SocketType.tcp, 0))!
mut s := StreamSocket{ mut s := StreamSocket{
handle: sockfd handle: sockfd
} }
return s return s
} }
fn (mut s StreamSocket) close() ? { fn (mut s StreamSocket) close() ! {
return shutdown(s.handle) return shutdown(s.handle)
} }
fn (mut s StreamSocket) @select(test Select, timeout time.Duration) ?bool { fn (mut s StreamSocket) @select(test Select, timeout time.Duration) !bool {
return @select(s.handle, test, timeout) return @select(s.handle, test, timeout)
} }
fn (mut s StreamSocket) connect(a string) ? { fn (mut s StreamSocket) connect(a string) ! {
if a.len >= max_sun_path { if a.len >= max_sun_path {
return error('Socket path too long! Max length: ${max_sun_path - 1} chars.') return error('Socket path too long! Max length: ${max_sun_path - 1} chars.')
} }
@ -73,12 +73,12 @@ fn (mut s StreamSocket) connect(a string) ? {
return return
} }
_ := error_code() _ := error_code()
write_result := s.@select(.write, unix.connect_timeout)? write_result := s.@select(.write, unix.connect_timeout)!
if write_result { if write_result {
// succeeded // succeeded
return return
} }
except_result := s.@select(.except, unix.connect_timeout)? except_result := s.@select(.except, unix.connect_timeout)!
if except_result { if except_result {
return net.err_connect_failed return net.err_connect_failed
} }
@ -86,11 +86,11 @@ fn (mut s StreamSocket) connect(a string) ? {
return net.err_connect_timed_out return net.err_connect_timed_out
} }
pub fn listen_stream(sock string) ?&StreamListener { pub fn listen_stream(sock string) !&StreamListener {
if sock.len >= max_sun_path { if sock.len >= max_sun_path {
return error('Socket path too long! Max length: ${max_sun_path - 1} chars.') return error('Socket path too long! Max length: ${max_sun_path - 1} chars.')
} }
mut s := new_stream_socket()? mut s := new_stream_socket()!
s.path = sock s.path = sock
mut addr := C.sockaddr_un{} mut addr := C.sockaddr_un{}
unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) } unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) }
@ -98,19 +98,19 @@ pub fn listen_stream(sock string) ?&StreamListener {
unsafe { C.strncpy(&addr.sun_path[0], &char(sock.str), max_sun_path) } unsafe { C.strncpy(&addr.sun_path[0], &char(sock.str), max_sun_path) }
size := C.SUN_LEN(&addr) size := C.SUN_LEN(&addr)
if os.exists(sock) { if os.exists(sock) {
os.rm(sock)? os.rm(sock)!
} }
net.socket_error(C.bind(s.handle, voidptr(&addr), size))? net.socket_error(C.bind(s.handle, voidptr(&addr), size))!
os.chmod(sock, 0o777)? os.chmod(sock, 0o777)!
net.socket_error(C.listen(s.handle, 128))? net.socket_error(C.listen(s.handle, 128))!
return &StreamListener{ return &StreamListener{
sock: s sock: s
} }
} }
pub fn connect_stream(path string) ?&StreamConn { pub fn connect_stream(path string) !&StreamConn {
mut s := new_stream_socket()? mut s := new_stream_socket()!
s.connect(path)? s.connect(path)!
return &StreamConn{ return &StreamConn{
sock: s sock: s
read_timeout: unix.unix_default_read_timeout read_timeout: unix.unix_default_read_timeout
@ -118,10 +118,10 @@ pub fn connect_stream(path string) ?&StreamConn {
} }
} }
pub fn (mut l StreamListener) accept() ?&StreamConn { pub fn (mut l StreamListener) accept() !&StreamConn {
mut new_handle := C.accept(l.sock.handle, 0, 0) mut new_handle := C.accept(l.sock.handle, 0, 0)
if new_handle <= 0 { if new_handle <= 0 {
l.wait_for_accept()? l.wait_for_accept()!
new_handle = C.accept(l.sock.handle, 0, 0) new_handle = C.accept(l.sock.handle, 0, 0)
if new_handle == -1 || new_handle == 0 { if new_handle == -1 || new_handle == 0 {
return error('accept failed') return error('accept failed')
@ -137,7 +137,7 @@ pub fn (mut l StreamListener) accept() ?&StreamConn {
} }
} }
pub fn (c &StreamListener) accept_deadline() ?time.Time { pub fn (c &StreamListener) accept_deadline() !time.Time {
if c.accept_deadline.unix != 0 { if c.accept_deadline.unix != 0 {
return c.accept_deadline return c.accept_deadline
} }
@ -156,21 +156,21 @@ pub fn (mut c StreamListener) set_accept_timeout(t time.Duration) {
c.accept_timeout = t c.accept_timeout = t
} }
pub fn (mut c StreamListener) wait_for_accept() ? { pub fn (mut c StreamListener) wait_for_accept() ! {
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout) return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
} }
pub fn (mut c StreamListener) close() ? { pub fn (mut c StreamListener) close() ! {
os.rm(c.sock.path)? os.rm(c.sock.path)!
c.sock.close()? c.sock.close()!
} }
pub fn (mut c StreamConn) close() ? { pub fn (mut c StreamConn) close() ! {
c.sock.close()? c.sock.close()!
} }
// write_ptr blocks and attempts to write all data // write_ptr blocks and attempts to write all data
pub fn (mut c StreamConn) write_ptr(b &u8, len int) ?int { pub fn (mut c StreamConn) write_ptr(b &u8, len int) !int {
$if trace_unix ? { $if trace_unix ? {
eprintln( eprintln(
'>>> StreamConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + '>>> StreamConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
@ -186,10 +186,10 @@ pub fn (mut c StreamConn) write_ptr(b &u8, len int) ?int {
if sent < 0 { if sent < 0 {
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_write()? c.wait_for_write()!
continue continue
} else { } else {
net.wrap_error(code)? net.wrap_error(code)!
} }
} }
total_sent += sent total_sent += sent
@ -199,17 +199,17 @@ pub fn (mut c StreamConn) write_ptr(b &u8, len int) ?int {
} }
// write blocks and attempts to write all data // write blocks and attempts to write all data
pub fn (mut c StreamConn) write(bytes []u8) ?int { pub fn (mut c StreamConn) write(bytes []u8) !int {
return c.write_ptr(bytes.data, bytes.len) return c.write_ptr(bytes.data, bytes.len)
} }
// write_string blocks and attempts to write all data // write_string blocks and attempts to write all data
pub fn (mut c StreamConn) write_string(s string) ?int { pub fn (mut c StreamConn) write_string(s string) !int {
return c.write_ptr(s.str, s.len) return c.write_ptr(s.str, s.len)
} }
pub fn (mut c StreamConn) read_ptr(buf_ptr &u8, len int) ?int { pub fn (mut c StreamConn) read_ptr(buf_ptr &u8, len int) !int {
mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))? mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
$if trace_unix ? { $if trace_unix ? {
eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
} }
@ -218,38 +218,38 @@ pub fn (mut c StreamConn) read_ptr(buf_ptr &u8, len int) ?int {
} }
code := error_code() code := error_code()
if code == int(error_ewouldblock) { if code == int(error_ewouldblock) {
c.wait_for_read()? c.wait_for_read()!
res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))? res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
$if trace_unix ? { $if trace_unix ? {
eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
} }
return net.socket_error(res) return net.socket_error(res)
} else { } else {
net.wrap_error(code)? net.wrap_error(code)!
} }
return net.socket_error(code) return net.socket_error(code)
} }
pub fn (mut c StreamConn) read(mut buf []u8) ?int { pub fn (mut c StreamConn) read(mut buf []u8) !int {
return c.read_ptr(buf.data, buf.len) return c.read_ptr(buf.data, buf.len)
} }
pub fn (mut c StreamConn) read_deadline() ?time.Time { pub fn (mut c StreamConn) read_deadline() !time.Time {
if c.read_deadline.unix == 0 { if c.read_deadline.unix == 0 {
return c.read_deadline return c.read_deadline
} }
return none return error('none')
} }
pub fn (mut c StreamConn) set_read_deadline(deadline time.Time) { pub fn (mut c StreamConn) set_read_deadline(deadline time.Time) {
c.read_deadline = deadline c.read_deadline = deadline
} }
pub fn (mut c StreamConn) write_deadline() ?time.Time { pub fn (mut c StreamConn) write_deadline() !time.Time {
if c.write_deadline.unix == 0 { if c.write_deadline.unix == 0 {
return c.write_deadline return c.write_deadline
} }
return none return error('none')
} }
pub fn (mut c StreamConn) set_write_deadline(deadline time.Time) { pub fn (mut c StreamConn) set_write_deadline(deadline time.Time) {
@ -273,12 +273,12 @@ pub fn (mut c StreamConn) set_write_timeout(t time.Duration) {
} }
[inline] [inline]
pub fn (mut c StreamConn) wait_for_read() ? { pub fn (mut c StreamConn) wait_for_read() ! {
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout) return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
} }
[inline] [inline]
pub fn (mut c StreamConn) wait_for_write() ? { pub fn (mut c StreamConn) wait_for_write() ! {
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout) return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
} }

View File

@ -27,22 +27,22 @@ fn handle_conn(mut c unix.StreamConn) {
} }
} }
fn echo_server(mut l unix.StreamListener) ? { fn echo_server(mut l unix.StreamListener) ! {
for { for {
mut new_conn := l.accept() or { continue } mut new_conn := l.accept() or { continue }
go handle_conn(mut new_conn) go handle_conn(mut new_conn)
} }
} }
fn echo() ? { fn echo() ! {
mut c := unix.connect_stream(test_port)? mut c := unix.connect_stream(test_port)!
defer { defer {
c.close() or {} c.close() or {}
} }
data := 'Hello from vlib/net!' data := 'Hello from vlib/net!'
c.write_string(data)? c.write_string(data)!
mut buf := []u8{len: 4096} mut buf := []u8{len: 4096}
read := c.read(mut buf)? read := c.read(mut buf)!
assert read == data.len assert read == data.len
for i := 0; i < read; i++ { for i := 0; i < read; i++ {
assert buf[i] == data[i] assert buf[i] == data[i]

Some files were not shown because too many files have changed in this diff Show More