From 4a0367a63c28304f64c41624e15f584fcaa101c6 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 15 Feb 2021 15:15:52 +0000 Subject: [PATCH] vlib: add [unsafe] tag to more functions: tos, string_from_wide, strings.Builder: write_bytes, free (#8766) --- cmd/tools/vdoc/html.v | 8 +++++--- cmd/tools/vsymlink.v | 4 ++-- vlib/builtin/builtin_windows.c.v | 4 ++-- vlib/builtin/rune.v | 2 +- vlib/builtin/string.v | 15 ++++++++++----- vlib/builtin/utf8.c.v | 2 ++ vlib/gg/gg.v | 2 +- vlib/json/json_primitives.v | 2 +- vlib/net/http/backend_nix.c.v | 6 +++--- vlib/net/tcp_read_line.v | 2 +- vlib/os/environment.c.v | 2 +- vlib/os/os_c.v | 12 ++++++------ vlib/os/os_nix.c.v | 4 ++-- vlib/os/os_windows.c.v | 20 +++++++++++--------- vlib/picoev/picoev.v | 2 +- vlib/picohttpparser/request.v | 18 ++++++++++++------ vlib/regex/regex.v | 2 +- vlib/sqlite/sqlite.v | 4 ++-- vlib/strconv/format.v | 4 ++-- vlib/strconv/utilities.v | 2 +- vlib/strings/builder.v | 5 +++-- vlib/v/util/util.v | 12 ++++++++---- vlib/vweb/vweb.v | 2 +- vlib/x/websocket/handshake.v | 2 +- vlib/x/websocket/utils.v | 4 ++-- 25 files changed, 82 insertions(+), 60 deletions(-) diff --git a/cmd/tools/vdoc/html.v b/cmd/tools/vdoc/html.v index 24cdcb726e..7152edf3e5 100644 --- a/cmd/tools/vdoc/html.v +++ b/cmd/tools/vdoc/html.v @@ -292,8 +292,10 @@ fn (vd VDoc) gen_html(d doc.Doc) string { } modules_toc_str := modules_toc.str() symbols_toc_str := symbols_toc.str() - modules_toc.free() - symbols_toc.free() + unsafe { + modules_toc.free() + symbols_toc.free() + } return html_content.replace('{{ title }}', d.head.name).replace('{{ head_name }}', header_name).replace('{{ version }}', version).replace('{{ light_icon }}', vd.assets['light_icon']).replace('{{ dark_icon }}', vd.assets['dark_icon']).replace('{{ menu_icon }}', vd.assets['menu_icon']).replace('{{ head_assets }}', @@ -471,7 +473,7 @@ fn doc_node_html(dn doc.DocNode, link string, head bool, include_examples bool, dnw.writeln('') dnw_str := dnw.str() defer { - dnw.free() + unsafe { dnw.free() } } return dnw_str } diff --git a/cmd/tools/vsymlink.v b/cmd/tools/vsymlink.v index 4eb2e0800f..82539299af 100644 --- a/cmd/tools/vsymlink.v +++ b/cmd/tools/vsymlink.v @@ -142,11 +142,11 @@ fn get_reg_value(reg_env_key voidptr, key string) ?string { $if windows { // query the value (shortcut the sizing step) reg_value_size := 4095 // this is the max length (not for the registry, but for the system %PATH%) - mut reg_value := &u16(malloc(reg_value_size)) + mut reg_value := unsafe { &u16(malloc(reg_value_size)) } if C.RegQueryValueEx(reg_env_key, key.to_wide(), 0, 0, reg_value, ®_value_size) != 0 { return error('Unable to get registry value for "$key", try rerunning as an Administrator') } - return string_from_wide(reg_value) + return unsafe { string_from_wide(reg_value) } } return error('not on windows') } diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index 9990278a06..127fdd3f26 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -142,14 +142,14 @@ fn print_backtrace_skipping_top_frames_msvc(skipframes int) bool { nframe := frames - i - 1 mut lineinfo := '' if C.SymGetLineFromAddr64(handle, frame_addr, &offset, &sline64) == 1 { - file_name := tos3(sline64.f_file_name) + file_name := unsafe { tos3(sline64.f_file_name) } lnumber := sline64.f_line_number lineinfo = '$file_name:$lnumber' } else { addr: lineinfo = '?? : address = 0x${(&frame_addr):x}' } - sfunc := tos3(fname) + sfunc := unsafe { tos3(fname) } eprintln('${nframe:-2d}: ${sfunc:-25s} $lineinfo') } else { // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes diff --git a/vlib/builtin/rune.v b/vlib/builtin/rune.v index acfc66efcf..8cbb45acc8 100644 --- a/vlib/builtin/rune.v +++ b/vlib/builtin/rune.v @@ -51,6 +51,6 @@ pub fn (b []byte) bytestr() string { fn bytes2string(b []byte) string { mut copy := b.clone() copy << `\0` - res := tos(copy.data, copy.len-1) + res := unsafe { tos(copy.data, copy.len-1) } return res } diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 5687f7b222..7e2a14b77a 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -73,7 +73,7 @@ pub fn vstrlen(s byteptr) int { // tos converts a C string to a V string. // String data is reused, not copied. -//[unsafe] +[unsafe] pub fn tos(s byteptr, len int) string { // This should never happen. if s == 0 { @@ -86,12 +86,14 @@ pub fn tos(s byteptr, len int) string { } // tos_clone returns a copy of `s`. +[unsafe] pub fn tos_clone(s byteptr) string { - return tos2(s).clone() + return unsafe { tos2(s) }.clone() } // tos2 does the same as `tos`, but also calculates the length. Called by `string(bytes)` casts. // Used only internally. +[unsafe] pub fn tos2(s byteptr) string { if s == 0 { panic('tos2: nil string') @@ -103,6 +105,7 @@ pub fn tos2(s byteptr) string { } // tos3 does the same as `tos2`, but for char*, to avoid warnings. +[unsafe] pub fn tos3(s charptr) string { if s == 0 { panic('tos3: nil string') @@ -114,19 +117,21 @@ pub fn tos3(s charptr) string { } // tos4 does the same as `tos2`, but returns an empty string on nil ptr. +[unsafe] pub fn tos4(s byteptr) string { if s == 0 { return '' } - return tos2(s) + return unsafe { tos2(s) } } // tos5 does the same as `tos4`, but for char*, to avoid warnings. +[unsafe] pub fn tos5(s charptr) string { if s == 0 { return '' } - return tos3(s) + return unsafe { tos3(s) } } [deprecated] @@ -207,7 +212,7 @@ pub fn (s string) cstr() byteptr { // cstring_to_vstring creates a copy of cstr and turns it into a v string. [unsafe] pub fn cstring_to_vstring(cstr byteptr) string { - return tos_clone(cstr) + return unsafe { tos_clone(cstr) } } // replace_once replaces the first occurence of `rep` with the string passed in `with`. diff --git a/vlib/builtin/utf8.c.v b/vlib/builtin/utf8.c.v index a6cc2e3896..8fb3c921a9 100644 --- a/vlib/builtin/utf8.c.v +++ b/vlib/builtin/utf8.c.v @@ -21,6 +21,7 @@ pub fn (_str string) to_wide() &u16 { } } +[unsafe] pub fn string_from_wide(_wstr &u16) string { $if windows { unsafe { @@ -32,6 +33,7 @@ pub fn string_from_wide(_wstr &u16) string { } } +[unsafe] pub fn string_from_wide2(_wstr &u16, len int) string { $if windows { unsafe { diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index e049158bf0..75f15ba03a 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -249,7 +249,7 @@ fn gg_cleanup_fn(user_data voidptr) { fn gg_fail_fn(msg charptr, user_data voidptr) { mut g := unsafe { &Context(user_data) } - vmsg := tos3(msg) + vmsg := unsafe { tos3(msg) } if g.config.fail_fn != voidptr(0) { g.config.fail_fn(vmsg, g.config.user_data) } else { diff --git a/vlib/json/json_primitives.v b/vlib/json/json_primitives.v index b43dedda1e..9d83eb15cd 100644 --- a/vlib/json/json_primitives.v +++ b/vlib/json/json_primitives.v @@ -108,7 +108,7 @@ fn decode_string(root &C.cJSON) string { } // println('decode string valuestring="$root.valuestring"') // return tos(root.valuestring, _strlen(root.valuestring)) - return tos_clone(root.valuestring) // , _strlen(root.valuestring)) + return unsafe { tos_clone(root.valuestring) } // , _strlen(root.valuestring)) } fn C.cJSON_IsTrue(voidptr) bool diff --git a/vlib/net/http/backend_nix.c.v b/vlib/net/http/backend_nix.c.v index b580f5cbf3..cae10849de 100644 --- a/vlib/net/http/backend_nix.c.v +++ b/vlib/net/http/backend_nix.c.v @@ -45,17 +45,17 @@ fn (req &Request) ssl_do(port int, method Method, host_name string, path string) mut readcounter := 0 for { readcounter++ - len := C.BIO_read(web, buff, bufsize) + len := unsafe { C.BIO_read(web, buff, bufsize) } if len <= 0 { break } $if debug_http ? { eprintln('ssl_do, read ${readcounter:4d} | len: $len') eprintln('-'.repeat(20)) - eprintln(tos(buff, len)) + eprintln(unsafe { tos(buff, len) }) eprintln('-'.repeat(20)) } - content.write_bytes(buff, len) + unsafe { content.write_bytes(buff, len) } } if web != 0 { C.BIO_free_all(web) diff --git a/vlib/net/tcp_read_line.v b/vlib/net/tcp_read_line.v index cd78953e50..38cbdeb199 100644 --- a/vlib/net/tcp_read_line.v +++ b/vlib/net/tcp_read_line.v @@ -35,7 +35,7 @@ pub fn (mut con TcpConn) read_line() string { } } bufbp := byteptr(buf) - line = tos_clone(bufbp) + line = unsafe { tos_clone(bufbp) } if eol_idx > 0 { // At this point, we are sure that recv returned valid data, // that contains *at least* one line. diff --git a/vlib/os/environment.c.v b/vlib/os/environment.c.v index 705833b653..ff7173ab42 100644 --- a/vlib/os/environment.c.v +++ b/vlib/os/environment.c.v @@ -72,7 +72,7 @@ pub fn environ() map[string]string { mut estrings := C.GetEnvironmentStringsW() mut eline := '' for c := estrings; *c != 0; { - eline = string_from_wide(c) + eline = unsafe { string_from_wide(c) } eq_index := eline.index_byte(`=`) if eq_index > 0 { res[eline[0..eq_index]] = eline[eq_index + 1..] diff --git a/vlib/os/os_c.v b/vlib/os/os_c.v index 31616091e3..eed279db1e 100644 --- a/vlib/os/os_c.v +++ b/vlib/os/os_c.v @@ -319,7 +319,7 @@ pub fn posix_get_error_msg(code int) string { if ptr_text == 0 { return '' } - return tos3(ptr_text) + return unsafe { tos3(ptr_text) } } // vpclose will close a file pointer opened with `vpopen`. @@ -463,7 +463,7 @@ pub fn rmdir(path string) ? { // print_c_errno will print the current value of `C.errno`. fn print_c_errno() { e := C.errno - se := tos_clone(byteptr(C.strerror(C.errno))) + se := unsafe { tos_clone(byteptr(C.strerror(C.errno))) } println('errno=$e err=$se') } @@ -498,12 +498,12 @@ pub fn get_raw_line() string { } $else { max := size_t(0) mut buf := charptr(0) - nr_chars := C.getline(&buf, &max, C.stdin) + nr_chars := unsafe { C.getline(&buf, &max, C.stdin) } // defer { unsafe{ free(buf) } } if nr_chars == 0 || nr_chars == -1 { return '' } - return tos3(buf) + return unsafe { tos3(buf) } // res := tos_clone(buf) // return res } @@ -610,7 +610,7 @@ pub fn executable() string { // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew final_len := C.GetFinalPathNameByHandleW(file, final_path, size, 0) if final_len < size { - ret := string_from_wide2(final_path, final_len) + ret := unsafe { string_from_wide2(final_path, final_len) } // remove '\\?\' from beginning (see link above) return ret[4..] } else { @@ -619,7 +619,7 @@ pub fn executable() string { } C.CloseHandle(file) } - return string_from_wide2(result, len) + return unsafe { string_from_wide2(result, len) } } $if macos { mut result := vcalloc(max_path_len) diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index fde3160424..7aa500b3ed 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -82,7 +82,7 @@ fn init_os_args(argc int, argv &&byte) []string { pub fn ls(path string) ?[]string { mut res := []string{} - dir := C.opendir(charptr(path.str)) + dir := unsafe { C.opendir(charptr(path.str)) } if isnil(dir) { return error('ls() couldnt open dir "$path"') } @@ -99,8 +99,8 @@ pub fn ls(path string) ?[]string { || (bptr[0] == `.` && bptr[1] == `.` && bptr[2] == 0) { continue } + res << tos_clone(bptr) } - res << tos_clone(bptr) } C.closedir(dir) return res diff --git a/vlib/os/os_windows.c.v b/vlib/os/os_windows.c.v index 8017dac138..ad7d119565 100644 --- a/vlib/os/os_windows.c.v +++ b/vlib/os/os_windows.c.v @@ -79,7 +79,7 @@ mut: fn init_os_args_wide(argc int, argv &byteptr) []string { mut args_ := []string{} for i in 0 .. argc { - args_ << string_from_wide(unsafe { &u16(argv[i]) }) + args_ << unsafe { string_from_wide(&u16(argv[i])) } } return args_ } @@ -102,12 +102,12 @@ pub fn ls(path string) ?[]string { // NOTE:TODO: once we have a way to convert utf16 wide character to utf8 // we should use FindFirstFileW and FindNextFileW h_find_files := C.FindFirstFile(path_files.to_wide(), voidptr(&find_file_data)) - first_filename := string_from_wide(&u16(find_file_data.c_file_name)) + first_filename := unsafe { string_from_wide(&u16(find_file_data.c_file_name)) } if first_filename != '.' && first_filename != '..' { dir_files << first_filename } for C.FindNextFile(h_find_files, voidptr(&find_file_data)) > 0 { - filename := string_from_wide(&u16(find_file_data.c_file_name)) + filename := unsafe { string_from_wide(&u16(find_file_data.c_file_name)) } if filename != '.' && filename != '..' { dir_files << filename.clone() } @@ -218,7 +218,7 @@ pub fn get_error_msg(code int) string { if ptr_text == 0 { // compare with null return '' } - return string_from_wide(ptr_text) + return unsafe { string_from_wide(ptr_text) } } // exec starts the specified command, waits for it to complete, and returns its output. @@ -273,15 +273,17 @@ pub fn exec(cmd string) ?Result { mut bytes_read := u32(0) mut read_data := strings.new_builder(1024) for { - readfile_result := C.ReadFile(child_stdout_read, buf, 1000, voidptr(&bytes_read), - 0) - read_data.write_bytes(buf, int(bytes_read)) - if readfile_result == false || int(bytes_read) == 0 { + mut result := false + unsafe { + result = C.ReadFile(child_stdout_read, buf, 1000, voidptr(&bytes_read), 0) + read_data.write_bytes(buf, int(bytes_read)) + } + if result == false || int(bytes_read) == 0 { break } } soutput := read_data.str().trim_space() - read_data.free() + unsafe { read_data.free() } exit_code := u32(0) C.WaitForSingleObject(proc_info.h_process, C.INFINITE) C.GetExitCodeProcess(proc_info.h_process, voidptr(&exit_code)) diff --git a/vlib/picoev/picoev.v b/vlib/picoev/picoev.v index 07ba1b9ce8..6b7825dbd2 100644 --- a/vlib/picoev/picoev.v +++ b/vlib/picoev/picoev.v @@ -170,7 +170,7 @@ fn rw_callback(loop &C.picoev_loop, fd int, events int, cb_arg voidptr) { } } else { r += idx - mut s := tos(buf, r) + mut s := unsafe { tos(buf, r) } mut out := p.out unsafe { out += fd * max_write diff --git a/vlib/picohttpparser/request.v b/vlib/picohttpparser/request.v index 9d8a182dd5..573cfd3076 100644 --- a/vlib/picohttpparser/request.v +++ b/vlib/picohttpparser/request.v @@ -28,8 +28,10 @@ pub fn (mut r Request) parse_request(s string, max_headers int) int { 0 ) if pret > 0 { - r.method = tos(r.method.str, int(method_len)) - r.path = tos(r.path.str, int(path_len)) + unsafe { + r.method = tos(r.method.str, int(method_len)) + r.path = tos(r.path.str, int(path_len)) + } r.num_headers = num_headers } return pret @@ -46,8 +48,10 @@ pub fn (mut r Request) parse_request_path(s string) int { &r.path, &path_len ) if pret > 0 { - r.method = tos(r.method.str, int(method_len)) - r.path = tos(r.path.str, int(path_len)) + unsafe { + r.method = tos(r.method.str, int(method_len)) + r.path = tos(r.path.str, int(path_len)) + } } return pret } @@ -63,8 +67,10 @@ pub fn (mut r Request) parse_request_path_pipeline(s string) int { &r.path, &path_len ) if pret > 0 { - r.method = tos(r.method.str, int(method_len)) - r.path = tos(r.path.str, int(path_len)) + unsafe { + r.method = tos(r.method.str, int(method_len)) + r.path = tos(r.path.str, int(path_len)) + } } return pret } diff --git a/vlib/regex/regex.v b/vlib/regex/regex.v index aec86d71e0..dfaca4a9af 100644 --- a/vlib/regex/regex.v +++ b/vlib/regex/regex.v @@ -530,7 +530,7 @@ fn (re RE) get_char_class(pc int) string { buf_ptr[i] = byte(0) } - return tos_clone( buf_ptr ) + return unsafe { tos_clone( buf_ptr ) } } fn (re RE) check_char_class(pc int, ch rune) bool { diff --git a/vlib/sqlite/sqlite.v b/vlib/sqlite/sqlite.v index f7a6139a22..2ed929011a 100644 --- a/vlib/sqlite/sqlite.v +++ b/vlib/sqlite/sqlite.v @@ -123,7 +123,7 @@ pub fn (db DB) q_string(query string) string { stmt := &C.sqlite3_stmt(0) C.sqlite3_prepare_v2(db.conn, query.str, -1, &stmt, 0) C.sqlite3_step(stmt) - res := tos_clone(C.sqlite3_column_text(stmt, 0)) + res := unsafe { tos_clone(C.sqlite3_column_text(stmt, 0)) } C.sqlite3_finalize(stmt) return res } @@ -145,7 +145,7 @@ pub fn (db DB) exec(query string) ([]Row, int) { } mut row := Row{} for i in 0 .. nr_cols { - val := tos_clone(C.sqlite3_column_text(stmt, i)) + val := unsafe { tos_clone(C.sqlite3_column_text(stmt, i)) } row.vals << val } rows << row diff --git a/vlib/strconv/format.v b/vlib/strconv/format.v index ba16e87818..d76ec93b24 100644 --- a/vlib/strconv/format.v +++ b/vlib/strconv/format.v @@ -183,7 +183,7 @@ pub fn f64_to_str_lnd(f f64, dec_digit int) string { } res[r_i] = 0 //println("result: [${tos(&res[0],r_i)}]") - return tos(res.data, r_i) + return unsafe { tos(res.data, r_i) } } else { if dec_digit > 0 { mut c := 0 @@ -194,7 +194,7 @@ pub fn f64_to_str_lnd(f f64, dec_digit int) string { } res[r_i] = 0 } - return tos(res.data, r_i) + return unsafe { tos(res.data, r_i) } } } diff --git a/vlib/strconv/utilities.v b/vlib/strconv/utilities.v index 048635afdb..d9d24d8a74 100644 --- a/vlib/strconv/utilities.v +++ b/vlib/strconv/utilities.v @@ -336,5 +336,5 @@ pub fn f64_to_str_l(f f64) string { } } res[r_i] = 0 - return tos(res.data,r_i) + return unsafe { tos(res.data,r_i) } } diff --git a/vlib/strings/builder.v b/vlib/strings/builder.v index ce4b6d3acc..dbf0313c61 100644 --- a/vlib/strings/builder.v +++ b/vlib/strings/builder.v @@ -27,6 +27,7 @@ pub fn new_builder(initial_size int) Builder { } // write_bytes appends `bytes` to the accumulated buffer +[unsafe] pub fn (mut b Builder) write_bytes(bytes byteptr, howmany int) { b.buf.push_many(bytes, howmany) b.len += howmany @@ -61,8 +62,7 @@ pub fn (mut b Builder) go_back(n int) { fn bytes2string(b []byte) string { mut copy := b.clone() copy << byte(`\0`) - res := tos(copy.data, copy.len - 1) - return res + return unsafe { tos(copy.data, copy.len - 1) } } // cut_last cuts the last `n` bytes from the buffer and returns them @@ -137,6 +137,7 @@ pub fn (mut b Builder) str() string { } // free - manually free the contents of the buffer +[unsafe] pub fn (mut b Builder) free() { unsafe { free(b.buf.data) } // b.buf = []byte{cap: b.initial_size} diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 07c46ef869..9943edcf00 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -29,8 +29,10 @@ pub const ( pub fn vhash() string { mut buf := [50]byte{} buf[0] = 0 - unsafe { C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) } - return tos_clone(buf) + unsafe { + C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) + return tos_clone(buf) + } } pub fn full_hash() string { @@ -95,8 +97,10 @@ pub fn githash(should_get_from_filesystem bool) string { } mut buf := [50]byte{} buf[0] = 0 - unsafe { C.snprintf(charptr(buf), 50, '%s', C.V_CURRENT_COMMIT_HASH) } - return tos_clone(buf) + unsafe { + C.snprintf(charptr(buf), 50, '%s', C.V_CURRENT_COMMIT_HASH) + return tos_clone(buf) + } } // diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 98708669c2..5cd81677e6 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -96,7 +96,7 @@ pub fn (mut ctx Context) send_response_to_client(mimetype string, res string) bo ctx.done = true mut sb := strings.new_builder(1024) defer { - sb.free() + unsafe { sb.free() } } sb.write('HTTP/1.1 $ctx.status') sb.write('\r\nContent-Type: $mimetype') diff --git a/vlib/x/websocket/handshake.v b/vlib/x/websocket/handshake.v index e285124cd4..518ff2f39f 100644 --- a/vlib/x/websocket/handshake.v +++ b/vlib/x/websocket/handshake.v @@ -10,7 +10,7 @@ fn (mut ws Client) handshake() ? { seckey := base64.encode(nonce) mut sb := strings.new_builder(1024) defer { - sb.free() + unsafe { sb.free() } } sb.write('GET ') sb.write(ws.uri.resource) diff --git a/vlib/x/websocket/utils.v b/vlib/x/websocket/utils.v index 97e201b879..ed26db6894 100644 --- a/vlib/x/websocket/utils.v +++ b/vlib/x/websocket/utils.v @@ -35,7 +35,7 @@ fn create_key_challenge_response(seckey string) ?string { sha1buf := seckey + guid shabytes := sha1buf.bytes() hash := sha1.sum(shabytes) - b64 := base64.encode(tos(hash.data, hash.len)) + b64 := base64.encode(unsafe { tos(hash.data, hash.len) }) unsafe { hash.free() shabytes.free() @@ -50,5 +50,5 @@ fn get_nonce(nonce_size int) string { for i in 0 .. nonce_size { nonce[i] = alphanum[rand.intn(alphanum.len)] } - return tos(nonce.data, nonce.len).clone() + return unsafe { tos(nonce.data, nonce.len) }.clone() }