...
This commit is contained in:
2403
aiprompts/v_advanced/advanced_topics.md
Normal file
2403
aiprompts/v_advanced/advanced_topics.md
Normal file
File diff suppressed because it is too large
Load Diff
124
aiprompts/v_advanced/html_parser.md
Normal file
124
aiprompts/v_advanced/html_parser.md
Normal file
@@ -0,0 +1,124 @@
|
||||
module net.html
|
||||
|
||||
net/html is an **HTML Parser** written in pure V.
|
||||
|
||||
## Usage
|
||||
|
||||
```v
|
||||
import net.html
|
||||
|
||||
fn main() {
|
||||
doc := html.parse('<html><body><h1 class="title">Hello world!</h1></body></html>')
|
||||
tag := doc.get_tags(name: 'h1')[0] // <h1>Hello world!</h1>
|
||||
println(tag.name) // h1
|
||||
println(tag.content) // Hello world!
|
||||
println(tag.attributes) // {'class':'title'}
|
||||
println(tag.str()) // <h1 class="title">Hello world!</h1>
|
||||
}
|
||||
```
|
||||
|
||||
More examples found on [`parser_test.v`](parser_test.v) and [`html_test.v`](html_test.v)
|
||||
|
||||
fn parse(text string) DocumentObjectModel
|
||||
parse parses and returns the DOM from the given text.
|
||||
|
||||
Note: this function converts tags to lowercase. E.g. <MyTag>content</MyTag> is parsed as <mytag>content</mytag>.
|
||||
fn parse_file(filename string) DocumentObjectModel
|
||||
parse_file parses and returns the DOM from the contents of a file.
|
||||
|
||||
Note: this function converts tags to lowercase. E.g. <MyTag>content</MyTag> is parsed as <mytag>content</mytag>.
|
||||
enum CloseTagType {
|
||||
in_name
|
||||
new_tag
|
||||
}
|
||||
struct DocumentObjectModel {
|
||||
mut:
|
||||
root &Tag = unsafe { nil }
|
||||
constructed bool
|
||||
btree BTree
|
||||
all_tags []&Tag
|
||||
all_attributes map[string][]&Tag
|
||||
close_tags map[string]bool // add a counter to see count how many times is closed and parse correctly
|
||||
attributes map[string][]string
|
||||
tag_attributes map[string][][]&Tag
|
||||
tag_type map[string][]&Tag
|
||||
debug_file os.File
|
||||
}
|
||||
The W3C Document Object Model (DOM) is a platform and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of a document.
|
||||
|
||||
https://www.w3.org/TR/WD-DOM/introduction.html
|
||||
fn (dom DocumentObjectModel) get_root() &Tag
|
||||
get_root returns the root of the document.
|
||||
fn (dom DocumentObjectModel) get_tag(name string) []&Tag
|
||||
get_tag retrieves all tags in the document that have the given tag name.
|
||||
fn (dom DocumentObjectModel) get_tags(options GetTagsOptions) []&Tag
|
||||
get_tags returns all tags stored in the document.
|
||||
fn (dom DocumentObjectModel) get_tags_by_class_name(names ...string) []&Tag
|
||||
get_tags_by_class_name retrieves all tags recursively in the document root that have the given class name(s).
|
||||
fn (dom DocumentObjectModel) get_tag_by_attribute(name string) []&Tag
|
||||
get_tag_by_attribute retrieves all tags in the document that have the given attribute name.
|
||||
fn (dom DocumentObjectModel) get_tags_by_attribute(name string) []&Tag
|
||||
get_tags_by_attribute retrieves all tags in the document that have the given attribute name.
|
||||
fn (mut dom DocumentObjectModel) get_tags_by_attribute_value(name string, value string) []&Tag
|
||||
get_tags_by_attribute_value retrieves all tags in the document that have the given attribute name and value.
|
||||
fn (mut dom DocumentObjectModel) get_tag_by_attribute_value(name string, value string) []&Tag
|
||||
get_tag_by_attribute_value retrieves all tags in the document that have the given attribute name and value.
|
||||
struct GetTagsOptions {
|
||||
pub:
|
||||
name string
|
||||
}
|
||||
struct Parser {
|
||||
mut:
|
||||
dom DocumentObjectModel
|
||||
lexical_attributes LexicalAttributes = LexicalAttributes{
|
||||
current_tag: &Tag{}
|
||||
}
|
||||
filename string = 'direct-parse'
|
||||
initialized bool
|
||||
tags []&Tag
|
||||
debug_file os.File
|
||||
}
|
||||
Parser is responsible for reading the HTML strings and converting them into a `DocumentObjectModel`.
|
||||
fn (mut parser Parser) add_code_tag(name string)
|
||||
This function is used to add a tag for the parser ignore it's content. For example, if you have an html or XML with a custom tag, like `<script>`, using this function, like `add_code_tag('script')` will make all `script` tags content be jumped, so you still have its content, but will not confuse the parser with it's `>` or `<`.
|
||||
fn (mut parser Parser) split_parse(data string)
|
||||
split_parse parses the HTML fragment
|
||||
fn (mut parser Parser) parse_html(data string)
|
||||
parse_html parses the given HTML string
|
||||
fn (mut parser Parser) finalize()
|
||||
finalize finishes the parsing stage .
|
||||
fn (mut parser Parser) get_dom() DocumentObjectModel
|
||||
get_dom returns the parser's current DOM representation.
|
||||
struct Tag {
|
||||
pub mut:
|
||||
name string
|
||||
content string
|
||||
children []&Tag
|
||||
attributes map[string]string // attributes will be like map[name]value
|
||||
last_attribute string
|
||||
class_set datatypes.Set[string]
|
||||
parent &Tag = unsafe { nil }
|
||||
position_in_parent int
|
||||
closed bool
|
||||
close_type CloseTagType = .in_name
|
||||
}
|
||||
Tag holds the information of an HTML tag.
|
||||
fn (tag Tag) text() string
|
||||
text returns the text contents of the tag.
|
||||
fn (tag &Tag) str() string
|
||||
fn (tag &Tag) get_tag(name string) ?&Tag
|
||||
get_tag retrieves the first found child tag in the tag that has the given tag name.
|
||||
fn (tag &Tag) get_tags(name string) []&Tag
|
||||
get_tags retrieves all child tags recursively in the tag that have the given tag name.
|
||||
fn (tag &Tag) get_tag_by_attribute(name string) ?&Tag
|
||||
get_tag_by_attribute retrieves the first found child tag in the tag that has the given attribute name.
|
||||
fn (tag &Tag) get_tags_by_attribute(name string) []&Tag
|
||||
get_tags_by_attribute retrieves all child tags recursively in the tag that have the given attribute name.
|
||||
fn (tag &Tag) get_tag_by_attribute_value(name string, value string) ?&Tag
|
||||
get_tag_by_attribute_value retrieves the first found child tag in the tag that has the given attribute name and value.
|
||||
fn (tag &Tag) get_tags_by_attribute_value(name string, value string) []&Tag
|
||||
get_tags_by_attribute_value retrieves all child tags recursively in the tag that have the given attribute name and value.
|
||||
fn (tag &Tag) get_tag_by_class_name(names ...string) ?&Tag
|
||||
get_tag_by_class_name retrieves the first found child tag in the tag that has the given class name(s).
|
||||
fn (tag &Tag) get_tags_by_class_name(names ...string) []&Tag
|
||||
get_tags_by_class_name retrieves all child tags recursively in the tag that have the given class name(s).
|
||||
105
aiprompts/v_advanced/io.md
Normal file
105
aiprompts/v_advanced/io.md
Normal file
@@ -0,0 +1,105 @@
|
||||
module io
|
||||
## Description
|
||||
|
||||
`io` provides common interfaces for buffered reading/writing of data.
|
||||
|
||||
const read_all_len = 10 * 1024
|
||||
const read_all_grow_len = 1024
|
||||
fn cp(mut src Reader, mut dst Writer) !
|
||||
cp copies from `src` to `dst` by allocating a maximum of 1024 bytes buffer for reading until either EOF is reached on `src` or an error occurs. An error is returned if an error is encountered during write.
|
||||
fn make_readerwriter(r Reader, w Writer) ReaderWriterImpl
|
||||
make_readerwriter takes a rstream and a wstream and makes an rwstream with them.
|
||||
fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader
|
||||
new_buffered_reader creates a new BufferedReader.
|
||||
fn new_multi_writer(writers ...Writer) Writer
|
||||
new_multi_writer returns a Writer that writes to all writers. The write function of the returned Writer writes to all writers of the MultiWriter, returns the length of bytes written, and if any writer fails to write the full length an error is returned and writing to other writers stops, and if any writer returns an error the error is returned immediately and writing to other writers stops.
|
||||
fn read_all(config ReadAllConfig) ![]u8
|
||||
read_all reads all bytes from a reader until either a 0 length read or if read_to_end_of_stream is true then the end of the stream (`none`).
|
||||
fn read_any(mut r Reader) ![]u8
|
||||
read_any reads any available bytes from a reader (until the reader returns a read of 0 length).
|
||||
interface RandomReader {
|
||||
read_from(pos u64, mut buf []u8) !int
|
||||
}
|
||||
RandomReader represents a stream of readable data from at a random location.
|
||||
interface RandomWriter {
|
||||
write_to(pos u64, buf []u8) !int
|
||||
}
|
||||
RandomWriter is the interface that wraps the `write_to` method, which writes `buf.len` bytes to the underlying data stream at a random `pos`.
|
||||
interface Reader {
|
||||
// read reads up to buf.len bytes and places
|
||||
// them into buf.
|
||||
// A type that implements this should return
|
||||
// `io.Eof` on end of stream (EOF) instead of just returning 0
|
||||
mut:
|
||||
read(mut buf []u8) !int
|
||||
}
|
||||
Reader represents a stream of data that can be read.
|
||||
interface ReaderWriter {
|
||||
Reader
|
||||
Writer
|
||||
}
|
||||
ReaderWriter represents a stream that can be read and written.
|
||||
interface Writer {
|
||||
mut:
|
||||
write(buf []u8) !int
|
||||
}
|
||||
Writer is the interface that wraps the `write` method, which writes `buf.len` bytes to the underlying data stream.
|
||||
fn (mut r ReaderWriterImpl) read(mut buf []u8) !int
|
||||
read reads up to `buf.len` bytes into `buf`. It returns the number of bytes read or any error encountered.
|
||||
fn (mut r ReaderWriterImpl) write(buf []u8) !int
|
||||
write writes `buf.len` bytes from `buf` to the underlying data stream. It returns the number of bytes written or any error encountered.
|
||||
struct BufferedReadLineConfig {
|
||||
pub:
|
||||
delim u8 = `\n` // line delimiter
|
||||
}
|
||||
BufferedReadLineConfig are options that can be given to the read_line() function.
|
||||
struct BufferedReader {
|
||||
mut:
|
||||
reader Reader
|
||||
buf []u8
|
||||
offset int // current offset in the buffer
|
||||
len int
|
||||
fails int // how many times fill_buffer has read 0 bytes in a row
|
||||
mfails int // maximum fails, after which we can assume that the stream has ended
|
||||
pub mut:
|
||||
end_of_stream bool // whether we reached the end of the upstream reader
|
||||
total_read int // total number of bytes read
|
||||
}
|
||||
BufferedReader provides a buffered interface for a reader.
|
||||
fn (mut r BufferedReader) read(mut buf []u8) !int
|
||||
read fufills the Reader interface.
|
||||
fn (mut r BufferedReader) free()
|
||||
free deallocates the memory for a buffered reader's internal buffer.
|
||||
fn (r BufferedReader) end_of_stream() bool
|
||||
end_of_stream returns whether the end of the stream was reached.
|
||||
fn (mut r BufferedReader) read_line(config BufferedReadLineConfig) !string
|
||||
read_line attempts to read a line from the buffered reader. It will read until it finds the specified line delimiter such as (\n, the default or \0) or the end of stream.
|
||||
struct BufferedReaderConfig {
|
||||
pub:
|
||||
reader Reader
|
||||
cap int = 128 * 1024 // large for fast reading of big(ish) files
|
||||
retries int = 2 // how many times to retry before assuming the stream ended
|
||||
}
|
||||
BufferedReaderConfig are options that can be given to a buffered reader.
|
||||
struct Eof {
|
||||
Error
|
||||
}
|
||||
/ Eof error means that we reach the end of the stream.
|
||||
struct MultiWriter {
|
||||
pub mut:
|
||||
writers []Writer
|
||||
}
|
||||
MultiWriter writes to all its writers.
|
||||
fn (mut m MultiWriter) write(buf []u8) !int
|
||||
write writes to all writers of the MultiWriter. Returns the length of bytes written. If any writer fails to write the full length an error is returned and writing to other writers stops. If any writer returns an error the error is returned immediately and writing to other writers stops.
|
||||
struct NotExpected {
|
||||
cause string
|
||||
code int
|
||||
}
|
||||
NotExpected is a generic error that means that we receave a not expected error.
|
||||
struct ReadAllConfig {
|
||||
pub:
|
||||
read_to_end_of_stream bool
|
||||
reader Reader
|
||||
}
|
||||
ReadAllConfig allows options to be passed for the behaviour of read_all.
|
||||
354
aiprompts/v_advanced/net.md
Normal file
354
aiprompts/v_advanced/net.md
Normal file
@@ -0,0 +1,354 @@
|
||||
module net
|
||||
## Description
|
||||
|
||||
`net` provides networking functions. It is mostly a wrapper to BSD sockets, so you can listen on a port, connect to remote TCP/UDP services, and communicate with them.
|
||||
|
||||
const msg_nosignal = 0x4000
|
||||
const err_connection_refused = error_with_code('net: connection refused', errors_base + 10)
|
||||
const err_option_wrong_type = error_with_code('net: set_option_xxx option wrong type',
|
||||
errors_base + 3)
|
||||
const opts_can_set = [
|
||||
SocketOption.broadcast,
|
||||
.debug,
|
||||
.dont_route,
|
||||
.keep_alive,
|
||||
.linger,
|
||||
.oob_inline,
|
||||
.receive_buf_size,
|
||||
.receive_low_size,
|
||||
.receive_timeout,
|
||||
.send_buf_size,
|
||||
.send_low_size,
|
||||
.send_timeout,
|
||||
.ipv6_only,
|
||||
]
|
||||
const error_eagain = C.EAGAIN
|
||||
const err_port_out_of_range = error_with_code('net: port out of range', errors_base + 5)
|
||||
const opts_bool = [SocketOption.broadcast, .debug, .dont_route, .error, .keep_alive, .oob_inline]
|
||||
const err_connect_failed = error_with_code('net: connect failed', errors_base + 7)
|
||||
const errors_base = 0
|
||||
Well defined errors that are returned from socket functions
|
||||
const opts_int = [
|
||||
SocketOption.receive_buf_size,
|
||||
.receive_low_size,
|
||||
.receive_timeout,
|
||||
.send_buf_size,
|
||||
.send_low_size,
|
||||
.send_timeout,
|
||||
]
|
||||
const error_eintr = C.EINTR
|
||||
const error_ewouldblock = C.EWOULDBLOCK
|
||||
const err_no_udp_remote = error_with_code('net: no udp remote', errors_base + 6)
|
||||
const error_einprogress = C.EINPROGRESS
|
||||
const err_timed_out_code = errors_base + 9
|
||||
const err_connect_timed_out = error_with_code('net: connect timed out', errors_base + 8)
|
||||
const err_new_socket_failed = error_with_code('net: new_socket failed to create socket',
|
||||
errors_base + 1)
|
||||
const msg_dontwait = C.MSG_DONTWAIT
|
||||
const infinite_timeout = time.infinite
|
||||
infinite_timeout should be given to functions when an infinite_timeout is wanted (i.e. functions only ever return with data)
|
||||
const no_timeout = time.Duration(0)
|
||||
no_timeout should be given to functions when no timeout is wanted (i.e. all functions return instantly)
|
||||
const err_timed_out = error_with_code('net: op timed out', errors_base + 9)
|
||||
const tcp_default_read_timeout = 30 * time.second
|
||||
const err_option_not_settable = error_with_code('net: set_option_xxx option not settable',
|
||||
errors_base + 2)
|
||||
const tcp_default_write_timeout = 30 * time.second
|
||||
fn addr_from_socket_handle(handle int) Addr
|
||||
addr_from_socket_handle returns an address, based on the given integer socket `handle`
|
||||
fn close(handle int) !
|
||||
close a socket, given its file descriptor `handle`. In non-blocking mode, if `close()` does not succeed immediately, it causes an error to be propagated to `TcpSocket.close()`, which is not intended. Therefore, `select` is used just like `connect()`.
|
||||
fn default_tcp_dialer() Dialer
|
||||
default_tcp_dialer will give you an instance of Dialer, that is suitable for making new tcp connections.
|
||||
fn dial_tcp(oaddress string) !&TcpConn
|
||||
dial_tcp will try to create a new TcpConn to the given address.
|
||||
fn dial_tcp_with_bind(saddr string, laddr string) !&TcpConn
|
||||
dial_tcp_with_bind will bind the given local address `laddr` and dial.
|
||||
fn dial_udp(raddr string) !&UdpConn
|
||||
fn error_code() int
|
||||
fn listen_tcp(family AddrFamily, saddr string, options ListenOptions) !&TcpListener
|
||||
fn listen_udp(laddr string) !&UdpConn
|
||||
fn new_ip(port u16, addr [4]u8) Addr
|
||||
new_ip creates a new Addr from the IPv4 address family, based on the given port and addr
|
||||
fn new_ip6(port u16, addr [16]u8) Addr
|
||||
new_ip6 creates a new Addr from the IP6 address family, based on the given port and addr
|
||||
fn peer_addr_from_socket_handle(handle int) !Addr
|
||||
peer_addr_from_socket_handle retrieves the ip address and port number, given a socket handle
|
||||
fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ![]Addr
|
||||
resolve_addrs converts the given `addr`, `family` and `@type` to a list of addresses
|
||||
fn resolve_addrs_fuzzy(addr string, @type SocketType) ![]Addr
|
||||
resolve_addrs converts the given `addr` and `@type` to a list of addresses
|
||||
fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr
|
||||
resolve_ipaddrs converts the given `addr`, `family` and `typ` to a list of addresses
|
||||
fn set_blocking(handle int, state bool) !
|
||||
set_blocking will change the state of the socket to either blocking, when state is true, or non blocking (false).
|
||||
fn shutdown(handle int, config ShutdownConfig) int
|
||||
shutdown shutsdown a socket, given its file descriptor `handle`. By default it shuts it down in both directions, both for reading and for writing. You can change that using `net.shutdown(handle, how: .read)` or `net.shutdown(handle, how: .write)` In non-blocking mode, `shutdown()` may not succeed immediately, so `select` is also used to make sure that the function doesn't return an incorrect result.
|
||||
fn socket_error(potential_code int) !int
|
||||
fn socket_error_message(potential_code int, s string) !int
|
||||
fn split_address(addr string) !(string, u16)
|
||||
split_address splits an address into its host name and its port
|
||||
fn tcp_socket_from_handle_raw(sockfd int) TcpSocket
|
||||
tcp_socket_from_handle_raw is similar to tcp_socket_from_handle, but it does not modify any socket options
|
||||
fn validate_port(port int) !u16
|
||||
validate_port checks whether a port is valid and returns the port or an error
|
||||
fn wrap_error(error_code int) !
|
||||
interface Connection {
|
||||
addr() !Addr
|
||||
peer_addr() !Addr
|
||||
mut:
|
||||
read(mut []u8) !int
|
||||
write([]u8) !int
|
||||
close() !
|
||||
}
|
||||
Connection provides a generic SOCK_STREAM style interface that protocols can use as a base connection object to support TCP, UNIX Domain Sockets and various proxying solutions.
|
||||
interface Dialer {
|
||||
dial(address string) !Connection
|
||||
}
|
||||
Dialer is an abstract dialer interface for producing connections to adresses.
|
||||
fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) !
|
||||
fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) !
|
||||
fn (mut s TcpSocket) set_dualstack(on bool) !
|
||||
fn (mut s TcpSocket) bind(addr string) !
|
||||
bind a local rddress for TcpSocket
|
||||
fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) !
|
||||
fn (mut s UdpSocket) set_dualstack(on bool) !
|
||||
enum AddrFamily {
|
||||
unix = C.AF_UNIX
|
||||
ip = C.AF_INET
|
||||
ip6 = C.AF_INET6
|
||||
unspec = C.AF_UNSPEC
|
||||
}
|
||||
AddrFamily are the available address families
|
||||
enum ShutdownDirection {
|
||||
read
|
||||
write
|
||||
read_and_write
|
||||
}
|
||||
ShutdownDirection is used by `net.shutdown`, for specifying the direction for which the communication will be cut.
|
||||
enum SocketOption {
|
||||
// TODO: SO_ACCEPT_CONN is not here because windows doesn't support it
|
||||
// and there is no easy way to define it
|
||||
broadcast = C.SO_BROADCAST
|
||||
debug = C.SO_DEBUG
|
||||
dont_route = C.SO_DONTROUTE
|
||||
error = C.SO_ERROR
|
||||
keep_alive = C.SO_KEEPALIVE
|
||||
linger = C.SO_LINGER
|
||||
oob_inline = C.SO_OOBINLINE
|
||||
reuse_addr = C.SO_REUSEADDR
|
||||
receive_buf_size = C.SO_RCVBUF
|
||||
receive_low_size = C.SO_RCVLOWAT
|
||||
receive_timeout = C.SO_RCVTIMEO
|
||||
send_buf_size = C.SO_SNDBUF
|
||||
send_low_size = C.SO_SNDLOWAT
|
||||
send_timeout = C.SO_SNDTIMEO
|
||||
socket_type = C.SO_TYPE
|
||||
ipv6_only = C.IPV6_V6ONLY
|
||||
}
|
||||
enum SocketType {
|
||||
udp = C.SOCK_DGRAM
|
||||
tcp = C.SOCK_STREAM
|
||||
seqpacket = C.SOCK_SEQPACKET
|
||||
}
|
||||
SocketType are the available sockets
|
||||
struct Addr {
|
||||
pub:
|
||||
len u8
|
||||
f u8
|
||||
addr AddrData
|
||||
}
|
||||
fn (a Addr) family() AddrFamily
|
||||
family returns the family/kind of the given address `a`
|
||||
fn (a Addr) len() u32
|
||||
len returns the length in bytes of the address `a`, depending on its family
|
||||
fn (a Addr) port() !u16
|
||||
port returns the ip or ip6 port of the given address `a`
|
||||
fn (a Addr) str() string
|
||||
str returns a string representation of the address `a`
|
||||
struct C.addrinfo {
|
||||
mut:
|
||||
ai_family int
|
||||
ai_socktype int
|
||||
ai_flags int
|
||||
ai_protocol int
|
||||
ai_addrlen int
|
||||
ai_addr voidptr
|
||||
ai_canonname voidptr
|
||||
ai_next voidptr
|
||||
}
|
||||
struct C.fd_set {}
|
||||
struct C.sockaddr_in {
|
||||
mut:
|
||||
sin_len u8
|
||||
sin_family u8
|
||||
sin_port u16
|
||||
sin_addr u32
|
||||
sin_zero [8]char
|
||||
}
|
||||
struct C.sockaddr_in6 {
|
||||
mut:
|
||||
// 1 + 1 + 2 + 4 + 16 + 4 = 28;
|
||||
sin6_len u8 // 1
|
||||
sin6_family u8 // 1
|
||||
sin6_port u16 // 2
|
||||
sin6_flowinfo u32 // 4
|
||||
sin6_addr [16]u8 // 16
|
||||
sin6_scope_id u32 // 4
|
||||
}
|
||||
struct C.sockaddr_un {
|
||||
mut:
|
||||
sun_len u8
|
||||
sun_family u8
|
||||
sun_path [max_unix_path]char
|
||||
}
|
||||
struct Ip {
|
||||
port u16
|
||||
addr [4]u8
|
||||
// Pad to size so that socket functions
|
||||
// dont complain to us (see in.h and bind())
|
||||
// TODO(emily): I would really like to use
|
||||
// some constant calculations here
|
||||
// so that this doesnt have to be hardcoded
|
||||
sin_pad [8]u8
|
||||
}
|
||||
fn (a Ip) str() string
|
||||
str returns a string representation of `a`
|
||||
struct Ip6 {
|
||||
port u16
|
||||
flow_info u32
|
||||
addr [16]u8
|
||||
scope_id u32
|
||||
}
|
||||
fn (a Ip6) str() string
|
||||
str returns a string representation of `a`
|
||||
struct ListenOptions {
|
||||
pub:
|
||||
dualstack bool = true
|
||||
backlog int = 128
|
||||
}
|
||||
struct ShutdownConfig {
|
||||
pub:
|
||||
how ShutdownDirection = .read_and_write
|
||||
}
|
||||
struct Socket {
|
||||
pub:
|
||||
handle int
|
||||
}
|
||||
fn (s &Socket) address() !Addr
|
||||
address gets the address of a socket
|
||||
struct TCPDialer {}
|
||||
TCPDialer is a concrete instance of the Dialer interface, for creating tcp connections.
|
||||
fn (t TCPDialer) dial(address string) !Connection
|
||||
dial will try to create a new abstract connection to the given address. It will return an error, if that is not possible.
|
||||
struct TcpConn {
|
||||
pub mut:
|
||||
sock TcpSocket
|
||||
handle int
|
||||
write_deadline time.Time
|
||||
read_deadline time.Time
|
||||
read_timeout time.Duration
|
||||
write_timeout time.Duration
|
||||
is_blocking bool = true
|
||||
}
|
||||
fn (c &TcpConn) addr() !Addr
|
||||
fn (mut c TcpConn) close() !
|
||||
close closes the tcp connection
|
||||
fn (mut con TcpConn) get_blocking() bool
|
||||
get_blocking returns whether the connection is in a blocking state, that is calls to .read_line, C.recv etc will block till there is new data arrived, instead of returning immediately.
|
||||
fn (c &TcpConn) peer_addr() !Addr
|
||||
peer_addr retrieves the ip address and port number used by the peer
|
||||
fn (c &TcpConn) peer_ip() !string
|
||||
peer_ip retrieves the ip address used by the peer, and returns it as a string
|
||||
fn (c TcpConn) read(mut buf []u8) !int
|
||||
read reads data from the tcp connection into the mutable buffer `buf`. The number of bytes read is limited to the length of the buffer `buf.len`. The returned value is the number of read bytes (between 0 and `buf.len`).
|
||||
fn (mut c TcpConn) read_deadline() !time.Time
|
||||
fn (mut con TcpConn) read_line() string
|
||||
read_line is a *simple*, *non customizable*, blocking line reader. It will return a line, ending with LF, or just '', on EOF.
|
||||
|
||||
Note: if you want more control over the buffer, please use a buffered IO reader instead: `io.new_buffered_reader({reader: io.make_reader(con)})`
|
||||
fn (mut con TcpConn) read_line_max(max_line_len int) string
|
||||
read_line_max is a *simple*, *non customizable*, blocking line reader. It will return a line, ending with LF, '' on EOF. It stops reading, when the result line length exceeds max_line_len.
|
||||
fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int
|
||||
read_ptr reads data from the tcp connection to the given buffer. It reads at most `len` bytes. It returns the number of actually read bytes, which can vary between 0 to `len`.
|
||||
fn (c &TcpConn) read_timeout() time.Duration
|
||||
fn (mut con TcpConn) set_blocking(state bool) !
|
||||
set_blocking will change the state of the connection to either blocking, when state is true, or non blocking (false). The default for `net` tcp connections is the blocking mode. Calling .read_line will set the connection to blocking mode. In general, changing the blocking mode after a successful connection may cause unexpected surprises, so this function is not recommended to be called anywhere but for this file.
|
||||
fn (mut c TcpConn) set_read_deadline(deadline time.Time)
|
||||
fn (mut c TcpConn) set_read_timeout(t time.Duration)
|
||||
fn (mut c TcpConn) set_sock() !
|
||||
set_sock initialises the c.sock field. It should be called after `.accept_only()!`.
|
||||
|
||||
Note: just use `.accept()!`. In most cases it is simpler, and calls `.set_sock()!` for you.
|
||||
fn (mut c TcpConn) set_write_deadline(deadline time.Time)
|
||||
fn (mut c TcpConn) set_write_timeout(t time.Duration)
|
||||
fn (c TcpConn) str() string
|
||||
fn (c TcpConn) wait_for_read() !
|
||||
fn (mut c TcpConn) wait_for_write() !
|
||||
fn (mut c TcpConn) write(bytes []u8) !int
|
||||
write blocks and attempts to write all data
|
||||
fn (mut c TcpConn) write_deadline() !time.Time
|
||||
fn (mut c TcpConn) write_ptr(b &u8, len int) !int
|
||||
write_ptr blocks and attempts to write all data
|
||||
fn (mut c TcpConn) write_string(s string) !int
|
||||
write_string blocks and attempts to write all data
|
||||
fn (c &TcpConn) write_timeout() time.Duration
|
||||
struct TcpListener {
|
||||
pub mut:
|
||||
sock TcpSocket
|
||||
accept_timeout time.Duration
|
||||
accept_deadline time.Time
|
||||
is_blocking bool = true
|
||||
}
|
||||
fn (mut l TcpListener) accept() !&TcpConn
|
||||
accept a tcp connection from an external source to the listener `l`.
|
||||
fn (mut l TcpListener) accept_only() !&TcpConn
|
||||
accept_only accepts a tcp connection from an external source to the listener `l`. Unlike `accept`, `accept_only` *will not call* `.set_sock()!` on the result, and is thus faster.
|
||||
|
||||
|
||||
|
||||
Note: you *need* to call `.set_sock()!` manually, before using theconnection after calling `.accept_only()!`, but that does not have to happen in the same thread that called `.accept_only()!`. The intention of this API, is to have a more efficient way to accept connections, that are later processed by a thread pool, while the main thread remains active, so that it can accept other connections. See also vlib/vweb/vweb.v .
|
||||
|
||||
If you do not need that, just call `.accept()!` instead, which will call `.set_sock()!` for you.
|
||||
fn (c &TcpListener) accept_deadline() !time.Time
|
||||
fn (mut c TcpListener) set_accept_deadline(deadline time.Time)
|
||||
fn (c &TcpListener) accept_timeout() time.Duration
|
||||
fn (mut c TcpListener) set_accept_timeout(t time.Duration)
|
||||
fn (mut c TcpListener) wait_for_accept() !
|
||||
fn (mut c TcpListener) close() !
|
||||
fn (c &TcpListener) addr() !Addr
|
||||
struct UdpConn {
|
||||
pub mut:
|
||||
sock UdpSocket
|
||||
mut:
|
||||
write_deadline time.Time
|
||||
read_deadline time.Time
|
||||
read_timeout time.Duration
|
||||
write_timeout time.Duration
|
||||
}
|
||||
fn (mut c UdpConn) write_ptr(b &u8, len int) !int
|
||||
sock := UdpSocket{ handle: sbase.handle l: local r: resolve_wrapper(raddr) } }
|
||||
fn (mut c UdpConn) write(buf []u8) !int
|
||||
fn (mut c UdpConn) write_string(s string) !int
|
||||
fn (mut c UdpConn) write_to_ptr(addr Addr, b &u8, len int) !int
|
||||
fn (mut c UdpConn) write_to(addr Addr, buf []u8) !int
|
||||
write_to blocks and writes the buf to the remote addr specified
|
||||
fn (mut c UdpConn) write_to_string(addr Addr, s string) !int
|
||||
write_to_string blocks and writes the buf to the remote addr specified
|
||||
fn (mut c UdpConn) read(mut buf []u8) !(int, Addr)
|
||||
read reads from the socket into buf up to buf.len returning the number of bytes read
|
||||
fn (c &UdpConn) read_deadline() !time.Time
|
||||
fn (mut c UdpConn) set_read_deadline(deadline time.Time)
|
||||
fn (c &UdpConn) write_deadline() !time.Time
|
||||
fn (mut c UdpConn) set_write_deadline(deadline time.Time)
|
||||
fn (c &UdpConn) read_timeout() time.Duration
|
||||
fn (mut c UdpConn) set_read_timeout(t time.Duration)
|
||||
fn (c &UdpConn) write_timeout() time.Duration
|
||||
fn (mut c UdpConn) set_write_timeout(t time.Duration)
|
||||
fn (mut c UdpConn) wait_for_read() !
|
||||
fn (mut c UdpConn) wait_for_write() !
|
||||
fn (c &UdpConn) str() string
|
||||
fn (mut c UdpConn) close() !
|
||||
struct Unix {
|
||||
path [max_unix_path]char
|
||||
}
|
||||
187
aiprompts/v_advanced/reflection.md
Normal file
187
aiprompts/v_advanced/reflection.md
Normal file
@@ -0,0 +1,187 @@
|
||||
## Compile time reflection
|
||||
|
||||
$ is used as a prefix for compile time (also referred to as 'comptime') operations.
|
||||
|
||||
Having built-in JSON support is nice, but V also allows you to create efficient serializers for any data format. V has compile time if and for constructs:
|
||||
|
||||
.fields
|
||||
You can iterate over struct fields using .fields, it also works with generic types (e.g. T.fields) and generic arguments (e.g. param.fields where fn gen[T](param T) {).
|
||||
|
||||
struct User {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
$for field in User.fields {
|
||||
$if field.typ is string {
|
||||
println('${field.name} is of type string')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// name is of type string
|
||||
.values
|
||||
You can read Enum values and their attributes.
|
||||
|
||||
enum Color {
|
||||
red @[RED] // first attribute
|
||||
blue @[BLUE] // second attribute
|
||||
}
|
||||
|
||||
fn main() {
|
||||
$for e in Color.values {
|
||||
println(e.name)
|
||||
println(e.attrs)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// red
|
||||
// ['RED']
|
||||
// blue
|
||||
// ['BLUE']
|
||||
.attributes
|
||||
You can read Struct attributes.
|
||||
|
||||
@[COLOR]
|
||||
struct Foo {
|
||||
a int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
$for e in Foo.attributes {
|
||||
println(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// StructAttribute{
|
||||
// name: 'COLOR'
|
||||
// has_arg: false
|
||||
// arg: ''
|
||||
// kind: plain
|
||||
// }
|
||||
.variants
|
||||
You can read variant types from Sum type.
|
||||
|
||||
type MySum = int | string
|
||||
|
||||
fn main() {
|
||||
$for v in MySum.variants {
|
||||
$if v.typ is int {
|
||||
println('has int type')
|
||||
} $else $if v.typ is string {
|
||||
println('has string type')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// has int type
|
||||
// has string type
|
||||
.methods
|
||||
You can retrieve information about struct methods.
|
||||
|
||||
struct Foo {
|
||||
}
|
||||
|
||||
fn (f Foo) test() int {
|
||||
return 123
|
||||
}
|
||||
|
||||
fn (f Foo) test2() string {
|
||||
return 'foo'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo := Foo{}
|
||||
$for m in Foo.methods {
|
||||
$if m.return_type is int {
|
||||
print('${m.name} returns int: ')
|
||||
println(foo.$method())
|
||||
} $else $if m.return_type is string {
|
||||
print('${m.name} returns string: ')
|
||||
println(foo.$method())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test returns int: 123
|
||||
// test2 returns string: foo
|
||||
.params
|
||||
You can retrieve information about struct method params.
|
||||
|
||||
struct Test {
|
||||
}
|
||||
|
||||
fn (t Test) foo(arg1 int, arg2 string) {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
$for m in Test.methods {
|
||||
$for param in m.params {
|
||||
println('${typeof(param.typ).name}: ${param.name}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// int: arg1
|
||||
// string: arg2
|
||||
|
||||
## Example
|
||||
|
||||
```v
|
||||
// An example deserializer implementation
|
||||
|
||||
struct User {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
data := 'name=Alice\nage=18'
|
||||
user := decode[User](data)
|
||||
println(user)
|
||||
}
|
||||
|
||||
fn decode[T](data string) T {
|
||||
mut result := T{}
|
||||
// compile-time `for` loop
|
||||
// T.fields gives an array of a field metadata type
|
||||
$for field in T.fields {
|
||||
$if field.typ is string {
|
||||
// $(string_expr) produces an identifier
|
||||
result.$(field.name) = get_string(data, field.name)
|
||||
} $else $if field.typ is int {
|
||||
result.$(field.name) = get_int(data, field.name)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fn get_string(data string, field_name string) string {
|
||||
for line in data.split_into_lines() {
|
||||
key_val := line.split('=')
|
||||
if key_val[0] == field_name {
|
||||
return key_val[1]
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
fn get_int(data string, field string) int {
|
||||
return get_string(data, field).int()
|
||||
}
|
||||
|
||||
// `decode<User>` generates:
|
||||
// fn decode_User(data string) User {
|
||||
// mut result := User{}
|
||||
// result.name = get_string(data, 'name')
|
||||
// result.age = get_int(data, 'age')
|
||||
// return result
|
||||
// }
|
||||
```
|
||||
516
aiprompts/v_advanced/regex.md
Normal file
516
aiprompts/v_advanced/regex.md
Normal file
@@ -0,0 +1,516 @@
|
||||
|
||||
# Regex Library
|
||||
|
||||
#### Differences with PCRE:
|
||||
|
||||
> regex is not PCRE compatible.
|
||||
|
||||
- The basic element is the token not the sequence of symbols, and the mostsimple token, is a single character.
|
||||
| the OR operator acts on tokens, for example abc|ebc is notabc OR ebc. Instead it is evaluated like ab, followed by c OR e, followed by bc, because the token is the base element, not the sequence of symbols.
|
||||
- Two char classes with an OR in the middle is a syntax error.
|
||||
- The match operation stops at the end of the string. It does NOT stopat new line characters.
|
||||
- The tokens are the atomic units, used by this regex engine. They can be one of the following:
|
||||
- Simple char, This token is a simple single character like a or b etc.
|
||||
- Match positional delimiters
|
||||
- ^ Matches the start of the string.
|
||||
- $ Matches the end of the string.
|
||||
|
||||
#### Char class (cc)
|
||||
|
||||
- The character classes match all the chars specified inside. Use square brackets [ ] to enclose them.
|
||||
- The sequence of the chars in the character class, is evaluated with an OR op.
|
||||
- For example, the cc [abc], matches any character, that is a or b or c, but it doesn't match C or z.
|
||||
- Inside a cc, it is possible to specify a "range" of characters, for example [ad-h] is equivalent to writing [adefgh].
|
||||
- A cc can have different ranges at the same time, for example [a-zA-Z0-9] matches all the latin lowercase, uppercase and numeric characters.
|
||||
- It is possible to negate the meaning of a cc, using the caret char at the start of the cc like this: [^abc] . That matches every char that is NOT a or b or c.
|
||||
- A cc can contain meta-chars like: [a-z\d], that match all the lowercase latin chars a-z and all the digits \d.
|
||||
- It is possible to mix all the properties of the char class together.
|
||||
- Note > In order to match the - (minus) char, it must be preceded by > a backslash in the cc, for example [\-_\d\a] will match: > - - minus, > - _ underscore, > - \d numeric chars, > - \a lower case chars.
|
||||
|
||||
#### Meta-chars
|
||||
|
||||
- A meta-char is specified by a backslash, before a character. For example \w is the meta-char w.
|
||||
- A meta-char can match different types of characters.
|
||||
- \w matches a word char [a-zA-Z0-9_]
|
||||
- \W matches a non word char
|
||||
- \d matches a digit [0-9]
|
||||
- \D matches a non digit
|
||||
- \s matches a space char, one of [' ','\t','\n','\r','\v','\f']
|
||||
- \S matches a non space char
|
||||
- \a matches only a lowercase char [a-z]
|
||||
- \A matches only an uppercase char [A-Z]
|
||||
- \x41 match a byte of value 0x41, A in ascii code
|
||||
- \X414C match two consecutive bytes of value 0x414c, AL in ascii code
|
||||
|
||||
#### Quantifiers
|
||||
|
||||
Each token can have a quantifier, that specifies how many times the character must be matched.
|
||||
|
||||
Short quantifiers
|
||||
|
||||
- ? matches 0 or 1 time, a?b matches both ab or b
|
||||
- + matches at least 1 time, for example, a+ matches both aaa or a
|
||||
- * matches 0 or more times, for example, a*b matches aaab, ab or b
|
||||
|
||||
Long quantifiers
|
||||
|
||||
- {x} matches exactly x times, a{2} matches aa, but not aaa or a
|
||||
- {min,} matches at least min times, a{2,} matches aaa or aa, not a
|
||||
- {,max} matches at least 0 times and at maximum max times,for example, a{,2} matches a and aa, but doesn't match aaa- {min,max} matches from min times, to max times, for examplea{2,3} matches aa and aaa, but doesn't match a or aaaa
|
||||
- A long quantifier, may have a greedy off flag, that is the ? character after the brackets. {2,4}? means to match the minimum number of possible tokens, in this case 2.
|
||||
|
||||
|
||||
#### dot char
|
||||
|
||||
The dot is a particular meta-char, that matches "any char".
|
||||
|
||||
input:
|
||||
|
||||
'''abccc ddeef'''
|
||||
|
||||
The following table shows the query strings and the result of parsing source string.
|
||||
|
||||
| query string | result |
|
||||
|--------------|---------|
|
||||
| `.*c` | `abc` |
|
||||
| `.*dd` | `abcc dd` |
|
||||
| `ab.*e` | `abccc dde`|
|
||||
| `ab.{3} .*e` | `abccc dde`|
|
||||
|
||||
- The dot matches any character, until the next token match is satisfied.
|
||||
- Important Note: Consecutive dots, for example ..., are not allowed. > This will cause a syntax error. Use a quantifier instead.
|
||||
|
||||
OR token
|
||||
The token |, means a logic OR operation between two consecutive tokens, i.e. a|b matches a character that is a or b.
|
||||
|
||||
The OR token can work in a "chained way": a|(b)|cd means test first a, if the char is not a, then test the group (b), and if the group doesn't match too, finally test the token c.
|
||||
|
||||
Note > Unlike in PCRE, the OR operation works at token level! > It doesn't work at concatenation level!
|
||||
|
||||
Note > Two char classes with an OR in the middle is a syntax error.
|
||||
|
||||
That also means, that a query string like abc|bde is not equal to (abc)|(bde), but instead to ab(c|b)de. The OR operation works only for c|b, not at char concatenation level.
|
||||
|
||||
#### Groups
|
||||
|
||||
Groups are a method to create complex patterns with repetitions of blocks of tokens.
|
||||
|
||||
The groups are delimited by round brackets `( )`.
|
||||
|
||||
Groups can be nested. Like all other tokens, groups can have a quantifier too.
|
||||
|
||||
- `c(pa)+z` match `cpapaz` or `cpaz` or `cpapapaz`.
|
||||
- `(c(pa)+z ?)+` matches `cpaz cpapaz cpapapaz` or `cpapaz`
|
||||
|
||||
Let's analyze this last case, first we have the group `#0`, that is the most outer round brackets `(...)+`. This group has a quantifier `+`, that says to match its content at least one time.
|
||||
Then we have a simple char token `c`, and a second group `#1`: `(pa)+`. This group also tries to match the sequence `pa`, at least one time, as specified by the `+` quantifier.
|
||||
Then, we have another simple token `z` and another simple token `?`, i.e. the space char (ascii code 32) followed by the `?` quantifier, which means that the preceding space should be matched 0 or 1 time.
|
||||
|
||||
This explains why the `(c(pa)+z ?)+` query string, can match `cpaz cpapaz cpapapaz`.
|
||||
|
||||
In this implementation the groups are "capture groups". This means that the last temporal result for each group, can be retrieved from the `RE` struct.
|
||||
|
||||
The "capture groups" are stored as indexes in the field `groups`, that is an `[]int` inside the `RE` struct.
|
||||
|
||||
example
|
||||
|
||||
```v
|
||||
import regex
|
||||
|
||||
text := 'cpaz cpapaz cpapapaz'
|
||||
query := r'(c(pa)+z ?)+'
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
println(re.get_query())
|
||||
// #0(c#1(pa)+z ?)+
|
||||
// #0 and #1 are the ids of the groups, are shown if re.debug is 1 or 2
|
||||
start, end := re.match_string(text)
|
||||
// [start=0, end=20] match => [cpaz cpapaz cpapapaz]
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println('${gi / 2} :[${text[re.groups[gi]..re.groups[gi + 1]]}]')
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
// groups captured
|
||||
// 0 :[cpapapaz]
|
||||
// 1 :[pa]
|
||||
```
|
||||
|
||||
Note > To show the group id number in the result of the get_query() > the flag debug of the RE object must be 1 or 2
|
||||
|
||||
In order to simplify the use of the captured groups, it is possible to use the utility function: get_group_list.
|
||||
|
||||
This function returns a list of groups using this support struct:
|
||||
|
||||
```v
|
||||
pub struct Re_group {
|
||||
pub:
|
||||
start int = -1
|
||||
end int = -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Groups example:
|
||||
|
||||
This simple function converts an HTML RGB value with 3 or 6 hex digits to an u32 value, this function is not optimized and it is only for didatical purpose. Example: #A0B0CC #A9F
|
||||
|
||||
```v
|
||||
import regex
|
||||
|
||||
fn convert_html_rgb(in_col string) u32 {
|
||||
mut n_digit := if in_col.len == 4 { 1 } else { 2 }
|
||||
mut col_mul := if in_col.len == 4 { 4 } else { 0 }
|
||||
// this is the regex query, it uses the V string interpolation to customize the regex query
|
||||
// Note: If you want to use escaped code you must use the r"" (raw) strings,
|
||||
// *** please remember that the V interpoaltion doesn't work on raw strings. ***
|
||||
query :='#([a-fA-F0-9]{${n_digit}})([a-fA-F0-9]{${n_digit}})([a-fA-F0-9]{${n_digit}})'
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
start, end := re.match_string(in_col)
|
||||
println('start: ${start}, end: ${end}')
|
||||
mut res := u32(0)
|
||||
if start >= 0 {
|
||||
group_list := re.get_group_list() // this is the utility function
|
||||
r := ('0x' + in_col[group_list[0].start..group_list[0].end]).int() << col_mul
|
||||
g := ('0x' + in_col[group_list[1].start..group_list[1].end]).int() << col_mul
|
||||
b := ('0x' + in_col[group_list[2].start..group_list[2].end]).int() << col_mul
|
||||
println('r: ${r} g: ${g} b: ${b}')
|
||||
res = u32(r) << 16 | u32(g) << 8 | u32(b)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
Other utility functions are get_group_by_id and get_group_bounds_by_id that get directly the string of a group using its id:
|
||||
|
||||
```v
|
||||
txt := 'my used string....'
|
||||
for g_index := 0; g_index < re.group_count; g_index++ {
|
||||
println('#${g_index} [${re.get_group_by_id(txt, g_index)}] \
|
||||
}] bounds: ${re.get_group_bounds_by_id(g_index)}')
|
||||
}
|
||||
```
|
||||
|
||||
More helper functions are listed in the Groups query functions section.
|
||||
|
||||
Groups Continuous saving
|
||||
In particular situations, it is useful to have a continuous group saving. This is possible by initializing the group_csave field in the RE struct.
|
||||
|
||||
This feature allows you to collect data in a continuous/streaming way.
|
||||
|
||||
In the example, we can pass a text, followed by an integer list, that we wish to collect. To achieve this task, we can use the continuous group saving, by enabling the right flag: re.group_csave_flag = true.
|
||||
|
||||
The .group_csave array will be filled then, following this logic:
|
||||
|
||||
re.group_csave[0] - number of total saved records re.group_csave[1+n*3] - id of the saved group re.group_csave[2+n*3] - start index in the source string of the saved group re.group_csave[3+n*3] - end index in the source string of the saved group
|
||||
|
||||
The regex will save groups, until it finishes, or finds that the array has no more space. If the space ends, no error is raised, and further records will not be saved.
|
||||
|
||||
```v
|
||||
import regex
|
||||
|
||||
txt := 'http://www.ciao.mondo/hello/pippo12_/pera.html'
|
||||
query := r'(?P<format>https?)|(?P<format>ftps?)://(?P<token>[\w_]+.)+'
|
||||
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
// println(re.get_code()) // uncomment to see the print of the regex execution code
|
||||
re.debug = 2 // enable maximum log
|
||||
println('String: ${txt}')
|
||||
println('Query : ${re.get_query()}')
|
||||
re.debug = 0 // disable log
|
||||
re.group_csave_flag = true
|
||||
start, end := re.match_string(txt)
|
||||
if start >= 0 {
|
||||
println('Match (${start}, ${end}) => [${txt[start..end]}]')
|
||||
} else {
|
||||
println('No Match')
|
||||
}
|
||||
|
||||
if re.group_csave_flag == true && start >= 0 && re.group_csave.len > 0 {
|
||||
println('cg: ${re.group_csave}')
|
||||
mut cs_i := 1
|
||||
for cs_i < re.group_csave[0] * 3 {
|
||||
g_id := re.group_csave[cs_i]
|
||||
st := re.group_csave[cs_i + 1]
|
||||
en := re.group_csave[cs_i + 2]
|
||||
println('cg[${g_id}] ${st} ${en}:[${txt[st..en]}]')
|
||||
cs_i += 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The output will be:
|
||||
|
||||
```v
|
||||
String: http://www.ciao.mondo/hello/pippo12_/pera.html
|
||||
Query : #0(?P<format>https?)|{8,14}#0(?P<format>ftps?)://#1(?P<token>[\w_]+.)+
|
||||
Match (0, 46) => [http://www.ciao.mondo/hello/pippo12_/pera.html]
|
||||
cg: [8, 0, 0, 4, 1, 7, 11, 1, 11, 16, 1, 16, 22, 1, 22, 28, 1, 28, 37, 1, 37, 42, 1, 42, 46]
|
||||
cg[0] 0 4:[http]
|
||||
cg[1] 7 11:[www.]
|
||||
cg[1] 11 16:[ciao.]
|
||||
cg[1] 16 22:[mondo/]
|
||||
cg[1] 22 28:[hello/]
|
||||
cg[1] 28 37:[pippo12_/]
|
||||
cg[1] 37 42:[pera.]
|
||||
cg[1] 42 46:[html]
|
||||
```v
|
||||
|
||||
#### Named capturing groups
|
||||
|
||||
This regex module supports partially the question mark ? PCRE syntax for groups.
|
||||
|
||||
- `(?:abcd)` non capturing group: the content of the group will not be saved.
|
||||
- `(?P<mygroup>abcdef)` named group: the group content is saved and labeled as mygroup.
|
||||
|
||||
The label of the groups is saved in the `group_map` of the `RE` struct, that is a map from `string` to `int`, where the value is the index in `group_csave` list of indexes.
|
||||
|
||||
Here is an example for how to use them:
|
||||
|
||||
```v
|
||||
import regex
|
||||
|
||||
|
||||
txt := 'http://www.ciao.mondo/hello/pippo12_/pera.html'
|
||||
query := r'(?P<format>https?)|(?P<format>ftps?)://(?P<token>[\w_]+.)+'
|
||||
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
// println(re.get_code()) // uncomment to see the print of the regex execution code
|
||||
re.debug = 2 // enable maximum log
|
||||
println('String: ${txt}')
|
||||
println('Query : ${re.get_query()}')
|
||||
re.debug = 0 // disable log
|
||||
start, end := re.match_string(txt)
|
||||
if start >= 0 {
|
||||
println('Match (${start}, ${end}) => [${txt[start..end]}]')
|
||||
} else {
|
||||
println('No Match')
|
||||
}
|
||||
|
||||
for name in re.group_map.keys() {
|
||||
println('group:${name} \t=> [${re.get_group_by_name(txt, name)}] \
|
||||
}] bounds: ${re.get_group_bounds_by_name(name)}')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
String: http://www.ciao.mondo/hello/pippo12_/pera.html
|
||||
Query : #0(?P<format>https?)|{8,14}#0(?P<format>ftps?)://#1(?P<token>[\w_]+.)+
|
||||
Match (0, 46) => [http://www.ciao.mondo/hello/pippo12_/pera.html]
|
||||
group:format => [http] bounds: (0, 4)
|
||||
group:token => [html] bounds: (42, 46)
|
||||
```
|
||||
|
||||
In order to simplify the use of the named groups, it is possible to use a name map in the re struct, using the function `re.get_group_by_name`.
|
||||
|
||||
Here is a more complex example of using them:
|
||||
|
||||
```v
|
||||
import regex
|
||||
|
||||
// This function demonstrate the use of the named groups
|
||||
fn convert_html_rgb_n(in_col string) u32 {
|
||||
mut n_digit := if in_col.len == 4 { 1 } else { 2 }
|
||||
mut col_mul := if in_col.len == 4 { 4 } else { 0 }
|
||||
query := r'#(?P<red>[a-fA-F0-9]{${n_digit}})(?P<green>[a-fA-F0-9]{${n_digit}})(?P<blue>[a-fA-F0-9]{${n_digit}})'
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
start, end := re.match_string(in_col)
|
||||
println('start: ${start}, end: ${end}')
|
||||
mut res := u32(0)
|
||||
if start >= 0 {
|
||||
red_s, red_e := re.get_group_bounds_by_name('red')
|
||||
r := ('0x' + in_col[red_s..red_e]).int() << col_mul
|
||||
green_s, green_e := re.get_group_bounds_by_name('green')
|
||||
g := ('0x' + in_col[green_s..green_e]).int() << col_mul
|
||||
blue_s, blue_e := re.get_group_bounds_by_name('blue')
|
||||
b := ('0x' + in_col[blue_s..blue_e]).int() << col_mul
|
||||
println('r: ${r} g: ${g} b: ${b}')
|
||||
res = u32(r) << 16 | u32(g) << 8 | u32(b)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
Other utilities are `get_group_by_name` and `get_group_bounds_by_name`, that return the string of a group using its name:
|
||||
|
||||
```v
|
||||
txt := 'my used string....'
|
||||
for name in re.group_map.keys() {
|
||||
println('group:${name} \t=> [${re.get_group_by_name(txt, name)}] \
|
||||
}] bounds: ${re.get_group_bounds_by_name(name)}')
|
||||
}
|
||||
```
|
||||
|
||||
#### Groups query functions
|
||||
|
||||
These functions are helpers to query the captured groups
|
||||
|
||||
```v
|
||||
// get_group_bounds_by_name get a group boundaries by its name
|
||||
pub fn (re RE) get_group_bounds_by_name(group_name string) (int, int)
|
||||
|
||||
// get_group_by_name get a group string by its name
|
||||
pub fn (re RE) get_group_by_name(group_name string) string
|
||||
|
||||
// get_group_by_id get a group boundaries by its id
|
||||
pub fn (re RE) get_group_bounds_by_id(group_id int) (int, int)
|
||||
|
||||
// get_group_by_id get a group string by its id
|
||||
pub fn (re RE) get_group_by_id(in_txt string, group_id int) string
|
||||
|
||||
struct Re_group {
|
||||
pub:
|
||||
start int = -1
|
||||
end int = -1
|
||||
}
|
||||
|
||||
// get_group_list return a list of Re_group for the found groups
|
||||
pub fn (re RE) get_group_list() []Re_group
|
||||
|
||||
// get_group_list return a list of Re_group for the found groups
|
||||
pub fn (re RE) get_group_list() []Re_group
|
||||
Flags
|
||||
It is possible to set some flags in the regex parser, that change the behavior of the parser itself.
|
||||
|
||||
```
|
||||
|
||||
#### init the regex struct with flags (optional)
|
||||
|
||||
```v
|
||||
mut re := regex.new()
|
||||
re.flag = regex.f_bin
|
||||
// f_bin: parse a string as bytes, utf-8 management disabled.
|
||||
// f_efm: exit on the first char matches in the query, used by thefind function.
|
||||
//f_ms: matches only if the index of the start match is 0,same as ^ at the start of the query string.
|
||||
// f_me: matches only if the end index of the match is the last charof the input string, same as $ end of query string.
|
||||
// f_nl: stop the matching if found a new line char \n or \r
|
||||
```
|
||||
|
||||
|
||||
## Simplified initializer
|
||||
|
||||
```v
|
||||
// regex create a regex object from the query string and compile it
|
||||
pub fn regex_opt(in_query string) ?RE
|
||||
|
||||
// new create a RE of small size, usually sufficient for ordinary use
|
||||
pub fn new() RE
|
||||
|
||||
//After an initializer is used, the regex expression must be compiled with:
|
||||
|
||||
// compile_opt compile RE pattern string, returning an error if the compilation fails
|
||||
pub fn (mut re RE) compile_opt(pattern string) !
|
||||
```
|
||||
|
||||
## Matching Functions
|
||||
|
||||
```v
|
||||
|
||||
// match_string try to match the input string, return start and end index if found else start is -1
|
||||
pub fn (mut re RE) match_string(in_txt string) (int, int)
|
||||
```
|
||||
|
||||
## Find functions
|
||||
|
||||
```v
|
||||
// find try to find the first match in the input string
|
||||
// return start and end index if found else start is -1
|
||||
pub fn (mut re RE) find(in_txt string) (int, int)
|
||||
|
||||
// find_all find all the "non overlapping" occurrences of the matching pattern
|
||||
// return a list of start end indexes like: [3,4,6,8]
|
||||
// the matches are [3,4] and [6,8]
|
||||
pub fn (mut re RE) find_all(in_txt string) []int
|
||||
|
||||
// find_all_str find all the "non overlapping" occurrences of the match pattern
|
||||
// return a list of strings
|
||||
// the result is like ['first match','secon match']
|
||||
pub fn (mut re RE) find_all_str(in_txt string) []string
|
||||
```
|
||||
|
||||
## Replace functions
|
||||
|
||||
```v
|
||||
// replace return a string where the matches are replaced with the repl_str string,
|
||||
// this function supports groups in the replace string
|
||||
pub fn (mut re RE) replace(in_txt string, repl string) string
|
||||
|
||||
//replace string can include groups references:
|
||||
|
||||
|
||||
txt := 'Today it is a good day.'
|
||||
query := r'(a\w)[ ,.]'
|
||||
mut re := regex.regex_opt(query)?
|
||||
res := re.replace(txt, r'__[\0]__')
|
||||
|
||||
```
|
||||
in above example we used the group 0 in the replace string: \0, the result will be:
|
||||
|
||||
Today it is a good day. => Tod__[ay]__it is a good d__[ay]__
|
||||
|
||||
Note > In the replace strings can be used only groups from 0 to 9.
|
||||
|
||||
If the usage of groups in the replace process, is not needed, it is possible to use a quick function:
|
||||
|
||||
```v
|
||||
// replace_simple return a string where the matches are replaced with the replace string
|
||||
pub fn (mut re RE) replace_simple(in_txt string, repl string) string
|
||||
|
||||
//If it is needed to replace N instances of the found strings it is possible to use:
|
||||
|
||||
|
||||
// replace_n return a string where the first `count` matches are replaced with the repl_str string
|
||||
// `count` indicate the number of max replacements that will be done.
|
||||
// if count is > 0 the replace began from the start of the string toward the end
|
||||
// if count is < 0 the replace began from the end of the string toward the start
|
||||
// if count is 0 do nothing
|
||||
pub fn (mut re RE) replace_n(in_txt string, repl_str string, count int) string
|
||||
|
||||
//For complex find and replace operations, you can use replace_by_fn . The replace_by_fn, uses a custom replace callback function, thus allowing customizations. The custom callback function is called for every non overlapped find.
|
||||
// The custom callback function must be of the type:
|
||||
|
||||
|
||||
// type of function used for custom replace
|
||||
// in_txt source text
|
||||
// start index of the start of the match in in_txt
|
||||
// end index of the end of the match in in_txt
|
||||
// --- the match is in in_txt[start..end] ---
|
||||
fn (re RE, in_txt string, start int, end int) string
|
||||
The following example will clarify its usage:
|
||||
|
||||
```
|
||||
customized replace function example
|
||||
|
||||
```v
|
||||
|
||||
import regex
|
||||
//
|
||||
// it will be called on each non overlapped find
|
||||
|
||||
fn my_repl(re regex.RE, in_txt string, start int, end int) string {
|
||||
g0 := re.get_group_by_id(in_txt, 0)
|
||||
g1 := re.get_group_by_id(in_txt, 1)
|
||||
g2 := re.get_group_by_id(in_txt, 2)
|
||||
return'*${g0}*${g1}*${g2}*'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
txt := 'today [John] is gone to his house with (Jack) and [Marie].'
|
||||
query := r'(.)(\A\w+)(.)'
|
||||
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
|
||||
result := re.replace_by_fn(txt, my_repl)
|
||||
println(result)
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```txt
|
||||
today *[*John*]* is gone to his house with *(*Jack*)* and *[*Marie*]*.
|
||||
```
|
||||
49
aiprompts/v_advanced/smtp.md
Normal file
49
aiprompts/v_advanced/smtp.md
Normal file
@@ -0,0 +1,49 @@
|
||||
module net.smtp
|
||||
|
||||
fn new_client(config Client) !&Client
|
||||
new_client returns a new SMTP client and connects to it
|
||||
enum BodyType {
|
||||
text
|
||||
html
|
||||
}
|
||||
struct Attachment {
|
||||
filename string
|
||||
bytes []u8
|
||||
cid string
|
||||
}
|
||||
struct Client {
|
||||
mut:
|
||||
conn net.TcpConn
|
||||
ssl_conn &ssl.SSLConn = unsafe { nil }
|
||||
reader ?&io.BufferedReader
|
||||
pub:
|
||||
server string
|
||||
port int = 25
|
||||
username string
|
||||
password string
|
||||
from string
|
||||
ssl bool
|
||||
starttls bool
|
||||
pub mut:
|
||||
is_open bool
|
||||
encrypted bool
|
||||
}
|
||||
fn (mut c Client) reconnect() !
|
||||
reconnect reconnects to the SMTP server if the connection was closed
|
||||
fn (mut c Client) send(config Mail) !
|
||||
send sends an email
|
||||
fn (mut c Client) quit() !
|
||||
quit closes the connection to the server
|
||||
struct Mail {
|
||||
pub:
|
||||
from string
|
||||
to string
|
||||
cc string
|
||||
bcc string
|
||||
date time.Time = time.now()
|
||||
subject string
|
||||
body_type BodyType
|
||||
body string
|
||||
attachments []Attachment
|
||||
boundary string
|
||||
}
|
||||
311
aiprompts/v_advanced/time instructions.md
Normal file
311
aiprompts/v_advanced/time instructions.md
Normal file
@@ -0,0 +1,311 @@
|
||||
|
||||
## Description
|
||||
|
||||
V's `time` module, provides utilities for working with time and dates:
|
||||
|
||||
- parsing of time values expressed in one of the commonly used standard time/date formats
|
||||
- formatting of time values
|
||||
- arithmetic over times/durations
|
||||
- converting between local time and UTC (timezone support)
|
||||
- stop watches for accurately measuring time durations
|
||||
- sleeping for a period of time
|
||||
|
||||
## Examples
|
||||
|
||||
You can see the current time. [See](https://play.vlang.io/?query=c121a6dda7):
|
||||
|
||||
```v
|
||||
import time
|
||||
|
||||
println(time.now())
|
||||
```
|
||||
|
||||
`time.Time` values can be compared, [see](https://play.vlang.io/?query=133d1a0ce5):
|
||||
|
||||
```v
|
||||
import time
|
||||
|
||||
const time_to_test = time.Time{
|
||||
year: 1980
|
||||
month: 7
|
||||
day: 11
|
||||
hour: 21
|
||||
minute: 23
|
||||
second: 42
|
||||
nanosecond: 123456789
|
||||
}
|
||||
|
||||
println(time_to_test.format())
|
||||
|
||||
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,
|
||||
[see](https://play.vlang.io/p/b02ca6027f):
|
||||
|
||||
```v
|
||||
import time
|
||||
|
||||
s := '2018-01-27 12:48:34'
|
||||
t := time.parse(s) or { panic('failing format: ${s} | err: ${err}') }
|
||||
println(t)
|
||||
println(t.unix())
|
||||
```
|
||||
|
||||
V's time module also has these parse methods:
|
||||
|
||||
```v ignore
|
||||
fn parse(s string) !Time
|
||||
fn parse_iso8601(s string) !Time
|
||||
fn parse_rfc2822(s string) !Time
|
||||
fn parse_rfc3339(s string) !Time
|
||||
```
|
||||
|
||||
Another very useful feature of the `time` module is the stop watch,
|
||||
for when you want to measure short time periods, elapsed while you
|
||||
executed other tasks. [See](https://play.vlang.io/?query=f6c008bc34):
|
||||
|
||||
```v
|
||||
import time
|
||||
|
||||
fn do_something() {
|
||||
time.sleep(510 * time.millisecond)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
sw := time.new_stopwatch()
|
||||
do_something()
|
||||
println('Note: do_something() took: ${sw.elapsed().milliseconds()} ms')
|
||||
}
|
||||
```
|
||||
|
||||
```vlang
|
||||
|
||||
module time
|
||||
|
||||
const second = Duration(1000 * millisecond)
|
||||
const long_months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
|
||||
'September', 'October', 'November', 'December']
|
||||
const nanosecond = Duration(1)
|
||||
const absolute_zero_year = i64(-292277022399)
|
||||
const days_string = 'MonTueWedThuFriSatSun'
|
||||
const long_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']!
|
||||
const month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]!
|
||||
const seconds_per_hour = 60 * seconds_per_minute
|
||||
const millisecond = Duration(1000 * microsecond)
|
||||
const days_per_4_years = days_in_year * 4 + 1
|
||||
const microsecond = Duration(1000 * nanosecond)
|
||||
const days_per_400_years = days_in_year * 400 + 97
|
||||
const minute = Duration(60 * second)
|
||||
const days_before = [
|
||||
0,
|
||||
31,
|
||||
31 + 28,
|
||||
31 + 28 + 31,
|
||||
31 + 28 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
|
||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
|
||||
]!
|
||||
const months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec'
|
||||
const seconds_per_week = 7 * seconds_per_day
|
||||
const hour = Duration(60 * minute)
|
||||
const days_per_100_years = days_in_year * 100 + 24
|
||||
const seconds_per_minute = 60
|
||||
const days_in_year = 365
|
||||
const infinite = Duration(i64(9223372036854775807))
|
||||
const seconds_per_day = 24 * seconds_per_hour
|
||||
fn date_from_days_after_unix_epoch(days int) Time
|
||||
fn day_of_week(y int, m int, d int) int
|
||||
fn days_from_unix_epoch(year int, month int, day int) int
|
||||
fn days_in_month(month int, year int) !int
|
||||
fn is_leap_year(year int) bool
|
||||
fn new(t Time) Time
|
||||
fn new_stopwatch(opts StopWatchOptions) StopWatch
|
||||
fn new_time(t Time) Time
|
||||
fn now() Time
|
||||
fn offset() int
|
||||
fn parse(s string) !Time
|
||||
fn parse_format(s string, format string) !Time
|
||||
fn parse_iso8601(s string) !Time
|
||||
fn parse_rfc2822(s string) !Time
|
||||
fn parse_rfc3339(s string) !Time
|
||||
fn portable_timegm(t &C.tm) i64
|
||||
fn since(t Time) Duration
|
||||
fn sleep(duration Duration)
|
||||
fn sys_mono_now() u64
|
||||
fn ticks() i64
|
||||
fn unix(epoch i64) Time
|
||||
fn unix2(epoch i64, microsecond int) Time
|
||||
fn unix_microsecond(epoch i64, microsecond int) Time
|
||||
fn unix_nanosecond(abs_unix_timestamp i64, nanosecond int) Time
|
||||
fn utc() Time
|
||||
fn Time.new(t Time) Time
|
||||
type Duration = i64
|
||||
fn (d Duration) days() f64
|
||||
fn (d Duration) debug() string
|
||||
fn (d Duration) hours() f64
|
||||
fn (d Duration) microseconds() i64
|
||||
fn (d Duration) milliseconds() i64
|
||||
fn (d Duration) minutes() f64
|
||||
fn (d Duration) nanoseconds() i64
|
||||
fn (d Duration) seconds() f64
|
||||
fn (d Duration) str() string
|
||||
fn (d Duration) sys_milliseconds() int
|
||||
fn (d Duration) timespec() C.timespec
|
||||
enum FormatDate {
|
||||
ddmmyy
|
||||
ddmmyyyy
|
||||
mmddyy
|
||||
mmddyyyy
|
||||
mmmd
|
||||
mmmdd
|
||||
mmmddyy
|
||||
mmmddyyyy
|
||||
no_date
|
||||
yyyymmdd
|
||||
yymmdd
|
||||
}
|
||||
enum FormatDelimiter {
|
||||
dot
|
||||
hyphen
|
||||
slash
|
||||
space
|
||||
no_delimiter
|
||||
}
|
||||
enum FormatTime {
|
||||
hhmm12
|
||||
hhmm24
|
||||
hhmmss12
|
||||
hhmmss24
|
||||
hhmmss24_milli
|
||||
hhmmss24_micro
|
||||
hhmmss24_nano
|
||||
no_time
|
||||
}
|
||||
struct C.mach_timebase_info_data_t {
|
||||
numer u32
|
||||
denom u32
|
||||
}
|
||||
struct C.timespec {
|
||||
pub mut:
|
||||
tv_sec i64
|
||||
tv_nsec i64
|
||||
}
|
||||
struct C.timeval {
|
||||
pub:
|
||||
tv_sec u64
|
||||
tv_usec u64
|
||||
}
|
||||
struct C.tm {
|
||||
pub mut:
|
||||
tm_sec int
|
||||
tm_min int
|
||||
tm_hour int
|
||||
tm_mday int
|
||||
tm_mon int
|
||||
tm_year int
|
||||
tm_wday int
|
||||
tm_yday int
|
||||
tm_isdst int
|
||||
tm_gmtoff int
|
||||
}
|
||||
struct StopWatch {
|
||||
mut:
|
||||
elapsed u64
|
||||
pub mut:
|
||||
start u64
|
||||
end u64
|
||||
}
|
||||
fn (mut t StopWatch) start()
|
||||
fn (mut t StopWatch) restart()
|
||||
fn (mut t StopWatch) stop()
|
||||
fn (mut t StopWatch) pause()
|
||||
fn (t StopWatch) elapsed() Duration
|
||||
struct StopWatchOptions {
|
||||
pub:
|
||||
auto_start bool = true
|
||||
}
|
||||
struct Time {
|
||||
unix i64
|
||||
pub:
|
||||
year int
|
||||
month int
|
||||
day int
|
||||
hour int
|
||||
minute int
|
||||
second int
|
||||
nanosecond int
|
||||
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']
|
||||
}
|
||||
fn (lhs Time) - (rhs Time) Duration
|
||||
fn (t1 Time) < (t2 Time) bool
|
||||
fn (t1 Time) == (t2 Time) bool
|
||||
fn (t Time) add(duration_in_nanosecond Duration) Time
|
||||
fn (t Time) add_days(days int) Time
|
||||
fn (t Time) add_seconds(seconds int) Time
|
||||
fn (t Time) as_local() Time
|
||||
fn (t Time) as_utc() Time
|
||||
fn (t Time) clean() string
|
||||
fn (t Time) clean12() string
|
||||
fn (t Time) custom_format(s string) string
|
||||
fn (t Time) day_of_week() int
|
||||
fn (t Time) days_from_unix_epoch() int
|
||||
fn (t Time) ddmmy() string
|
||||
fn (t Time) debug() string
|
||||
fn (t Time) format() string
|
||||
fn (t Time) format_rfc3339() string
|
||||
fn (t Time) format_rfc3339_nano() string
|
||||
fn (t Time) format_ss() string
|
||||
fn (t Time) format_ss_micro() string
|
||||
fn (t Time) format_ss_milli() string
|
||||
fn (t Time) format_ss_nano() string
|
||||
fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate) string
|
||||
fn (t Time) get_fmt_str(fmt_dlmtr FormatDelimiter, fmt_time FormatTime, fmt_date FormatDate) string
|
||||
fn (t Time) get_fmt_time_str(fmt_time FormatTime) string
|
||||
fn (t Time) hhmm() string
|
||||
fn (t Time) hhmm12() string
|
||||
fn (t Time) hhmmss() string
|
||||
fn (t Time) http_header_string() string
|
||||
fn (t Time) is_utc() bool
|
||||
fn (t Time) local() Time
|
||||
fn (t Time) local_to_utc() Time
|
||||
fn (t Time) long_weekday_str() string
|
||||
fn (t Time) md() string
|
||||
fn (t Time) relative() string
|
||||
fn (t Time) relative_short() string
|
||||
fn (t Time) smonth() string
|
||||
fn (t Time) str() string
|
||||
fn (t Time) strftime(fmt string) string
|
||||
fn (t Time) unix() i64
|
||||
fn (t Time) unix_micro() i64
|
||||
fn (t Time) unix_milli() i64
|
||||
fn (t Time) unix_nano() i64
|
||||
fn (t Time) unix_time() i64
|
||||
fn (t Time) unix_time_micro() i64
|
||||
fn (t Time) unix_time_milli() i64
|
||||
fn (t Time) unix_time_nano() i64
|
||||
fn (t Time) utc_string() string
|
||||
fn (u Time) utc_to_local() Time
|
||||
fn (t Time) weekday_str() string
|
||||
fn (t Time) year_day() int
|
||||
fn (t Time) ymmdd() string
|
||||
struct TimeParseError {
|
||||
Error
|
||||
code int
|
||||
message string
|
||||
}
|
||||
fn (err TimeParseError) msg() string
|
||||
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user