mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
Merge branch 'vlang:master' into sqlite3_exec_param
This commit is contained in:
commit
9e8d6aada5
1
.github/workflows/macos_ci.yml
vendored
1
.github/workflows/macos_ci.yml
vendored
@ -97,6 +97,7 @@ jobs:
|
||||
mkdir -p ~/.vmodules
|
||||
ln -s $(pwd) ~/.vmodules/ui
|
||||
../v examples/rectangles.v
|
||||
../v examples/users.v
|
||||
## ../v run examples/build_examples.vsh
|
||||
- name: V self compilation with -usecache
|
||||
run: |
|
||||
|
@ -9,7 +9,7 @@ import semver
|
||||
|
||||
const (
|
||||
tool_name = os.file_name(os.executable())
|
||||
tool_version = '0.0.1'
|
||||
tool_version = '0.1.0'
|
||||
tool_description = '\n Bump the semantic version of the v.mod and/or specified files.
|
||||
|
||||
The first instance of a version number is replaced with the new version.
|
||||
@ -21,6 +21,11 @@ const (
|
||||
version: \'0.2.42\'
|
||||
VERSION = "1.23.8"
|
||||
|
||||
If certain lines need to be skipped, use the --skip option. For instance,
|
||||
the following command will skip lines containing "tool-version":
|
||||
|
||||
v bump --patch --skip "tool-version" [files...]
|
||||
|
||||
Examples:
|
||||
Bump the patch version in v.mod if it exists
|
||||
v bump --patch
|
||||
@ -37,6 +42,7 @@ struct Options {
|
||||
major bool
|
||||
minor bool
|
||||
patch bool
|
||||
skip string
|
||||
}
|
||||
|
||||
type ReplacementFunction = fn (re regex.RE, input string, start int, end int) string
|
||||
@ -67,10 +73,10 @@ fn get_replacement_function(options Options) ReplacementFunction {
|
||||
return replace_with_increased_patch_version
|
||||
}
|
||||
|
||||
fn process_file(input_file string, options Options) {
|
||||
lines := os.read_lines(input_file) or { panic('Failed to read file: ${input_file}') }
|
||||
fn process_file(input_file string, options Options) ! {
|
||||
lines := os.read_lines(input_file) or { return error('Failed to read file: ${input_file}') }
|
||||
|
||||
mut re := regex.regex_opt(semver_query) or { panic('Could not create a RegEx parser.') }
|
||||
mut re := regex.regex_opt(semver_query) or { return error('Could not create a RegEx parser.') }
|
||||
|
||||
repl_fn := get_replacement_function(options)
|
||||
|
||||
@ -85,7 +91,8 @@ fn process_file(input_file string, options Options) {
|
||||
}
|
||||
|
||||
// Check if replacement is necessary
|
||||
updated_line := if line.to_lower().contains('version') {
|
||||
updated_line := if line.to_lower().contains('version') && !(options.skip != ''
|
||||
&& line.contains(options.skip)) {
|
||||
replacement_complete = true
|
||||
re.replace_by_fn(line, repl_fn)
|
||||
} else {
|
||||
@ -103,11 +110,11 @@ fn process_file(input_file string, options Options) {
|
||||
os.rm(backup_file) or {}
|
||||
|
||||
// Rename the original to the backup.
|
||||
os.mv(input_file, backup_file) or { panic('Failed to copy file: ${input_file}') }
|
||||
os.mv(input_file, backup_file) or { return error('Failed to copy file: ${input_file}') }
|
||||
|
||||
// Process the old file and write it back to the original.
|
||||
os.write_file(input_file, new_lines.join_lines()) or {
|
||||
panic('Failed to write file: ${input_file}')
|
||||
return error('Failed to write file: ${input_file}')
|
||||
}
|
||||
|
||||
// Remove the backup file.
|
||||
@ -122,7 +129,7 @@ fn process_file(input_file string, options Options) {
|
||||
|
||||
fn main() {
|
||||
if os.args.len < 2 {
|
||||
println('Usage: ${tool_name} [options] [file1 file2 ...]
|
||||
eprintln('Usage: ${tool_name} [options] [file1 file2 ...]
|
||||
${tool_description}
|
||||
Try ${tool_name} -h for more help...')
|
||||
exit(1)
|
||||
@ -141,6 +148,12 @@ Try ${tool_name} -h for more help...')
|
||||
patch: fp.bool('patch', `p`, false, 'Bump the patch version.')
|
||||
minor: fp.bool('minor', `n`, false, 'Bump the minor version.')
|
||||
major: fp.bool('major', `m`, false, 'Bump the major version.')
|
||||
skip: fp.string('skip', `s`, '', 'Skip lines matching this substring.').trim_space()
|
||||
}
|
||||
|
||||
remaining := fp.finalize() or {
|
||||
eprintln(fp.usage())
|
||||
exit(1)
|
||||
}
|
||||
|
||||
if options.show_help {
|
||||
@ -148,24 +161,33 @@ Try ${tool_name} -h for more help...')
|
||||
exit(0)
|
||||
}
|
||||
|
||||
validate_options(options) or { panic(err) }
|
||||
validate_options(options) or {
|
||||
eprintln(fp.usage())
|
||||
exit(1)
|
||||
}
|
||||
|
||||
files := os.args[3..]
|
||||
files := remaining[1..]
|
||||
|
||||
if files.len == 0 {
|
||||
if !os.exists('v.mod') {
|
||||
println('v.mod does not exist. You can create one using "v init".')
|
||||
eprintln('v.mod does not exist. You can create one using "v init".')
|
||||
exit(1)
|
||||
}
|
||||
process_file('v.mod', options) or {
|
||||
eprintln('Failed to process v.mod: ${err}')
|
||||
exit(1)
|
||||
}
|
||||
process_file('v.mod', options)
|
||||
}
|
||||
|
||||
for input_file in files {
|
||||
if !os.exists(input_file) {
|
||||
println('File not found: ${input_file}')
|
||||
eprintln('File not found: ${input_file}')
|
||||
exit(1)
|
||||
}
|
||||
process_file(input_file, options) or {
|
||||
eprintln('Failed to process ${input_file}: ${err}')
|
||||
exit(1)
|
||||
}
|
||||
process_file(input_file, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ fn run_individual_test(case BumpTestCase) ! {
|
||||
|
||||
os.rm(test_file) or {}
|
||||
os.write_file(test_file, case.contents)!
|
||||
//
|
||||
|
||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --patch ${os.quoted_path(test_file)}')
|
||||
patch_lines := os.read_lines(test_file)!
|
||||
assert patch_lines[case.line] == case.expected_patch
|
||||
@ -90,7 +90,7 @@ fn run_individual_test(case BumpTestCase) ! {
|
||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --major ${os.quoted_path(test_file)}')
|
||||
major_lines := os.read_lines(test_file)!
|
||||
assert major_lines[case.line] == case.expected_major
|
||||
//
|
||||
|
||||
os.rm(test_file)!
|
||||
}
|
||||
|
||||
@ -99,3 +99,65 @@ fn test_all_bump_cases() {
|
||||
run_individual_test(case) or { panic(err) }
|
||||
}
|
||||
}
|
||||
|
||||
struct SkipTestCase {
|
||||
file_name string
|
||||
contents string
|
||||
skip string
|
||||
line int
|
||||
expected_patch string
|
||||
expected_minor string
|
||||
expected_major string
|
||||
}
|
||||
|
||||
const skip_test_cases = [
|
||||
SkipTestCase{
|
||||
file_name: 'CITATION.cff'
|
||||
contents: 'abstract: A sample CLI tool made in V that prints geometric shapes to the screen.
|
||||
authors:
|
||||
- alias: hungrybluedev
|
||||
family-names: Haldar
|
||||
given-names: Subhomoy
|
||||
cff-version: 1.2.0
|
||||
date-released: 2023-04-20
|
||||
license: MIT
|
||||
message: Please cite this software using these information.
|
||||
repository-code: https://github.com/hungrybluedev/geo
|
||||
title: geo
|
||||
url: https://github.com/hungrybluedev/geo
|
||||
version: 0.2.4
|
||||
'
|
||||
line: 12
|
||||
skip: 'cff-version'
|
||||
expected_patch: 'version: 0.2.5'
|
||||
expected_minor: 'version: 0.3.0'
|
||||
expected_major: 'version: 1.0.0'
|
||||
},
|
||||
]
|
||||
|
||||
fn run_skip_test(case SkipTestCase) ! {
|
||||
test_file := os.join_path_single(tfolder, case.file_name)
|
||||
|
||||
os.rm(test_file) or {}
|
||||
os.write_file(test_file, case.contents)!
|
||||
|
||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --patch --skip="${case.skip}" ${os.quoted_path(test_file)}')
|
||||
patch_lines := os.read_lines(test_file)!
|
||||
assert patch_lines[case.line] == case.expected_patch
|
||||
|
||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --minor --skip="${case.skip}" ${os.quoted_path(test_file)}')
|
||||
minor_lines := os.read_lines(test_file)!
|
||||
assert minor_lines[case.line] == case.expected_minor
|
||||
|
||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --major --skip="${case.skip}" ${os.quoted_path(test_file)}')
|
||||
major_lines := os.read_lines(test_file)!
|
||||
assert major_lines[case.line] == case.expected_major
|
||||
|
||||
os.rm(test_file)!
|
||||
}
|
||||
|
||||
fn test_all_skip_bump_cases() ! {
|
||||
for case in skip_test_cases {
|
||||
run_skip_test(case) or { panic(err) }
|
||||
}
|
||||
}
|
||||
|
@ -74,12 +74,12 @@ fn on_frame(mut app App) {
|
||||
// draw minute hand
|
||||
mut j := f32(n.minute)
|
||||
if n.second == 59 { // make minute hand move smoothly
|
||||
j += f32(math.sin(f32(n.microsecond) / 1e6 * math.pi / 2.0))
|
||||
j += f32(math.sin(f32(n.nanosecond) / 1e9 * math.pi / 2.0))
|
||||
}
|
||||
draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.minute_hand, hand_color, j * 6)
|
||||
|
||||
// draw second hand with smooth transition
|
||||
k := f32(n.second) + f32(math.sin(f32(n.microsecond) / 1e6 * math.pi / 2.0))
|
||||
k := f32(n.second) + f32(math.sin(f32(n.nanosecond) / 1e9 * math.pi / 2.0))
|
||||
draw_convex_poly_rotate(mut app.gg, app.dpi_scale, app.second_hand, second_hand_color,
|
||||
0 + k * 6)
|
||||
|
||||
|
230
vlib/os/notify/backend_darwin.c.v
Normal file
230
vlib/os/notify/backend_darwin.c.v
Normal file
@ -0,0 +1,230 @@
|
||||
module notify
|
||||
|
||||
import time
|
||||
import os
|
||||
|
||||
#insert "@VEXEROOT/vlib/os/notify/kqueue.h"
|
||||
|
||||
struct C.kevent {
|
||||
mut:
|
||||
ident u32
|
||||
filter i16
|
||||
flags u16
|
||||
fflags u32
|
||||
data int
|
||||
udata voidptr
|
||||
}
|
||||
|
||||
fn C.kqueue() int
|
||||
fn C.__kevent__(int, voidptr, int, voidptr, int, voidptr) int
|
||||
fn C.EV_SET(voidptr, u32, i16, u16, u32, int, voidptr)
|
||||
|
||||
// KqueueNotifier provides methods that implement FdNotifier using the
|
||||
// kqueue I/O event notification facility (macos, freeBSD, xxxBSD...unix only)
|
||||
[noinit]
|
||||
struct KqueueNotifier {
|
||||
kqueue_fd int
|
||||
}
|
||||
|
||||
// KqueueEvent describes an event that occurred for a file descriptor in
|
||||
// the watch list
|
||||
[noinit]
|
||||
struct KqueueEvent {
|
||||
pub:
|
||||
fd int
|
||||
kind FdEventType
|
||||
}
|
||||
|
||||
// new creates a new KqueueNotifier
|
||||
// The FdNotifier interface is returned to allow OS specific
|
||||
// implementations without exposing the concrete type
|
||||
pub fn new() !FdNotifier {
|
||||
fd := C.kqueue()
|
||||
if fd == -1 {
|
||||
return error(os.posix_get_error_msg(C.errno))
|
||||
}
|
||||
// Needed to circumvent V limitations
|
||||
x := &KqueueNotifier{
|
||||
kqueue_fd: fd
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
const (
|
||||
// filter types
|
||||
kqueue_read = i16(C.EVFILT_READ)
|
||||
kqueue_write = i16(C.EVFILT_WRITE)
|
||||
kqueue_aio = i16(C.EVFILT_AIO)
|
||||
kqueue_vnode = i16(C.EVFILT_VNODE)
|
||||
kqueue_proc = i16(C.EVFILT_PROC)
|
||||
kqueue_signal = i16(C.EVFILT_SIGNAL)
|
||||
kqueue_timer = i16(C.EVFILT_TIMER)
|
||||
kqueue_machport = i16(C.EVFILT_MACHPORT)
|
||||
kqueue_fs = i16(C.EVFILT_FS)
|
||||
kqueue_user = i16(C.EVFILT_USER)
|
||||
kqueue_vm = i16(C.EVFILT_VM)
|
||||
kqueue_exception = i16(C.EVFILT_EXCEPT)
|
||||
kqueue_syscount = i16(C.EVFILT_SYSCOUNT)
|
||||
|
||||
// actions
|
||||
kqueue_add = u16(C.EV_ADD)
|
||||
kqueue_delete = u16(C.EV_DELETE)
|
||||
kqueue_enable = u16(C.EV_ENABLE)
|
||||
kqueue_disable = u16(C.EV_DISABLE)
|
||||
|
||||
// flags
|
||||
kqueue_oneshot = u16(C.EV_ONESHOT)
|
||||
kqueue_edge_trigger = u16(C.EV_CLEAR) // kqueue_clear
|
||||
kqueue_receipt = u16(C.EV_RECEIPT)
|
||||
kqueue_dispatch = u16(C.EV_DISPATCH)
|
||||
kqueue_udata_specific = u16(C.EV_UDATA_SPECIFIC)
|
||||
kqueue_dispatch2 = u16(C.EV_DISPATCH | C.EV_UDATA_SPECIFIC)
|
||||
kqueue_vanished = u16(C.EV_VANISHED)
|
||||
kqueue_sysflags = u16(C.EV_SYSFLAGS)
|
||||
kqueue_flag0 = u16(C.EV_FLAG0)
|
||||
kqueue_flag1 = u16(C.EV_FLAG1)
|
||||
|
||||
// returned values
|
||||
kqueue_eof = u16(C.EV_EOF)
|
||||
kqueue_error = u16(C.EV_ERROR)
|
||||
)
|
||||
|
||||
// ctl is a helper method for add, modify, and remove
|
||||
fn (mut kn KqueueNotifier) ctl(fd int, filter i16, flags u16) ! {
|
||||
event := [1]C.kevent{}
|
||||
C.EV_SET(&event[0], fd, filter, flags, 0, 0, unsafe { nil })
|
||||
if C.__kevent__(kn.kqueue_fd, &event[0], 1, unsafe { nil }, 0, unsafe { nil }) == -1 {
|
||||
return error(os.posix_get_error_msg(C.errno))
|
||||
}
|
||||
}
|
||||
|
||||
// add adds a file descriptor to the watch list
|
||||
fn (mut kn KqueueNotifier) add(fd int, events FdEventType, conf ...FdConfigFlags) ! {
|
||||
filter := filter_to_mask(events)
|
||||
flags := flags_to_mask(...conf)
|
||||
kn.ctl(fd, filter, flags)!
|
||||
}
|
||||
|
||||
// modify sets an existing entry in the watch list to the provided events and configuration
|
||||
fn (mut kn KqueueNotifier) modify(fd int, events FdEventType, conf ...FdConfigFlags) ! {
|
||||
kn.add(fd, events, ...conf)!
|
||||
}
|
||||
|
||||
// remove removes a file descriptor from the watch list
|
||||
fn (mut kn KqueueNotifier) remove(fd int) ! {
|
||||
filter := notify.kqueue_read | notify.kqueue_write | notify.kqueue_exception
|
||||
flags := notify.kqueue_delete
|
||||
kn.ctl(fd, filter, flags)!
|
||||
}
|
||||
|
||||
// wait waits to be notified of events on the watch list,
|
||||
// returns at most 512 events
|
||||
fn (mut kn KqueueNotifier) wait(timeout time.Duration) []FdEvent {
|
||||
// arbitrary 512 limit; events will round robin on successive
|
||||
// waits if the number exceeds this
|
||||
// NOTE: we use a fixed size array here for stack allocation; this has
|
||||
// the added bonus of making KqueueNotifier thread safe
|
||||
events := [512]C.kevent{}
|
||||
// populate events with the new events
|
||||
to := &C.timespec{0, timeout.nanoseconds()}
|
||||
count := C.__kevent__(kn.kqueue_fd, unsafe { nil }, 0, &events[0], events.len, to)
|
||||
|
||||
if count > 0 {
|
||||
mut arr := []FdEvent{cap: count}
|
||||
for i := 0; i < count; i++ {
|
||||
fd := int(events[i].ident)
|
||||
kind := event_mask_to_flag(events[i].filter, events[i].flags)
|
||||
if kind.is_empty() {
|
||||
// NOTE: tcc only reports the first event for some
|
||||
// reason, leaving subsequent structs in the array as 0
|
||||
// (or possibly garbage)
|
||||
panic('encountered an empty event kind; this is most likely due to using tcc')
|
||||
}
|
||||
arr << &KqueueEvent{
|
||||
fd: fd
|
||||
kind: kind
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
// close closes the KqueueNotifier,
|
||||
// any successive calls to add, modify, remove, and wait should fail
|
||||
fn (mut kn KqueueNotifier) close() ! {
|
||||
if C.close(kn.kqueue_fd) == -1 {
|
||||
return error(os.posix_get_error_msg(C.errno))
|
||||
}
|
||||
}
|
||||
|
||||
// event_mask_to_flag is a helper function that converts a bitmask
|
||||
// returned by kevent() wait to FdEventType
|
||||
fn event_mask_to_flag(filter i16, flags u16) FdEventType {
|
||||
mut res := FdEventType.read
|
||||
|
||||
if filter & notify.kqueue_read != 0 {
|
||||
res.set(.read)
|
||||
}
|
||||
if filter & notify.kqueue_write != 0 {
|
||||
res.set(.write)
|
||||
}
|
||||
if filter & notify.kqueue_exception != 0 {
|
||||
res.set(.exception)
|
||||
}
|
||||
|
||||
if flags & notify.kqueue_eof != 0 {
|
||||
res.set(.hangup)
|
||||
}
|
||||
if flags & notify.kqueue_error != 0 {
|
||||
res.set(.error)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// filter_to_mask is a helper function that converts FdEventType
|
||||
// to a bitmask used by the C functions
|
||||
fn filter_to_mask(events FdEventType) i16 {
|
||||
mut mask := i16(0)
|
||||
if events.has(.read) {
|
||||
mask |= notify.kqueue_read
|
||||
}
|
||||
if events.has(.write) {
|
||||
mask |= notify.kqueue_write
|
||||
}
|
||||
if events.has(.exception) {
|
||||
mask |= notify.kqueue_exception
|
||||
}
|
||||
if events.has(.peer_hangup) {
|
||||
panic("Kqueue does not support 'peer_hangup' event type.")
|
||||
}
|
||||
if events.has(.error) {
|
||||
panic("Kqueue does not support 'error' event type.")
|
||||
}
|
||||
if events.has(.hangup) {
|
||||
panic("Kqueue does not support 'hangup' event type.")
|
||||
}
|
||||
return mask
|
||||
}
|
||||
|
||||
// flags_to_mask is a helper function that converts FdConfigFlags
|
||||
// to a bitmask used by the C functions
|
||||
fn flags_to_mask(confs ...FdConfigFlags) u16 {
|
||||
mut mask := notify.kqueue_add | notify.kqueue_enable
|
||||
for conf in confs {
|
||||
if conf.has(.edge_trigger) {
|
||||
mask |= notify.kqueue_edge_trigger
|
||||
}
|
||||
if conf.has(.one_shot) {
|
||||
mask |= notify.kqueue_oneshot
|
||||
}
|
||||
if conf.has(.wake_up) {
|
||||
panic("Kqueue does not support 'wake_up' flag.")
|
||||
}
|
||||
if conf.has(.exclusive) {
|
||||
panic("Kqueue does not support 'exclusive' flag.")
|
||||
}
|
||||
}
|
||||
return mask
|
||||
}
|
12
vlib/os/notify/kqueue.h
Normal file
12
vlib/os/notify/kqueue.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __KQUEUE_H
|
||||
#define __KQUEUE_H
|
||||
|
||||
#include <sys/event.h>
|
||||
|
||||
// Due to the renaming of 'struct kevent' and function 'kevent',
|
||||
// they are wrapped here to avoid conflicts.
|
||||
int __kevent__(int handle, const struct kevent* changelist, int nchanges, struct kevent* eventlist, int nevents, const struct timespec* timeout) {
|
||||
return kevent(handle, changelist, nchanges, eventlist, nevents, timeout);
|
||||
}
|
||||
|
||||
#endif
|
@ -5,7 +5,7 @@ import os.notify
|
||||
|
||||
// make a pipe and return the (read, write) file descriptors
|
||||
fn make_pipe() !(int, int) {
|
||||
$if linux {
|
||||
$if linux || macos {
|
||||
pipefd := [2]int{}
|
||||
if C.pipe(&pipefd[0]) != 0 {
|
||||
return error('error ${C.errno}: ' + os.posix_get_error_msg(C.errno))
|
||||
@ -16,8 +16,8 @@ fn make_pipe() !(int, int) {
|
||||
}
|
||||
|
||||
fn test_level_trigger() {
|
||||
// currently only linux is supported
|
||||
$if linux {
|
||||
// currently only linux and macos are supported
|
||||
$if linux || macos {
|
||||
mut notifier := notify.new()!
|
||||
reader, writer := make_pipe()!
|
||||
defer {
|
||||
@ -37,8 +37,8 @@ fn test_level_trigger() {
|
||||
}
|
||||
|
||||
fn test_edge_trigger() {
|
||||
// currently only linux is supported
|
||||
$if linux {
|
||||
// currently only linux and macos are supported
|
||||
$if linux || macos {
|
||||
mut notifier := notify.new()!
|
||||
reader, writer := make_pipe()!
|
||||
defer {
|
||||
@ -53,7 +53,27 @@ fn test_edge_trigger() {
|
||||
os.fd_write(writer, 'foobar')
|
||||
check_read_event(mut n, reader, 'foo')
|
||||
|
||||
assert notifier.wait(0).len == 0
|
||||
$if linux {
|
||||
assert notifier.wait(0).len == 0
|
||||
}
|
||||
$if macos {
|
||||
/*
|
||||
In the kqueue of macos, EV_CLEAR flag represents a clear event,
|
||||
which is mainly used for pipeline and socket class events. When this flag is set,
|
||||
kqueue will trigger the corresponding event when the data is readable or writable,
|
||||
but it is not guaranteed that the event will only be triggered once.
|
||||
Compared to EPOLLET, EV_CLEAR's behavior varies. In epoll, the edge triggered mode only triggers
|
||||
an event once when the state changes from unreadable/non writable to readable/writable,
|
||||
that is, when the data changes from unreadable to readable,
|
||||
or when the data changes from unreadable to writable. In the kqueue of macos,
|
||||
EV_CLEAR does not possess this precise edge triggering behavior.
|
||||
Therefore, in the kqueue of macos, even if the data is not completely read,
|
||||
it is possible to continue triggering read events. This means that if you don't process all the data,
|
||||
the next kqueue event notification may still be triggered
|
||||
*/
|
||||
|
||||
// notifier.wait(0).len == 1 or 0
|
||||
}
|
||||
|
||||
os.fd_write(writer, 'baz')
|
||||
// we do not get an event because there is still data
|
||||
@ -65,7 +85,7 @@ fn test_edge_trigger() {
|
||||
}
|
||||
|
||||
fn test_one_shot() {
|
||||
$if linux {
|
||||
$if linux || macos {
|
||||
mut notifier := notify.new()!
|
||||
reader, writer := make_pipe()!
|
||||
defer {
|
||||
@ -89,6 +109,7 @@ fn test_one_shot() {
|
||||
}
|
||||
}
|
||||
|
||||
// Kqueue does not support 'hangup' event type.
|
||||
fn test_hangup() {
|
||||
$if linux {
|
||||
mut notifier := notify.new()!
|
||||
@ -112,7 +133,7 @@ fn test_hangup() {
|
||||
}
|
||||
|
||||
fn test_write() {
|
||||
$if linux {
|
||||
$if linux || macos {
|
||||
mut notifier := notify.new()!
|
||||
reader, writer := make_pipe()!
|
||||
defer {
|
||||
@ -133,7 +154,7 @@ fn test_write() {
|
||||
}
|
||||
|
||||
fn test_remove() {
|
||||
$if linux {
|
||||
$if linux || macos {
|
||||
mut notifier := notify.new()!
|
||||
reader, writer := make_pipe()!
|
||||
defer {
|
||||
|
@ -23,7 +23,7 @@ pub mut:
|
||||
fd int
|
||||
loop_id int = -1
|
||||
events u32
|
||||
cb fn (int, int, voidptr)
|
||||
cb fn (int, int, voidptr) = unsafe { nil }
|
||||
// used internally by the kqueue implementation
|
||||
backend int
|
||||
}
|
||||
@ -31,7 +31,7 @@ pub mut:
|
||||
pub struct Config {
|
||||
pub:
|
||||
port int = 8080
|
||||
cb fn (voidptr, picohttpparser.Request, mut picohttpparser.Response)
|
||||
cb fn (voidptr, picohttpparser.Request, mut picohttpparser.Response) = unsafe { nil }
|
||||
err_cb fn (voidptr, picohttpparser.Request, mut picohttpparser.Response, IError) = default_err_cb
|
||||
user_data voidptr = unsafe { nil }
|
||||
timeout_secs int = 8
|
||||
@ -42,7 +42,7 @@ pub:
|
||||
|
||||
[heap]
|
||||
pub struct Picoev {
|
||||
cb fn (voidptr, picohttpparser.Request, mut picohttpparser.Response)
|
||||
cb fn (voidptr, picohttpparser.Request, mut picohttpparser.Response) = unsafe { nil }
|
||||
err_cb fn (voidptr, picohttpparser.Request, mut picohttpparser.Response, IError) = default_err_cb
|
||||
user_data voidptr = unsafe { nil }
|
||||
|
||||
|
@ -28,7 +28,7 @@ const time_to_test = time.Time{
|
||||
hour: 21
|
||||
minute: 23
|
||||
second: 42
|
||||
microsecond: 123456
|
||||
nanosecond: 123456789
|
||||
unix: 332198622
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ assert '1980-07-11 21:23' == time_to_test.format()
|
||||
assert '1980-07-11 21:23:42' == time_to_test.format_ss()
|
||||
assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli()
|
||||
assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro()
|
||||
assert '1980-07-11 21:23:42.123456789' == time_to_test.format_ss_nano()
|
||||
```
|
||||
|
||||
You can also parse strings to produce time.Time values,
|
||||
|
@ -9,3 +9,30 @@ fn test_custom_format() {
|
||||
|
||||
println(date.custom_format(test_str))
|
||||
}
|
||||
|
||||
fn test_hours() {
|
||||
assert time.parse('2023-08-04 00:00:45')!.custom_format('hh A h a') == '00 AM 0 am'
|
||||
assert time.parse('2023-08-04 01:00:45')!.custom_format('hh A h a') == '01 AM 1 am'
|
||||
assert time.parse('2023-08-04 02:00:45')!.custom_format('hh A h a') == '02 AM 2 am'
|
||||
assert time.parse('2023-08-04 03:00:45')!.custom_format('hh A h a') == '03 AM 3 am'
|
||||
assert time.parse('2023-08-04 04:00:45')!.custom_format('hh A h a') == '04 AM 4 am'
|
||||
assert time.parse('2023-08-04 05:00:45')!.custom_format('hh A h a') == '05 AM 5 am'
|
||||
assert time.parse('2023-08-04 06:00:45')!.custom_format('hh A h a') == '06 AM 6 am'
|
||||
assert time.parse('2023-08-04 07:00:45')!.custom_format('hh A h a') == '07 AM 7 am'
|
||||
assert time.parse('2023-08-04 08:00:45')!.custom_format('hh A h a') == '08 AM 8 am'
|
||||
assert time.parse('2023-08-04 09:00:45')!.custom_format('hh A h a') == '09 AM 9 am'
|
||||
assert time.parse('2023-08-04 10:00:45')!.custom_format('hh A h a') == '10 AM 10 am'
|
||||
assert time.parse('2023-08-04 11:00:45')!.custom_format('hh A h a') == '11 AM 11 am'
|
||||
assert time.parse('2023-08-04 12:00:45')!.custom_format('hh A h a') == '12 PM 12 pm'
|
||||
assert time.parse('2023-08-04 13:00:45')!.custom_format('hh A h a') == '01 PM 1 pm'
|
||||
assert time.parse('2023-08-04 14:00:45')!.custom_format('hh A h a') == '02 PM 2 pm'
|
||||
assert time.parse('2023-08-04 15:00:45')!.custom_format('hh A h a') == '03 PM 3 pm'
|
||||
assert time.parse('2023-08-04 16:00:45')!.custom_format('hh A h a') == '04 PM 4 pm'
|
||||
assert time.parse('2023-08-04 17:00:45')!.custom_format('hh A h a') == '05 PM 5 pm'
|
||||
assert time.parse('2023-08-04 18:00:45')!.custom_format('hh A h a') == '06 PM 6 pm'
|
||||
assert time.parse('2023-08-04 19:00:45')!.custom_format('hh A h a') == '07 PM 7 pm'
|
||||
assert time.parse('2023-08-04 20:00:45')!.custom_format('hh A h a') == '08 PM 8 pm'
|
||||
assert time.parse('2023-08-04 21:00:45')!.custom_format('hh A h a') == '09 PM 9 pm'
|
||||
assert time.parse('2023-08-04 22:00:45')!.custom_format('hh A h a') == '10 PM 10 pm'
|
||||
assert time.parse('2023-08-04 23:00:45')!.custom_format('hh A h a') == '11 PM 11 pm'
|
||||
}
|
||||
|
@ -31,3 +31,9 @@ fn test_duration_str() {
|
||||
assert time.Duration(1 * time.hour + 5 * time.second).str() == '1:00:05'
|
||||
assert time.Duration(168 * time.hour + 5 * time.minute + 7 * time.second).str() == '168:05:07'
|
||||
}
|
||||
|
||||
fn test_duration_debug() {
|
||||
assert time.Duration(1 * time.nanosecond).debug() == 'Duration: 1ns'
|
||||
assert time.Duration(169 * time.hour + 5 * time.minute + 7 * time.second).debug() == 'Duration: 7days, 1h, 5m, 7s'
|
||||
assert (-time.Duration(169 * time.hour + 5 * time.minute + 7 * time.second)).debug() == 'Duration: - 7days, 1h, 5m, 7s'
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub fn (t Time) format_ss() string {
|
||||
|
||||
// format_ss_milli returns a date string in "YYYY-MM-DD HH:mm:ss.123" format (24h).
|
||||
pub fn (t Time) format_ss_milli() string {
|
||||
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.microsecond / 1000):03d}'
|
||||
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000_000):03d}'
|
||||
}
|
||||
|
||||
// format_rfc3339 returns a date string in "YYYY-MM-DDTHH:mm:ss.123Z" format (24 hours, see https://www.rfc-editor.org/rfc/rfc3339.html)
|
||||
@ -25,12 +25,17 @@ pub fn (t Time) format_ss_milli() string {
|
||||
// It is intended to improve consistency and interoperability, when representing and using date and time in Internet protocols.
|
||||
pub fn (t Time) format_rfc3339() string {
|
||||
u := t.local_to_utc()
|
||||
return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.microsecond / 1000):03d}Z'
|
||||
return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.nanosecond / 1_000_000):03d}Z'
|
||||
}
|
||||
|
||||
// format_ss_micro returns a date string in "YYYY-MM-DD HH:mm:ss.123456" format (24h).
|
||||
pub fn (t Time) format_ss_micro() string {
|
||||
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.microsecond:06d}'
|
||||
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000):06d}'
|
||||
}
|
||||
|
||||
// format_ss_nano returns a date string in "YYYY-MM-DD HH:mm:ss.123456789" format (24h).
|
||||
pub fn (t Time) format_ss_nano() string {
|
||||
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.nanosecond:09d}'
|
||||
}
|
||||
|
||||
// hhmm returns a date string in "HH:mm" format (24h).
|
||||
@ -221,10 +226,12 @@ pub fn (t Time) custom_format(s string) string {
|
||||
sb.write_string('${t.hour:02}')
|
||||
}
|
||||
'h' {
|
||||
sb.write_string((t.hour % 12).str())
|
||||
h := if t.hour > 12 { t.hour - 12 } else { t.hour }
|
||||
sb.write_string(h.str())
|
||||
}
|
||||
'hh' {
|
||||
sb.write_string('${(t.hour % 12):02}')
|
||||
h := if t.hour > 12 { t.hour - 12 } else { t.hour }
|
||||
sb.write_string('${h:02}')
|
||||
}
|
||||
'm' {
|
||||
sb.write_string(t.minute.str())
|
||||
@ -306,17 +313,17 @@ pub fn (t Time) custom_format(s string) string {
|
||||
}
|
||||
}
|
||||
'a' {
|
||||
if t.hour > 12 {
|
||||
sb.write_string('pm')
|
||||
} else {
|
||||
if t.hour < 12 {
|
||||
sb.write_string('am')
|
||||
} else {
|
||||
sb.write_string('pm')
|
||||
}
|
||||
}
|
||||
'A' {
|
||||
if t.hour > 12 {
|
||||
sb.write_string('PM')
|
||||
} else {
|
||||
if t.hour < 12 {
|
||||
sb.write_string('AM')
|
||||
} else {
|
||||
sb.write_string('PM')
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -379,8 +386,9 @@ pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string {
|
||||
.hhmm24 { '${t.hour:02d}:${t.minute:02d}' }
|
||||
.hhmmss12 { '${hour_}:${t.minute:02d}:${t.second:02d} ${tp}' }
|
||||
.hhmmss24 { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}' }
|
||||
.hhmmss24_milli { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.microsecond / 1000):03d}' }
|
||||
.hhmmss24_micro { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.microsecond:06d}' }
|
||||
.hhmmss24_milli { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000_000):03d}' }
|
||||
.hhmmss24_micro { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000):06d}' }
|
||||
.hhmmss24_nano { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.nanosecond:06d}' }
|
||||
else { 'unknown enumeration ${fmt_time}' }
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,22 @@ module time
|
||||
// operator `==` returns true if provided time is equal to time
|
||||
[inline]
|
||||
pub fn (t1 Time) == (t2 Time) bool {
|
||||
return t1.unix == t2.unix && t1.microsecond == t2.microsecond
|
||||
return t1.unix == t2.unix && t1.nanosecond == t2.nanosecond
|
||||
}
|
||||
|
||||
// operator `<` returns true if provided time is less than time
|
||||
[inline]
|
||||
pub fn (t1 Time) < (t2 Time) bool {
|
||||
return t1.unix < t2.unix || (t1.unix == t2.unix && t1.microsecond < t2.microsecond)
|
||||
return t1.unix < t2.unix || (t1.unix == t2.unix && t1.nanosecond < t2.nanosecond)
|
||||
}
|
||||
|
||||
// Time subtract using operator overloading.
|
||||
[inline]
|
||||
pub fn (lhs Time) - (rhs Time) Duration {
|
||||
lhs_micro := lhs.unix * 1_000_000 + lhs.microsecond
|
||||
rhs_micro := rhs.unix * 1_000_000 + rhs.microsecond
|
||||
return (lhs_micro - rhs_micro) * microsecond
|
||||
// lhs.unix * 1_000_000_000 + i64(lhs.nanosecond) will overflow i64, for years > 3000 .
|
||||
// Doing the diff first, and *then* multiplying by `second`, is less likely to overflow,
|
||||
// since lhs and rhs will be likely close to each other.
|
||||
unixs := i64(lhs.unix - rhs.unix) * second
|
||||
nanos := lhs.nanosecond - rhs.nanosecond
|
||||
return unixs + nanos
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ fn test_time1_should_be_same_as_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
@ -48,7 +48,7 @@ fn test_time1_should_be_same_as_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
assert t1 == t2
|
||||
}
|
||||
@ -61,9 +61,9 @@ fn test_time1_should_not_be_same_as_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -71,7 +71,7 @@ fn test_time1_should_not_be_same_as_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 101
|
||||
nanosecond: 101
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -80,7 +80,7 @@ fn test_time1_should_not_be_same_as_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -90,7 +90,7 @@ fn test_time1_should_not_be_same_as_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 4
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t1 != t2
|
||||
assert t3 != t4
|
||||
@ -104,9 +104,9 @@ fn test_time1_should_be_greater_than_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 102
|
||||
nanosecond: 102
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -114,7 +114,7 @@ fn test_time1_should_be_greater_than_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 101
|
||||
nanosecond: 101
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -123,7 +123,7 @@ fn test_time1_should_be_greater_than_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 5
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -133,7 +133,7 @@ fn test_time1_should_be_greater_than_time2() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 4
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t1 > t2
|
||||
assert t3 > t4
|
||||
@ -147,9 +147,9 @@ fn test_time2_should_be_less_than_time1() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 102
|
||||
nanosecond: 102
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -157,7 +157,7 @@ fn test_time2_should_be_less_than_time1() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 101
|
||||
nanosecond: 101
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -166,7 +166,7 @@ fn test_time2_should_be_less_than_time1() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -176,7 +176,7 @@ fn test_time2_should_be_less_than_time1() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 2
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t2 < t1
|
||||
assert t4 < t3
|
||||
@ -190,9 +190,9 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 102
|
||||
nanosecond: 102
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -200,7 +200,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 101
|
||||
nanosecond: 101
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -209,7 +209,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 5
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -219,7 +219,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_gt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 4
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t1 >= t2
|
||||
assert t3 >= t4
|
||||
@ -233,9 +233,9 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -243,7 +243,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -252,7 +252,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -262,7 +262,7 @@ fn test_time1_should_be_greater_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t1 >= t2
|
||||
assert t3 >= t4
|
||||
@ -276,9 +276,9 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -286,7 +286,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 101
|
||||
nanosecond: 101
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -295,7 +295,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -305,7 +305,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_lt() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 4
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t1 <= t2
|
||||
assert t3 <= t4
|
||||
@ -319,9 +319,9 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
// Difference is one microsecond
|
||||
// Difference is one nanosecond
|
||||
t2 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -329,7 +329,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
t3 := new_time(Time{
|
||||
year: 2000
|
||||
@ -338,7 +338,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
// Difference is one second
|
||||
t4 := new_time(Time{
|
||||
@ -348,7 +348,7 @@ fn test_time1_should_be_less_or_equal_to_time2_when_eq() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 0
|
||||
nanosecond: 0
|
||||
})
|
||||
assert t1 <= t2
|
||||
assert t3 <= t4
|
||||
@ -362,7 +362,7 @@ fn test_time2_copied_from_time1_should_be_equal() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
t2 := new_time(t1)
|
||||
assert t2 == t1
|
||||
@ -370,8 +370,8 @@ fn test_time2_copied_from_time1_should_be_equal() {
|
||||
|
||||
fn test_subtract() {
|
||||
d_seconds := 3
|
||||
d_microseconds := 13
|
||||
duration := d_seconds * second + d_microseconds * microsecond
|
||||
d_nanoseconds := 13
|
||||
duration := d_seconds * second + d_nanoseconds * nanosecond
|
||||
t1 := new_time(Time{
|
||||
year: 2000
|
||||
month: 5
|
||||
@ -379,9 +379,9 @@ fn test_subtract() {
|
||||
hour: 22
|
||||
minute: 11
|
||||
second: 3
|
||||
microsecond: 100
|
||||
nanosecond: 100
|
||||
})
|
||||
t2 := unix2(i64(t1.unix) + d_seconds, t1.microsecond + d_microseconds)
|
||||
t2 := unix_nanosecond(i64(t1.unix) + d_seconds, t1.nanosecond + d_nanoseconds)
|
||||
d1 := t2 - t1
|
||||
d2 := t1 - t2
|
||||
assert d1 > 0
|
||||
|
@ -35,13 +35,13 @@ pub fn parse_rfc3339(s string) !Time {
|
||||
}
|
||||
// Check if sn is time only
|
||||
if !parts[0].contains('-') && parts[0].contains(':') {
|
||||
mut hour_, mut minute_, mut second_, mut microsecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, i64(0), true
|
||||
hour_, minute_, second_, microsecond_, unix_offset, is_local_time = parse_iso8601_time(parts[0])!
|
||||
mut hour_, mut minute_, mut second_, mut microsecond_, mut nanosecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, 0, i64(0), true
|
||||
hour_, minute_, second_, microsecond_, nanosecond_, unix_offset, is_local_time = parse_iso8601_time(parts[0])!
|
||||
t = new_time(Time{
|
||||
hour: hour_
|
||||
minute: minute_
|
||||
second: second_
|
||||
microsecond: microsecond_
|
||||
nanosecond: nanosecond_
|
||||
})
|
||||
if is_local_time {
|
||||
return t // Time is already local time
|
||||
@ -52,7 +52,7 @@ pub fn parse_rfc3339(s string) !Time {
|
||||
} else if unix_offset > 0 {
|
||||
unix_time += unix_offset
|
||||
}
|
||||
t = unix2(i64(unix_time), t.microsecond)
|
||||
t = unix_nanosecond(i64(unix_time), t.nanosecond)
|
||||
return t
|
||||
}
|
||||
|
||||
@ -171,9 +171,9 @@ pub fn parse_iso8601(s string) !Time {
|
||||
return error_invalid_time(12, 'malformed date')
|
||||
}
|
||||
year, month, day := parse_iso8601_date(parts[0])!
|
||||
mut hour_, mut minute_, mut second_, mut microsecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, i64(0), true
|
||||
mut hour_, mut minute_, mut second_, mut microsecond_, mut nanosecond_, mut unix_offset, mut is_local_time := 0, 0, 0, 0, 0, i64(0), true
|
||||
if parts.len == 2 {
|
||||
hour_, minute_, second_, microsecond_, unix_offset, is_local_time = parse_iso8601_time(parts[1])!
|
||||
hour_, minute_, second_, microsecond_, nanosecond_, unix_offset, is_local_time = parse_iso8601_time(parts[1])!
|
||||
}
|
||||
mut t := new_time(
|
||||
year: year
|
||||
@ -182,7 +182,7 @@ pub fn parse_iso8601(s string) !Time {
|
||||
hour: hour_
|
||||
minute: minute_
|
||||
second: second_
|
||||
microsecond: microsecond_
|
||||
nanosecond: nanosecond_
|
||||
)
|
||||
if is_local_time {
|
||||
return t // Time already local time
|
||||
@ -193,7 +193,7 @@ pub fn parse_iso8601(s string) !Time {
|
||||
} else if unix_offset > 0 {
|
||||
unix_time += unix_offset
|
||||
}
|
||||
t = unix2(i64(unix_time), t.microsecond)
|
||||
t = unix_nanosecond(i64(unix_time), t.nanosecond)
|
||||
return t
|
||||
}
|
||||
|
||||
@ -237,7 +237,7 @@ fn parse_iso8601_date(s string) !(int, int, int) {
|
||||
return year, month, day
|
||||
}
|
||||
|
||||
fn parse_iso8601_time(s string) !(int, int, int, int, i64, bool) {
|
||||
fn parse_iso8601_time(s string) !(int, int, int, int, int, i64, bool) {
|
||||
hour_ := 0
|
||||
minute_ := 0
|
||||
second_ := 0
|
||||
@ -281,6 +281,7 @@ fn parse_iso8601_time(s string) !(int, int, int, int, i64, bool) {
|
||||
if count < 4 {
|
||||
return error_invalid_time(10, 'malformed date')
|
||||
}
|
||||
nanosecond_ = microsecond_ * 1000
|
||||
}
|
||||
is_local_time := plus_min_z == `a` && count == 4
|
||||
is_utc := plus_min_z == `Z` && count == 5
|
||||
@ -300,5 +301,6 @@ fn parse_iso8601_time(s string) !(int, int, int, int, i64, bool) {
|
||||
if plus_min_z == `+` {
|
||||
unix_offset *= -1
|
||||
}
|
||||
return hour_, minute_, second_, microsecond_, unix_offset, is_local_time
|
||||
// eprintln('parse_iso8601_time s: $s | hour_: $hour_ | minute_: $minute_ | second_: $second_ | microsecond_: $microsecond_ | nanosecond_: $nanosecond_ | unix_offset: $unix_offset | is_local_time: $is_local_time')
|
||||
return hour_, minute_, second_, microsecond_, nanosecond_, unix_offset, is_local_time
|
||||
}
|
||||
|
@ -65,11 +65,11 @@ fn test_parse_iso8601() {
|
||||
]
|
||||
times := [
|
||||
[2020, 6, 5, 15, 38, 6, 0],
|
||||
[2020, 6, 5, 15, 38, 6, 15959],
|
||||
[2020, 6, 5, 15, 38, 6, 15959],
|
||||
[2020, 6, 5, 13, 38, 6, 15959],
|
||||
[2020, 6, 5, 17, 38, 6, 15959],
|
||||
[2020, 11, 5, 15, 38, 6, 15959],
|
||||
[2020, 6, 5, 15, 38, 6, 15959000],
|
||||
[2020, 6, 5, 15, 38, 6, 15959000],
|
||||
[2020, 6, 5, 13, 38, 6, 15959000],
|
||||
[2020, 6, 5, 17, 38, 6, 15959000],
|
||||
[2020, 11, 5, 15, 38, 6, 15959000],
|
||||
]
|
||||
for i, format in formats {
|
||||
t := time.parse_iso8601(format) or {
|
||||
@ -89,8 +89,8 @@ fn test_parse_iso8601() {
|
||||
assert t.minute == minute
|
||||
second := times[i][5]
|
||||
assert t.second == second
|
||||
microsecond := times[i][6]
|
||||
assert t.microsecond == microsecond
|
||||
nanosecond := times[i][6]
|
||||
assert t.nanosecond == nanosecond
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ fn test_parse_iso8601_local() {
|
||||
assert t.hour == 15
|
||||
assert t.minute == 38
|
||||
assert t.second == 6
|
||||
assert t.microsecond == 15959
|
||||
assert t.nanosecond == 15959_000
|
||||
}
|
||||
|
||||
fn test_parse_iso8601_invalid() {
|
||||
@ -145,7 +145,7 @@ fn test_parse_iso8601_date_only() {
|
||||
assert t.hour == 0
|
||||
assert t.minute == 0
|
||||
assert t.second == 0
|
||||
assert t.microsecond == 0
|
||||
assert t.nanosecond == 0
|
||||
}
|
||||
|
||||
fn check_invalid_date(s string) {
|
||||
|
@ -53,13 +53,6 @@ pub fn utc() Time {
|
||||
return solaris_utc()
|
||||
}
|
||||
return linux_utc()
|
||||
/*
|
||||
// defaults to most common feature, the microsecond precision is not available
|
||||
// in this API call
|
||||
t := C.time(0)
|
||||
_ = C.time(&t)
|
||||
return unix2(i64(t), 0)
|
||||
*/
|
||||
}
|
||||
|
||||
// new_time returns a time struct with the calculated Unix time.
|
||||
@ -90,7 +83,7 @@ pub fn ticks() i64 {
|
||||
} $else {
|
||||
ts := C.timeval{}
|
||||
C.gettimeofday(&ts, 0)
|
||||
return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1000)))
|
||||
return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1_000)))
|
||||
}
|
||||
// t := i64(C.mach_absolute_time())
|
||||
// # Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t );
|
||||
@ -105,7 +98,7 @@ pub fn (t Time) str() string {
|
||||
}
|
||||
|
||||
// convert_ctime converts a C time to V time.
|
||||
fn convert_ctime(t C.tm, microsecond int) Time {
|
||||
fn convert_ctime(t C.tm, nanosecond int) Time {
|
||||
return Time{
|
||||
year: t.tm_year + 1900
|
||||
month: t.tm_mon + 1
|
||||
@ -113,7 +106,7 @@ fn convert_ctime(t C.tm, microsecond int) Time {
|
||||
hour: t.tm_hour
|
||||
minute: t.tm_min
|
||||
second: t.tm_sec
|
||||
microsecond: microsecond
|
||||
nanosecond: nanosecond
|
||||
unix: make_unix_time(t)
|
||||
// for the actual code base when we
|
||||
// call convert_ctime, it is always
|
||||
|
109
vlib/time/time.v
109
vlib/time/time.v
@ -40,15 +40,17 @@ pub const (
|
||||
// Time contains various time units for a point in time.
|
||||
pub struct Time {
|
||||
pub:
|
||||
year int
|
||||
month int
|
||||
day int
|
||||
hour int
|
||||
minute int
|
||||
second int
|
||||
microsecond int
|
||||
unix i64
|
||||
is_local bool // used to make time.now().local().local() == time.now().local()
|
||||
year int
|
||||
month int
|
||||
day int
|
||||
hour int
|
||||
minute int
|
||||
second int
|
||||
nanosecond int
|
||||
unix i64
|
||||
is_local bool // used to make time.now().local().local() == time.now().local()
|
||||
//
|
||||
microsecond int [deprecated: 'use t.nanosecond / 1000 instead'; deprecated_after: '2023-08-05']
|
||||
}
|
||||
|
||||
// FormatDelimiter contains different time formats.
|
||||
@ -59,6 +61,7 @@ pub enum FormatTime {
|
||||
hhmmss24
|
||||
hhmmss24_milli
|
||||
hhmmss24_micro
|
||||
hhmmss24_nano
|
||||
no_time
|
||||
}
|
||||
|
||||
@ -99,7 +102,7 @@ pub fn (t Time) smonth() string {
|
||||
return time.months_string[i * 3..(i + 1) * 3]
|
||||
}
|
||||
|
||||
// unix_time returns the UNIX time.
|
||||
// unix_time returns the UNIX time with second resolution.
|
||||
[inline]
|
||||
pub fn (t Time) unix_time() i64 {
|
||||
return t.unix
|
||||
@ -108,18 +111,39 @@ pub fn (t Time) unix_time() i64 {
|
||||
// unix_time_milli returns the UNIX time with millisecond resolution.
|
||||
[inline]
|
||||
pub fn (t Time) unix_time_milli() i64 {
|
||||
return t.unix * 1000 + (t.microsecond / 1000)
|
||||
return t.unix * 1_000 + (i64(t.nanosecond) / 1_000_000)
|
||||
}
|
||||
|
||||
// unix_time_micro returns the UNIX time with microsecond resolution.
|
||||
[inline]
|
||||
pub fn (t Time) unix_time_micro() i64 {
|
||||
return t.unix * 1_000_000 + (i64(t.nanosecond) / 1_000)
|
||||
}
|
||||
|
||||
// unix_time_nano returns the UNIX time with nanosecond resolution.
|
||||
[inline]
|
||||
pub fn (t Time) unix_time_nano() i64 {
|
||||
// TODO: use i128 here, when V supports it, since the following expression overflows for years like 3001:
|
||||
return t.unix * 1_000_000_000 + i64(t.nanosecond)
|
||||
}
|
||||
|
||||
// add returns a new time with the given duration added.
|
||||
pub fn (t Time) add(d Duration) Time {
|
||||
microseconds := i64(t.unix) * 1_000_000 + t.microsecond + d.microseconds()
|
||||
unix := microseconds / 1_000_000
|
||||
micro := microseconds % 1_000_000
|
||||
if t.is_local {
|
||||
return unix2(unix, int(micro)).as_local()
|
||||
// This expression overflows i64 for big years (and we do not have i128 yet):
|
||||
// nanos := t.unix * 1_000_000_000 + i64(t.nanosecond) <-
|
||||
// ... so instead, handle the addition manually in parts ¯\_(ツ)_/¯
|
||||
mut unixs := t.unix
|
||||
mut nanos := i64(t.nanosecond) + d.nanoseconds()
|
||||
unixs += nanos / time.second
|
||||
nanos = nanos % time.second
|
||||
if nanos < 0 {
|
||||
unixs--
|
||||
nanos += time.second
|
||||
}
|
||||
return unix2(unix, int(micro))
|
||||
if t.is_local {
|
||||
return unix_nanosecond(unixs, int(nanos)).as_local()
|
||||
}
|
||||
return unix_nanosecond(unixs, int(nanos))
|
||||
}
|
||||
|
||||
// add_seconds returns a new time struct with an added number of seconds.
|
||||
@ -311,9 +335,9 @@ pub fn days_in_month(month int, year int) !int {
|
||||
return res
|
||||
}
|
||||
|
||||
// debug returns detailed breakdown of time (`Time{ year: YYYY month: MM day: dd hour: HH: minute: mm second: ss microsecond: micros unix: unix }`)
|
||||
// debug returns detailed breakdown of time (`Time{ year: YYYY month: MM day: dd hour: HH: minute: mm second: ss nanosecond: nanos unix: unix }`)
|
||||
pub fn (t Time) debug() string {
|
||||
return 'Time{ year: ${t.year:04} month: ${t.month:02} day: ${t.day:02} hour: ${t.hour:02} minute: ${t.minute:02} second: ${t.second:02} microsecond: ${t.microsecond:06} unix: ${t.unix:07} }'
|
||||
return 'Time{ year: ${t.year:04} month: ${t.month:02} day: ${t.day:02} hour: ${t.hour:02} minute: ${t.minute:02} second: ${t.second:02} nanosecond: ${t.nanosecond:09} unix: ${t.unix:07} }'
|
||||
}
|
||||
|
||||
// A lot of these are taken from the Go library.
|
||||
@ -326,6 +350,7 @@ pub const (
|
||||
second = Duration(1000 * millisecond)
|
||||
minute = Duration(60 * second)
|
||||
hour = Duration(60 * minute)
|
||||
// day = Duration(24 * hour)
|
||||
infinite = Duration(i64(9223372036854775807))
|
||||
)
|
||||
|
||||
@ -348,23 +373,22 @@ pub fn (d Duration) milliseconds() i64 {
|
||||
// consider all of them in sub-one intervals
|
||||
// seconds returns the duration as a floating point number of seconds.
|
||||
pub fn (d Duration) seconds() f64 {
|
||||
sec := d / time.second
|
||||
nsec := d % time.second
|
||||
return f64(sec) + f64(nsec) / time.second
|
||||
return f64(d) / f64(time.second)
|
||||
}
|
||||
|
||||
// minutes returns the duration as a floating point number of minutes.
|
||||
pub fn (d Duration) minutes() f64 {
|
||||
min := d / time.minute
|
||||
nsec := d % time.minute
|
||||
return f64(min) + f64(nsec) / time.minute
|
||||
return f64(d) / f64(time.minute)
|
||||
}
|
||||
|
||||
// hours returns the duration as a floating point number of hours.
|
||||
pub fn (d Duration) hours() f64 {
|
||||
hr := d / time.hour
|
||||
nsec := d % time.hour
|
||||
return f64(hr) + f64(nsec) / time.hour
|
||||
return f64(d) / f64(time.hour)
|
||||
}
|
||||
|
||||
// days returns the duration as a floating point number of days.
|
||||
pub fn (d Duration) days() f64 {
|
||||
return f64(d) / f64(time.hour * 24)
|
||||
}
|
||||
|
||||
// str pretty prints the duration
|
||||
@ -412,6 +436,35 @@ pub fn (d Duration) str() string {
|
||||
return '${ns}ns'
|
||||
}
|
||||
|
||||
// debug returns a detailed breakdown of the Duration, as: 'Duration: - 50days, 4h, 3m, 7s, 541ms, 78us, 9ns'
|
||||
pub fn (d Duration) debug() string {
|
||||
mut res := []string{}
|
||||
mut x := i64(d)
|
||||
mut sign := ''
|
||||
if x < 0 {
|
||||
sign = '- '
|
||||
x = -x
|
||||
}
|
||||
for label, v in {
|
||||
'days': 24 * time.hour
|
||||
'h': time.hour
|
||||
'm': time.minute
|
||||
's': time.second
|
||||
'ms': time.millisecond
|
||||
'us': time.microsecond
|
||||
} {
|
||||
if x > v {
|
||||
xx := x / v
|
||||
x = x % v
|
||||
res << xx.str() + label
|
||||
}
|
||||
}
|
||||
if x > 0 {
|
||||
res << '${x}ns'
|
||||
}
|
||||
return 'Duration: ${sign}${res.join(', ')}'
|
||||
}
|
||||
|
||||
// offset returns time zone UTC offset in seconds.
|
||||
pub fn offset() int {
|
||||
t := utc()
|
||||
|
@ -3,8 +3,6 @@ import time
|
||||
fn test_add_to_day_in_the_previous_century() {
|
||||
a := time.parse_iso8601('1900-01-01')!
|
||||
aa := a.add_days(180)
|
||||
dump(a.debug())
|
||||
dump(aa.debug())
|
||||
assert aa.ymmdd() == '1900-06-30'
|
||||
}
|
||||
|
||||
@ -23,6 +21,8 @@ fn test_add_to_day_in_the_recent_past() {
|
||||
fn test_add_to_day_in_the_future_1() {
|
||||
a := time.parse_iso8601('3000-11-01')!
|
||||
aa := a.add_days(180)
|
||||
dump(a.debug())
|
||||
dump(aa.debug())
|
||||
assert aa.ymmdd() == '3001-04-30'
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,10 @@ module time
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
const (
|
||||
// start_time is needed on Darwin and Windows because of potential overflows
|
||||
start_time = C.mach_absolute_time()
|
||||
time_base = init_time_base()
|
||||
)
|
||||
// start_time is needed on Darwin and Windows because of potential overflows
|
||||
const start_time = C.mach_absolute_time()
|
||||
|
||||
const time_base = init_time_base()
|
||||
|
||||
[typedef]
|
||||
struct C.mach_timebase_info_data_t {
|
||||
@ -25,11 +24,6 @@ struct InternalTimeBase {
|
||||
denom u32 = 1
|
||||
}
|
||||
|
||||
pub struct C.timeval {
|
||||
tv_sec u64
|
||||
tv_usec u64
|
||||
}
|
||||
|
||||
fn init_time_base() C.mach_timebase_info_data_t {
|
||||
tb := C.mach_timebase_info_data_t{}
|
||||
C.mach_timebase_info(&tb)
|
||||
@ -62,29 +56,22 @@ fn vpc_now_darwin() u64 {
|
||||
return (tm - time.start_time) * time.time_base.numer / time.time_base.denom
|
||||
}
|
||||
|
||||
// darwin_now returns a better precision current time for Darwin based operating system
|
||||
// this should be implemented with native system calls eventually
|
||||
// but for now a bit tweaky. It uses the deprecated gettimeofday clock to get
|
||||
// the microseconds seconds part and converts to local time
|
||||
// darwin_now returns a better precision current time for macos
|
||||
fn darwin_now() Time {
|
||||
// get the high precision time as UTC clock
|
||||
tv := C.timeval{}
|
||||
C.gettimeofday(&tv, 0)
|
||||
// get the high precision time as UTC realtime clock, and use the nanoseconds part
|
||||
mut ts := C.timespec{}
|
||||
C.clock_gettime(C.CLOCK_REALTIME, &ts)
|
||||
loc_tm := C.tm{}
|
||||
asec := voidptr(&tv.tv_sec)
|
||||
C.localtime_r(asec, &loc_tm)
|
||||
return convert_ctime(loc_tm, int(tv.tv_usec))
|
||||
C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
|
||||
return convert_ctime(loc_tm, int(ts.tv_nsec))
|
||||
}
|
||||
|
||||
// darwin_utc returns a better precision current time for Darwin based operating system
|
||||
// this should be implemented with native system calls eventually
|
||||
// but for now a bit tweaky. It uses the deprecated gettimeofday clock to get
|
||||
// the microseconds seconds part and normal local time to get correct local time
|
||||
// darwin_utc returns a better precision current time for macos
|
||||
fn darwin_utc() Time {
|
||||
// get the high precision time as UTC clock
|
||||
tv := C.timeval{}
|
||||
C.gettimeofday(&tv, 0)
|
||||
return unix2(i64(tv.tv_sec), int(tv.tv_usec))
|
||||
mut ts := C.timespec{}
|
||||
C.clock_gettime(C.CLOCK_REALTIME, &ts)
|
||||
return unix_nanosecond(i64(ts.tv_sec), int(ts.tv_nsec))
|
||||
}
|
||||
|
||||
// dummy to compile with all compilers
|
||||
|
@ -36,7 +36,7 @@ pub fn (t Time) local() Time {
|
||||
}
|
||||
loc_tm := C.tm{}
|
||||
C.localtime_r(voidptr(&t.unix), &loc_tm)
|
||||
return convert_ctime(loc_tm, t.microsecond)
|
||||
return convert_ctime(loc_tm, t.nanosecond)
|
||||
}
|
||||
|
||||
// in most systems, these are __quad_t, which is an i64
|
||||
@ -58,7 +58,7 @@ pub fn sys_mono_now() u64 {
|
||||
} $else {
|
||||
ts := C.timespec{}
|
||||
C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
|
||||
return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec)
|
||||
return u64(ts.tv_sec) * 1_000_000_000 + u64(ts.tv_nsec)
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ pub fn sys_mono_now() u64 {
|
||||
fn vpc_now() u64 {
|
||||
ts := C.timespec{}
|
||||
C.clock_gettime(C.CLOCK_MONOTONIC, &ts)
|
||||
return u64(ts.tv_sec) * 1000000000 + u64(ts.tv_nsec)
|
||||
return u64(ts.tv_sec) * 1_000_000_000 + u64(ts.tv_nsec)
|
||||
}
|
||||
|
||||
// The linux_* functions are placed here, since they're used on Android as well
|
||||
@ -83,7 +83,7 @@ fn linux_now() Time {
|
||||
C.clock_gettime(C.CLOCK_REALTIME, &ts)
|
||||
loc_tm := C.tm{}
|
||||
C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
|
||||
return convert_ctime(loc_tm, int(ts.tv_nsec / 1000))
|
||||
return convert_ctime(loc_tm, int(ts.tv_nsec))
|
||||
}
|
||||
|
||||
fn linux_utc() Time {
|
||||
@ -91,7 +91,7 @@ fn linux_utc() Time {
|
||||
// and use the nanoseconds part
|
||||
mut ts := C.timespec{}
|
||||
C.clock_gettime(C.CLOCK_REALTIME, &ts)
|
||||
return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000))
|
||||
return unix_nanosecond(i64(ts.tv_sec), int(ts.tv_nsec))
|
||||
}
|
||||
|
||||
// dummy to compile with all compilers
|
||||
@ -104,12 +104,6 @@ fn win_utc() Time {
|
||||
return Time{}
|
||||
}
|
||||
|
||||
// dummy to compile with all compilers
|
||||
pub struct C.timeval {
|
||||
tv_sec u64
|
||||
tv_usec u64
|
||||
}
|
||||
|
||||
// return absolute timespec for now()+d
|
||||
pub fn (d Duration) timespec() C.timespec {
|
||||
mut ts := C.timespec{}
|
||||
|
@ -10,7 +10,7 @@ fn solaris_now() Time {
|
||||
C.clock_gettime(C.CLOCK_REALTIME, &ts)
|
||||
loc_tm := C.tm{}
|
||||
C.localtime_r(voidptr(&ts.tv_sec), &loc_tm)
|
||||
return convert_ctime(loc_tm, int(ts.tv_nsec / 1000))
|
||||
return convert_ctime(loc_tm, int(ts.tv_nsec))
|
||||
}
|
||||
|
||||
fn solaris_utc() Time {
|
||||
@ -18,7 +18,7 @@ fn solaris_utc() Time {
|
||||
// and use the nanoseconds part
|
||||
mut ts := C.timespec{}
|
||||
C.clock_gettime(C.CLOCK_REALTIME, &ts)
|
||||
return unix2(i64(ts.tv_sec), int(ts.tv_nsec / 1000))
|
||||
return unix_nanosecond(i64(ts.tv_sec), int(ts.tv_nsec))
|
||||
}
|
||||
|
||||
// dummy to compile with all compilers
|
||||
|
@ -1,18 +1,16 @@
|
||||
import time
|
||||
import math
|
||||
|
||||
const (
|
||||
time_to_test = time.Time{
|
||||
year: 1980
|
||||
month: 7
|
||||
day: 11
|
||||
hour: 21
|
||||
minute: 23
|
||||
second: 42
|
||||
microsecond: 123456
|
||||
unix: 332198622
|
||||
}
|
||||
)
|
||||
const time_to_test = time.Time{
|
||||
year: 1980
|
||||
month: 7
|
||||
day: 11
|
||||
hour: 21
|
||||
minute: 23
|
||||
second: 42
|
||||
nanosecond: 123456789
|
||||
unix: 332198622
|
||||
}
|
||||
|
||||
fn test_is_leap_year() {
|
||||
// 1996 % 4 = 0 and 1996 % 100 > 0
|
||||
@ -83,6 +81,14 @@ fn test_unix() {
|
||||
assert t6.second == 29
|
||||
}
|
||||
|
||||
fn test_format_rfc3339() {
|
||||
// assert '1980-07-11T19:23:42.123Z'
|
||||
res := time_to_test.format_rfc3339()
|
||||
assert res.ends_with('23:42.123Z')
|
||||
assert res.starts_with('1980-07-1')
|
||||
assert res.contains('T')
|
||||
}
|
||||
|
||||
fn test_format_ss() {
|
||||
assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy)
|
||||
}
|
||||
@ -93,20 +99,18 @@ fn test_format_ss_milli() {
|
||||
assert '1980-07-11 21:23:42.123' == time_to_test.format_ss_milli()
|
||||
}
|
||||
|
||||
fn test_format_rfc3339() {
|
||||
// assert '1980-07-11T19:23:42.123Z'
|
||||
res := time_to_test.format_rfc3339()
|
||||
assert res.ends_with('23:42.123Z')
|
||||
assert res.starts_with('1980-07-1')
|
||||
assert res.contains('T')
|
||||
}
|
||||
|
||||
fn test_format_ss_micro() {
|
||||
assert '11.07.1980 21:23:42.123456' == time_to_test.get_fmt_str(.dot, .hhmmss24_micro,
|
||||
.ddmmyyyy)
|
||||
assert '1980-07-11 21:23:42.123456' == time_to_test.format_ss_micro()
|
||||
}
|
||||
|
||||
fn test_format_ss_nano() {
|
||||
assert '11.07.1980 21:23:42.123456789' == time_to_test.get_fmt_str(.dot, .hhmmss24_nano,
|
||||
.ddmmyyyy)
|
||||
assert '1980-07-11 21:23:42.123456789' == time_to_test.format_ss_nano()
|
||||
}
|
||||
|
||||
fn test_smonth() {
|
||||
month_names := ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
|
||||
'Dec']
|
||||
@ -180,21 +184,29 @@ fn test_weekday_str() {
|
||||
|
||||
fn test_add() {
|
||||
d_seconds := 3
|
||||
d_microseconds := 13
|
||||
duration := time.Duration(d_seconds * time.second + d_microseconds * time.microsecond)
|
||||
d_nanoseconds := 13
|
||||
duration := time.Duration(d_seconds * time.second + d_nanoseconds * time.nanosecond)
|
||||
// dump(duration.debug())
|
||||
t1 := time_to_test
|
||||
// dump(t1.debug())
|
||||
t2 := time_to_test.add(duration)
|
||||
// dump(t2.debug())
|
||||
assert t2.second == t1.second + d_seconds
|
||||
assert t2.microsecond == t1.microsecond + d_microseconds
|
||||
assert t2.nanosecond == t1.nanosecond + d_nanoseconds
|
||||
assert t2.unix == t1.unix + d_seconds
|
||||
assert t2.is_local == t1.is_local
|
||||
//
|
||||
t3 := time_to_test.add(-duration)
|
||||
// dump(t3.debug())
|
||||
assert t3.second == t1.second - d_seconds
|
||||
assert t3.microsecond == t1.microsecond - d_microseconds
|
||||
assert t3.nanosecond == t1.nanosecond - d_nanoseconds
|
||||
assert t3.unix == t1.unix - d_seconds
|
||||
assert t3.is_local == t1.is_local
|
||||
//
|
||||
t4 := time_to_test.as_local()
|
||||
// dump(t4.debug())
|
||||
t5 := t4.add(duration)
|
||||
// dump(t5.debug())
|
||||
assert t5.is_local == t4.is_local
|
||||
}
|
||||
|
||||
@ -220,13 +232,14 @@ fn test_now() {
|
||||
assert now.minute < 60
|
||||
assert now.second >= 0
|
||||
assert now.second <= 60 // <= 60 cause of leap seconds
|
||||
assert now.microsecond >= 0
|
||||
assert now.microsecond < 1000000
|
||||
assert now.nanosecond >= 0
|
||||
assert now.nanosecond < time.second
|
||||
}
|
||||
|
||||
fn test_utc() {
|
||||
now := time.utc()
|
||||
// The year the test was built
|
||||
// dump(now.debug())
|
||||
assert now.year >= 2020
|
||||
assert now.month > 0
|
||||
assert now.month <= 12
|
||||
@ -234,20 +247,20 @@ fn test_utc() {
|
||||
assert now.minute < 60
|
||||
assert now.second >= 0
|
||||
assert now.second <= 60 // <= 60 cause of leap seconds
|
||||
assert now.microsecond >= 0
|
||||
assert now.microsecond < 1000000
|
||||
assert now.nanosecond >= 0
|
||||
assert now.nanosecond < time.second
|
||||
}
|
||||
|
||||
fn test_unix_time() {
|
||||
t1 := time.utc()
|
||||
time.sleep(50 * time.millisecond)
|
||||
t2 := time.utc()
|
||||
eprintln('t1: ${t1}')
|
||||
eprintln('t2: ${t2}')
|
||||
eprintln(' t1: ${t1}')
|
||||
eprintln(' t2: ${t2}')
|
||||
ut1 := t1.unix_time()
|
||||
ut2 := t2.unix_time()
|
||||
eprintln('ut1: ${ut1}')
|
||||
eprintln('ut2: ${ut2}')
|
||||
eprintln(' ut1: ${ut1}')
|
||||
eprintln(' ut2: ${ut2}')
|
||||
assert ut2 - ut1 < 2
|
||||
//
|
||||
utm1 := t1.unix_time_milli()
|
||||
|
@ -39,6 +39,8 @@ fn C.SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation &C.TIME_ZONE_INFORMAT
|
||||
|
||||
fn C.localtime_s(t &C.time_t, tm &C.tm)
|
||||
|
||||
fn C.timespec_get(t &C.timespec, base int) int
|
||||
|
||||
const (
|
||||
// start_time is needed on Darwin and Windows because of potential overflows
|
||||
start_time = init_win_time_start()
|
||||
@ -107,7 +109,7 @@ pub fn (t Time) local() Time {
|
||||
hour: u16(t.hour)
|
||||
minute: u16(t.minute)
|
||||
second: u16(t.second)
|
||||
millisecond: u16(t.microsecond / 1000)
|
||||
millisecond: u16(t.nanosecond / 1_000_000)
|
||||
}
|
||||
st_local := SystemTime{}
|
||||
C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, &st_utc, &st_local)
|
||||
@ -118,7 +120,7 @@ pub fn (t Time) local() Time {
|
||||
hour: st_local.hour
|
||||
minute: st_local.minute
|
||||
second: st_local.second // These are the same
|
||||
microsecond: int(st_local.millisecond) * 1000
|
||||
nanosecond: int(st_local.millisecond) * 1_000_000
|
||||
unix: st_local.unix_time()
|
||||
}
|
||||
return t_local
|
||||
@ -141,7 +143,7 @@ fn win_now() Time {
|
||||
hour: st_local.hour
|
||||
minute: st_local.minute
|
||||
second: st_local.second
|
||||
microsecond: int(st_local.millisecond) * 1000
|
||||
nanosecond: int(st_local.millisecond) * 1_000_000
|
||||
unix: st_local.unix_time()
|
||||
is_local: true
|
||||
}
|
||||
@ -163,7 +165,7 @@ fn win_utc() Time {
|
||||
hour: st_utc.hour
|
||||
minute: st_utc.minute
|
||||
second: st_utc.second
|
||||
microsecond: int(st_utc.millisecond) * 1000
|
||||
nanosecond: int(st_utc.millisecond) * 1_000_000
|
||||
unix: st_utc.unix_time()
|
||||
is_local: false
|
||||
}
|
||||
@ -213,12 +215,6 @@ fn solaris_utc() Time {
|
||||
return Time{}
|
||||
}
|
||||
|
||||
// dummy to compile with all compilers
|
||||
pub struct C.timeval {
|
||||
tv_sec u64
|
||||
tv_usec u64
|
||||
}
|
||||
|
||||
// sleep makes the calling thread sleep for a given duration (in nanoseconds).
|
||||
pub fn sleep(duration Duration) {
|
||||
C.Sleep(int(duration / millisecond))
|
||||
|
@ -3,7 +3,7 @@
|
||||
// that can be found in the LICENSE file.
|
||||
module time
|
||||
|
||||
// unix returns a time struct from Unix time.
|
||||
// unix returns a time struct from an Unix timestamp (number of seconds since 1970-01-01)
|
||||
pub fn unix(abs i64) Time {
|
||||
// Split into day and time
|
||||
mut day_offset := abs / seconds_per_day
|
||||
@ -24,8 +24,20 @@ pub fn unix(abs i64) Time {
|
||||
}
|
||||
}
|
||||
|
||||
// unix2 returns a time struct from Unix time and microsecond value
|
||||
// unix2 returns a Time struct, given an Unix timestamp in seconds, and a microsecond value
|
||||
[deprecated: 'use unix_microsecond(unix_ts, us) instead']
|
||||
[deprecated_after: '2023-09-05']
|
||||
pub fn unix2(abs i64, microsecond int) Time {
|
||||
return unix_nanosecond(abs, microsecond * 1000)
|
||||
}
|
||||
|
||||
// unix_microsecond returns a Time struct, given an Unix timestamp in seconds, and a microsecond value
|
||||
pub fn unix_microsecond(abs i64, microsecond int) Time {
|
||||
return unix_nanosecond(abs, microsecond * 1000)
|
||||
}
|
||||
|
||||
// unix_nanosecond returns a Time struct, given an Unix timestamp in seconds, and a nanosecond value
|
||||
pub fn unix_nanosecond(abs i64, nanosecond int) Time {
|
||||
// Split into day and time
|
||||
mut day_offset := abs / seconds_per_day
|
||||
if abs % seconds_per_day < 0 {
|
||||
@ -41,7 +53,7 @@ pub fn unix2(abs i64, microsecond int) Time {
|
||||
hour: hr
|
||||
minute: min
|
||||
second: sec
|
||||
microsecond: microsecond
|
||||
nanosecond: nanosecond
|
||||
unix: abs
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,13 @@ pub fn (t &Table) stringify_fn_decl(node &FnDecl, cur_mod string, m2a map[string
|
||||
f.write_string('pub ')
|
||||
}
|
||||
f.write_string('fn ')
|
||||
pre_comments := node.comments.filter(it.pos.pos < node.name_pos.pos)
|
||||
if pre_comments.len > 0 {
|
||||
write_comments(pre_comments, mut f)
|
||||
if !f.last_n(1)[0].is_space() {
|
||||
f.write_string(' ')
|
||||
}
|
||||
}
|
||||
if node.is_method {
|
||||
f.write_string('(')
|
||||
mut styp := util.no_cur_mod(t.type_to_code(node.receiver.typ.clear_flag(.shared_f)),
|
||||
@ -126,6 +133,7 @@ pub fn (t &Table) stringify_fn_decl(node &FnDecl, cur_mod string, m2a map[string
|
||||
|
||||
fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_mod string, m2a map[string]string) {
|
||||
mut add_para_types := true
|
||||
mut is_wrap_needed := false
|
||||
if node.generic_names.len > 0 {
|
||||
if node.is_method {
|
||||
sym := t.sym(node.params[0].typ)
|
||||
@ -161,6 +169,20 @@ fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_m
|
||||
is_type_only := param.name == ''
|
||||
should_add_type := true // is_last_param || is_type_only || node.params[i + 1].typ != param.typ ||
|
||||
// (node.is_variadic && i == node.params.len - 2)
|
||||
pre_comments := param.comments.filter(it.pos.pos < param.pos.pos)
|
||||
if pre_comments.len > 0 {
|
||||
if i == 0 && !pre_comments.last().is_inline {
|
||||
is_wrap_needed = true
|
||||
f.write_string('\n\t')
|
||||
}
|
||||
write_comments(pre_comments, mut f)
|
||||
if !f.last_n(1)[0].is_space() {
|
||||
f.write_string(' ')
|
||||
}
|
||||
}
|
||||
if is_wrap_needed {
|
||||
f.write_string('\t')
|
||||
}
|
||||
if param.is_mut {
|
||||
f.write_string(param.typ.share().str() + ' ')
|
||||
}
|
||||
@ -211,13 +233,50 @@ fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_m
|
||||
}
|
||||
}
|
||||
|
||||
fn write_comments(comments []Comment, mut f strings.Builder) {
|
||||
for i, c in comments {
|
||||
if !f.last_n(1)[0].is_space() {
|
||||
f.write_string(' ')
|
||||
}
|
||||
write_comment(c, mut f)
|
||||
if c.is_inline && i < comments.len - 1 && !c.is_multi {
|
||||
f.write_string(' ')
|
||||
} else if (!c.is_inline || c.is_multi) && i < comments.len - 1 {
|
||||
f.writeln('')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_comment(node Comment, mut f strings.Builder) {
|
||||
if node.is_inline {
|
||||
x := node.text.trim_left('\x01').trim_space()
|
||||
if x.contains('\n') {
|
||||
f.writeln('/*')
|
||||
f.writeln(x)
|
||||
f.write_string('*/')
|
||||
} else {
|
||||
f.write_string('/* ${x} */')
|
||||
}
|
||||
} else {
|
||||
mut s := node.text.trim_left('\x01').trim_right(' ')
|
||||
mut out_s := '//'
|
||||
if s != '' {
|
||||
if s[0].is_letter() || s[0].is_digit() {
|
||||
out_s += ' '
|
||||
}
|
||||
out_s += s
|
||||
}
|
||||
f.writeln(out_s)
|
||||
}
|
||||
}
|
||||
|
||||
struct StringifyModReplacement {
|
||||
mod string
|
||||
alias string
|
||||
weight int
|
||||
}
|
||||
|
||||
pub fn shorten_full_name_based_on_aliases(input string, m2a map[string]string) string {
|
||||
fn shorten_full_name_based_on_aliases(input string, m2a map[string]string) string {
|
||||
if m2a.len == 0 || -1 == input.index_u8(`.`) {
|
||||
// a simple typename, like `string` or `[]bool`; no module aliasings apply,
|
||||
// (or there just are not any mappings)
|
||||
|
@ -1779,7 +1779,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||
// cannot hide interface expected type to make possible to pass its interface type automatically
|
||||
earg_types << if targ.idx() != param.typ.idx() { param.typ } else { targ }
|
||||
} else {
|
||||
earg_types << targ
|
||||
earg_types << param.typ
|
||||
}
|
||||
param_share := param.typ.share()
|
||||
if param_share == .shared_t
|
||||
|
132
vlib/v/fmt/fmt.v
132
vlib/v/fmt/fmt.v
@ -1019,7 +1019,7 @@ pub fn (mut f Fmt) enum_decl(node ast.EnumDecl) {
|
||||
|
||||
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||
f.attrs(node.attrs)
|
||||
f.fn_header(node)
|
||||
f.write(f.table.stringify_fn_decl(&node, f.cur_mod, f.mod2alias))
|
||||
// Handle trailing comments after fn header declarations
|
||||
if node.no_body && node.end_comments.len > 0 {
|
||||
first_comment := node.end_comments[0]
|
||||
@ -1043,136 +1043,6 @@ pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||
f.fn_body(node)
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) fn_header(node ast.FnDecl) {
|
||||
if node.is_pub {
|
||||
f.write('pub ')
|
||||
}
|
||||
f.write('fn ')
|
||||
pre_comments := node.comments.filter(it.pos.pos < node.name_pos.pos)
|
||||
if pre_comments.len > 0 {
|
||||
f.comments(pre_comments)
|
||||
f.write(' ')
|
||||
}
|
||||
if node.is_method {
|
||||
f.write('(')
|
||||
mut styp := util.no_cur_mod(f.table.type_to_code(node.receiver.typ.clear_flag(.shared_f)),
|
||||
f.cur_mod)
|
||||
if node.rec_mut {
|
||||
f.write(node.receiver.typ.share().str() + ' ')
|
||||
styp = styp[1..] // remove &
|
||||
}
|
||||
f.write(node.receiver.name + ' ')
|
||||
styp = util.no_cur_mod(styp, f.cur_mod)
|
||||
if node.params[0].is_auto_rec {
|
||||
styp = styp.trim('&')
|
||||
}
|
||||
f.write(styp + ') ')
|
||||
} else if node.is_static_type_method {
|
||||
mut styp := util.no_cur_mod(f.table.type_to_code(node.receiver.typ.clear_flag(.shared_f)),
|
||||
f.cur_mod)
|
||||
f.write(styp + '.')
|
||||
}
|
||||
mut name := if !node.is_method && node.language == .v {
|
||||
node.name.all_after_last('.')
|
||||
} else {
|
||||
node.name
|
||||
}
|
||||
if node.is_static_type_method {
|
||||
name = name.after('__static__')
|
||||
}
|
||||
f.write(name)
|
||||
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
|
||||
f.write(' ')
|
||||
}
|
||||
mut add_para_types := true
|
||||
if node.generic_names.len > 0 {
|
||||
if node.is_method {
|
||||
sym := f.table.sym(node.params[0].typ)
|
||||
if sym.info is ast.Struct {
|
||||
generic_names := sym.info.generic_types.map(f.table.sym(it).name)
|
||||
if generic_names == node.generic_names {
|
||||
add_para_types = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if add_para_types {
|
||||
f.write('[')
|
||||
for i, gname in node.generic_names {
|
||||
is_last := i == node.generic_names.len - 1
|
||||
f.write(gname)
|
||||
if !is_last {
|
||||
f.write(', ')
|
||||
}
|
||||
}
|
||||
f.write(']')
|
||||
}
|
||||
}
|
||||
f.write('(')
|
||||
for i, arg in node.params {
|
||||
before_comments := arg.comments.filter(it.pos.pos < arg.pos.pos)
|
||||
if before_comments.len > 0 {
|
||||
f.comments(before_comments, level: .indent)
|
||||
}
|
||||
// skip receiver
|
||||
if node.is_method && i == 0 {
|
||||
continue
|
||||
}
|
||||
if arg.is_hidden {
|
||||
continue
|
||||
}
|
||||
is_last_arg := i == node.params.len - 1
|
||||
is_type_only := arg.name == ''
|
||||
should_add_type := true
|
||||
if arg.is_mut {
|
||||
f.write(arg.typ.share().str() + ' ')
|
||||
}
|
||||
f.write(arg.name)
|
||||
arg_sym := f.table.sym(arg.typ)
|
||||
if arg_sym.kind == .struct_ && (arg_sym.info as ast.Struct).is_anon {
|
||||
f.write(' struct {')
|
||||
struct_ := arg_sym.info as ast.Struct
|
||||
for field in struct_.fields {
|
||||
f.write(' ${field.name} ${f.table.type_to_str(field.typ)}')
|
||||
if field.has_default_expr {
|
||||
f.write(' = ${field.default_expr}')
|
||||
}
|
||||
}
|
||||
if struct_.fields.len > 0 {
|
||||
f.write(' ')
|
||||
}
|
||||
f.write('}')
|
||||
} else {
|
||||
mut s := f.table.type_to_str(arg.typ.clear_flag(.shared_f))
|
||||
if arg.is_mut {
|
||||
if s.starts_with('&') && ((!arg_sym.is_number() && arg_sym.kind != .bool)
|
||||
|| node.language != .v) {
|
||||
s = s[1..]
|
||||
}
|
||||
}
|
||||
s = util.no_cur_mod(s, f.cur_mod)
|
||||
s = ast.shorten_full_name_based_on_aliases(s, f.mod2alias)
|
||||
if should_add_type {
|
||||
if !is_type_only {
|
||||
f.write(' ')
|
||||
}
|
||||
if node.is_variadic && is_last_arg {
|
||||
f.write('...')
|
||||
}
|
||||
f.write(s)
|
||||
}
|
||||
}
|
||||
if !is_last_arg {
|
||||
f.write(', ')
|
||||
}
|
||||
}
|
||||
f.write(')')
|
||||
if node.return_type != ast.void_type {
|
||||
sreturn_type := util.no_cur_mod(f.table.type_to_str(node.return_type), f.cur_mod)
|
||||
short_sreturn_type := ast.shorten_full_name_based_on_aliases(sreturn_type, f.mod2alias)
|
||||
f.write(' ${short_sreturn_type}')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) anon_fn(node ast.AnonFn) {
|
||||
f.write(f.table.stringify_anon_decl(&node, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
||||
f.fn_body(node.decl)
|
||||
|
@ -3,6 +3,6 @@ fn /* main */ main() {
|
||||
}
|
||||
|
||||
fn // hi
|
||||
print_hi() {
|
||||
print_hi() {
|
||||
println('hi')
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
fn foo(
|
||||
// Foo
|
||||
s string) {
|
||||
}
|
||||
|
||||
fn bar( /* p1 */ a string, /* p2 */ b int) {
|
||||
println('hello')
|
||||
}
|
8
vlib/v/fmt/tests/fn_headers_with_param_comments_input.vv
Normal file
8
vlib/v/fmt/tests/fn_headers_with_param_comments_input.vv
Normal file
@ -0,0 +1,8 @@
|
||||
fn foo(
|
||||
// Foo
|
||||
s string) {
|
||||
}
|
||||
|
||||
fn bar(/*p1*/a string, /*p2*/b int) {
|
||||
println('hello')
|
||||
}
|
@ -11,7 +11,12 @@ recognized by the heuristic:
|
||||
tool_version = '1.2.1'
|
||||
version: '0.2.42'
|
||||
VERSION = "1.23.8"
|
||||
|
||||
|
||||
If certain lines need to be skipped, use the --skip option. For instance,
|
||||
the following command will skip lines containing "tool-version":
|
||||
|
||||
v bump --patch --skip "tool-version" [files...]
|
||||
|
||||
Examples:
|
||||
Bump the patch version in v.mod if it exists
|
||||
v bump --patch
|
||||
@ -22,7 +27,8 @@ Examples:
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Show this help text.
|
||||
-m, --major Bump the major version.
|
||||
-n, --minor Bump the minor version.
|
||||
-p, --patch Bump the patch version.
|
||||
-h, --help Show this help text.
|
||||
-m, --major Bump the major version.
|
||||
-n, --minor Bump the minor version.
|
||||
-p, --patch Bump the patch version.
|
||||
-s, --skip <string> Skip lines matching this substring.
|
||||
|
18
vlib/v/tests/struct_field_fn_call_test.v
Normal file
18
vlib/v/tests/struct_field_fn_call_test.v
Normal file
@ -0,0 +1,18 @@
|
||||
struct Foo {
|
||||
f fn (Foo) int = dummy
|
||||
}
|
||||
|
||||
fn dummy(s Foo) int {
|
||||
return 22
|
||||
}
|
||||
|
||||
fn (mut s Foo) fun() int {
|
||||
return s.f(s)
|
||||
}
|
||||
|
||||
fn test_struct_field_fn_call() {
|
||||
mut s := Foo{}
|
||||
ret := s.fun()
|
||||
println(ret)
|
||||
assert ret == 22
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user