Compare commits
407 Commits
v1.0.0_lib
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb15b5aa1b | ||
|
|
93476594ee | ||
|
|
04cb432e72 | ||
|
|
242838e3f3 | ||
|
|
0a993494e2 | ||
|
|
a3f2a6e3ac | ||
|
|
58b8b3d610 | ||
|
|
998a86975b | ||
|
|
6bb7a6f291 | ||
|
|
32f06f4fe8 | ||
|
|
f26fe9dea8 | ||
|
|
d5ea72a18a | ||
|
|
8b2aa01b3d | ||
|
|
35c840ab61 | ||
|
|
08350199e3 | ||
|
|
e774913db9 | ||
|
|
949e46642a | ||
|
|
3a8c06fe5b | ||
|
|
e4bb43bce7 | ||
|
|
3c57dd9a98 | ||
|
|
3754bfe088 | ||
|
|
cef9d850d8 | ||
|
|
04a7c36e7b | ||
|
|
9adfaf25ca | ||
|
|
8c10ef9de7 | ||
|
|
78e410dc1a | ||
|
|
258ddaed5f | ||
|
|
70572c4424 | ||
|
|
5be31bad4c | ||
|
|
d4f217f9f1 | ||
|
|
6e0fe7b8c6 | ||
|
|
2b4a0f158b | ||
|
|
34d2b00441 | ||
|
|
eb06aed649 | ||
|
|
7cb57e0c46 | ||
|
|
b771134121 | ||
|
|
dd63b4e225 | ||
|
|
b53cd6fd8b | ||
|
|
a4657c479d | ||
|
|
39c142fa56 | ||
|
|
a578b44788 | ||
|
|
21372c17e8 | ||
|
|
f70a0dbc2b | ||
|
|
fb2f8d9eff | ||
|
|
4d54eb946f | ||
|
|
98dd44b5eb | ||
|
|
7261037df8 | ||
|
|
0784a26081 | ||
|
|
a89a4155ea | ||
|
|
25feca605d | ||
|
|
4a1f1c6daa | ||
|
|
1678cdbddd | ||
|
|
a38f5452d8 | ||
|
|
44541bd1bd | ||
|
|
a4436b746e | ||
|
|
204e31d481 | ||
|
|
d32ddd2970 | ||
|
|
c64c538b6c | ||
|
|
63af166c32 | ||
|
|
4c9520165e | ||
|
|
ba10b27646 | ||
|
|
a497837cc9 | ||
|
|
f3414a0603 | ||
|
|
ed5b527559 | ||
|
|
b32fd63c83 | ||
|
|
683883b08a | ||
|
|
8830320c60 | ||
|
|
77b91ff98e | ||
|
|
dea293ffaa | ||
|
|
b004e1a808 | ||
|
|
3eaf8efc37 | ||
|
|
113772521d | ||
|
|
0c866baaf7 | ||
|
|
87e5440e00 | ||
|
|
9c88a9b352 | ||
|
|
36b586f7d3 | ||
|
|
d88bfcae87 | ||
|
|
7fda7c5072 | ||
|
|
14cb806b1c | ||
|
|
042da09665 | ||
|
|
18081ecb66 | ||
|
|
2da8140e2d | ||
|
|
def75703a4 | ||
|
|
426988b000 | ||
|
|
f86c810aea | ||
|
|
06f084d4ba | ||
|
|
8743dfc155 | ||
|
|
bd90d77bc7 | ||
|
|
5e4694abba | ||
|
|
f0ac08cb42 | ||
|
|
67acfdb53b | ||
|
|
cf0f8c6fd4 | ||
|
|
ac42b79b30 | ||
|
|
d84a031f32 | ||
|
|
e059473135 | ||
|
|
950aa6486e | ||
|
|
a3c179d089 | ||
|
|
220c4fe13b | ||
|
|
ec1f973bd4 | ||
|
|
6d771874a8 | ||
|
|
70697f4ae9 | ||
|
|
3636701fc2 | ||
|
|
b2ed37f5f5 | ||
|
|
1e4f964c47 | ||
|
|
68803053f4 | ||
|
|
36b9d189a1 | ||
|
|
897e83f66a | ||
|
|
efcd2a3858 | ||
|
|
324ca2ac32 | ||
|
|
64fb9fc8e5 | ||
|
|
684d912ca9 | ||
|
|
3db9e8f75a | ||
|
|
6243d3624a | ||
|
|
5664b04075 | ||
|
|
25b8fad800 | ||
|
|
1d3d6dd2dc | ||
|
|
2918b4e9ce | ||
|
|
9f8047d6d4 | ||
|
|
7326baf110 | ||
|
|
472245a8bd | ||
|
|
c8c2ccadd6 | ||
|
|
62511d77bc | ||
|
|
2f6be7b7ab | ||
|
|
cca65db1f4 | ||
|
|
fa83b0fb5e | ||
|
|
86fb93d0ef | ||
|
|
432c55de9b | ||
|
|
b388750a8d | ||
|
|
5876a2b11d | ||
|
|
a0f7be6825 | ||
|
|
1e6013d230 | ||
|
|
97c02c4f57 | ||
|
|
3d60ab1a6d | ||
|
|
a32596ed02 | ||
|
|
67a5eab44f | ||
|
|
775a7262f8 | ||
|
|
3ed391ab13 | ||
|
|
9f6bcee5be | ||
|
|
d2efc89796 | ||
|
|
437ab75068 | ||
|
|
aea6671b14 | ||
|
|
010d8de944 | ||
|
|
b0015be668 | ||
|
|
bf61f55dd3 | ||
|
|
83973cbc04 | ||
|
|
58b299ee60 | ||
|
|
d799a7fc85 | ||
|
|
2ea56b1dd1 | ||
|
|
6ed211328e | ||
|
|
e0e0be194e | ||
|
|
0156258c9b | ||
|
|
184488be25 | ||
|
|
60bd3aea38 | ||
|
|
41257c60f2 | ||
|
|
26973f335c | ||
|
|
6dd4a420f8 | ||
|
|
77af4a3fc4 | ||
|
|
6e5890921a | ||
|
|
13cbd81881 | ||
|
|
0c1a21e75c | ||
|
|
0e86ec5847 | ||
|
|
91ab230d81 | ||
|
|
112828c677 | ||
|
|
6b1651be7e | ||
|
|
a4a27cacff | ||
|
|
d2cc600e97 | ||
|
|
9ed3eaebd1 | ||
|
|
a77051e73a | ||
|
|
934851e3f5 | ||
|
|
c3e189c612 | ||
|
|
0b329720bf | ||
|
|
a10844d4bf | ||
|
|
52785475b9 | ||
|
|
1a794772b2 | ||
|
|
dc67c97ab2 | ||
|
|
f9056e732c | ||
|
|
60614d32b8 | ||
|
|
00d5c11e65 | ||
|
|
37aa1c8260 | ||
|
|
3a29890651 | ||
|
|
fb270887b4 | ||
|
|
e5870c79e1 | ||
|
|
fd52f76e4d | ||
|
|
3a02460be1 | ||
|
|
d35f557161 | ||
|
|
99e6ba7124 | ||
|
|
ff97bbbc9d | ||
|
|
3d9e45e733 | ||
|
|
991f5cdbb8 | ||
|
|
938b8af9b0 | ||
|
|
c0b9dc919b | ||
|
|
4a6289ecf7 | ||
|
|
ff0d29309a | ||
|
|
b2647468e2 | ||
|
|
8872af2d86 | ||
|
|
d611ca264f | ||
|
|
0ee7ef41fe | ||
|
|
03b98bc234 | ||
|
|
fc197b5117 | ||
|
|
8233a6e6b2 | ||
|
|
fda5b57f4f | ||
|
|
1f2b6ed23d | ||
|
|
4d92e354be | ||
|
|
fc50c60987 | ||
|
|
d9ab73a281 | ||
|
|
336e5dfb1d | ||
|
|
bfc4a2c95b | ||
|
|
53da326aea | ||
|
|
6fd64f93a0 | ||
|
|
216f5f4da1 | ||
|
|
fe73fa048a | ||
|
|
1f7d4acc40 | ||
|
|
008361d83c | ||
|
|
0fe8d7959b | ||
|
|
8d1a431f68 | ||
|
|
4afb5ebb20 | ||
|
|
0e36f685e8 | ||
|
|
ebc8199d42 | ||
|
|
3a32097dc8 | ||
|
|
855d851f47 | ||
|
|
55d7782af5 | ||
|
|
76f247847f | ||
|
|
da3b5f00f5 | ||
|
|
bc88511a29 | ||
|
|
1b6d9625e8 | ||
|
|
ba618cf070 | ||
|
|
3e6b09eb8d | ||
|
|
ed766f709a | ||
|
|
8f868995fc | ||
|
|
2cef4d6f20 | ||
|
|
7a8e526adf | ||
|
|
337bd035a8 | ||
|
|
3fae068b9b | ||
|
|
0890c29b7e | ||
|
|
852b9e2489 | ||
|
|
6dfe8f839a | ||
|
|
2cb056ec7b | ||
|
|
b117c6118b | ||
|
|
90affa4d51 | ||
|
|
866beeda31 | ||
|
|
8a8610a928 | ||
|
|
87e23c74b5 | ||
|
|
6f6294ebc2 | ||
|
|
3264417f15 | ||
|
|
ea4b6c84d0 | ||
|
|
749581309e | ||
|
|
6ce60d4088 | ||
|
|
6852f49401 | ||
|
|
af80bf5ef1 | ||
|
|
e59a989521 | ||
|
|
ff19fe0bc1 | ||
|
|
0186f0444c | ||
|
|
8a93cb6e31 | ||
|
|
529ebf3b49 | ||
|
|
aa43978b3e | ||
|
|
34042167eb | ||
|
|
1dc61d523d | ||
|
|
b127f58e41 | ||
|
|
00c19381fc | ||
|
|
6f5c43ae8e | ||
|
|
8349a74801 | ||
|
|
995603f6fe | ||
|
|
6b64e20161 | ||
|
|
c053e861e8 | ||
|
|
e9685cfbe7 | ||
|
|
78df87fddd | ||
|
|
b269d9cfa6 | ||
|
|
7c043fae5e | ||
|
|
8fbb39fd52 | ||
|
|
27dc68dd84 | ||
|
|
af3d06f3b4 | ||
|
|
183ebc0333 | ||
|
|
41913613c0 | ||
|
|
2167cddb01 | ||
|
|
ae8f5c81d4 | ||
|
|
c11d30ddba | ||
|
|
c0edac3cf3 | ||
|
|
a9bad602df | ||
|
|
88d718d490 | ||
|
|
a516cd8b55 | ||
|
|
a17ec9037a | ||
|
|
f42d15005b | ||
|
|
9eaab52bd2 | ||
|
|
629edd3a61 | ||
|
|
8d8338a135 | ||
|
|
bd4de26f70 | ||
|
|
acfa05a326 | ||
|
|
c4864f1a5b | ||
|
|
3523ec5439 | ||
|
|
e89da65240 | ||
|
|
b580b20e18 | ||
|
|
6a862c0c44 | ||
|
|
857d652ddf | ||
|
|
bd520c40ba | ||
|
|
90ac2149f9 | ||
|
|
2722f559cb | ||
|
|
482837faec | ||
|
|
1e41480587 | ||
|
|
962923c9cd | ||
|
|
d35bd0aa92 | ||
|
|
764f78ad61 | ||
|
|
10ae3f4e2e | ||
|
|
99946ba004 | ||
|
|
f6de644eea | ||
|
|
55db2ba084 | ||
|
|
7abf541dc5 | ||
|
|
f3da3a8476 | ||
|
|
94f2060c37 | ||
|
|
12084dc85a | ||
|
|
a9e8fc17b5 | ||
|
|
ec837c9d6e | ||
|
|
46d9c66db1 | ||
|
|
7f9fdf7f73 | ||
|
|
76ab069eda | ||
|
|
1e2c566295 | ||
|
|
38414e3063 | ||
|
|
badda7e702 | ||
|
|
dba9a2043b | ||
|
|
e26c728d69 | ||
|
|
ba22ea0a36 | ||
|
|
9b77cc47e8 | ||
|
|
c99ada340c | ||
|
|
f36a18f54d | ||
|
|
b2d1c9bd7a | ||
|
|
c98a54a0cf | ||
|
|
efd66f07dd | ||
|
|
356c57b8e5 | ||
|
|
3b28f21a32 | ||
|
|
90aa53f68d | ||
|
|
281a8eb96a | ||
|
|
fe850bb83c | ||
|
|
253d3302d2 | ||
|
|
ba9b8b459f | ||
|
|
9b4c6373b0 | ||
|
|
f1dfeea41b | ||
|
|
a1fad242f7 | ||
|
|
3980f38842 | ||
|
|
b26586f870 | ||
|
|
20a554b93e | ||
|
|
1378ba152f | ||
|
|
dd841bb813 | ||
|
|
cf14a05eb0 | ||
|
|
ce681db619 | ||
|
|
3e1cdf7965 | ||
|
|
a8cdb4a6a1 | ||
|
|
61d126020d | ||
|
|
01488c71df | ||
|
|
f76f911c98 | ||
|
|
6b869f980d | ||
|
|
72f063ddf1 | ||
|
|
a05733db59 | ||
|
|
383182e4b0 | ||
|
|
97e0830794 | ||
|
|
502870ed90 | ||
|
|
bbb84b0855 | ||
|
|
806509795e | ||
|
|
d9b070500f | ||
|
|
debddbf92a | ||
|
|
4ae98c0278 | ||
|
|
cef596e908 | ||
|
|
795c6a8032 | ||
|
|
13976fa3c5 | ||
|
|
d25e19992e | ||
|
|
ba0a5a19d6 | ||
|
|
321be70811 | ||
|
|
0c923be03d | ||
|
|
8ccdd51eb6 | ||
|
|
1ed4c90225 | ||
|
|
0622f4f1ac | ||
|
|
f4b59fb3e8 | ||
|
|
6fdbec7852 | ||
|
|
933738a631 | ||
|
|
b294b4fbd5 | ||
|
|
799965298a | ||
|
|
7da264b3f3 | ||
|
|
34119bfcd2 | ||
|
|
60f5d7124d | ||
|
|
26ecda371c | ||
|
|
389f0baad0 | ||
|
|
e27c4d3f7d | ||
|
|
5e456163f1 | ||
|
|
e8d38bcd6e | ||
|
|
00de1f1110 | ||
|
|
c37019801c | ||
|
|
1c2e1b3e90 | ||
|
|
f922d84d9d | ||
|
|
e14d44d12e | ||
|
|
9b0185a4a4 | ||
|
|
48f6525711 | ||
|
|
88a7d08db8 | ||
|
|
f877cf340c | ||
|
|
5a10ca65a1 | ||
|
|
c3537ce52f | ||
|
|
23a60af1e7 | ||
|
|
9adfeb3060 | ||
|
|
ab118fb712 | ||
|
|
af93044ded | ||
|
|
40ca3fd469 | ||
|
|
34adf15a24 | ||
|
|
c3c48c34f7 | ||
|
|
68af870e50 | ||
|
|
9747599e3e | ||
|
|
607e6aff84 | ||
|
|
3d7a1018da | ||
|
|
acc968a8a3 | ||
|
|
5f7a913974 | ||
|
|
36d05df0f5 |
41
.clang-format
Normal file
41
.clang-format
Normal file
@ -0,0 +1,41 @@
|
||||
BasedOnStyle: llvm
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
ColumnLimit: 0
|
||||
DerivePointerAlignment: false
|
||||
IncludeCategories:
|
||||
- Regex: '<[[:alnum:]_]+>'
|
||||
Priority: 1
|
||||
- Regex: '<(gtest|gmock)/'
|
||||
Priority: 2
|
||||
- Regex: '<[[:alnum:]_./]+>'
|
||||
Priority: 3
|
||||
- Regex: '<entt/'
|
||||
Priority: 4
|
||||
- Regex: '.*'
|
||||
Priority: 5
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
PointerAlignment: Right
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAroundPointerQualifiers: After
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
Standard: Latest
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
12
.clang-tidy
Normal file
12
.clang-tidy
Normal file
@ -0,0 +1,12 @@
|
||||
Checks: >
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
concurrency-*,
|
||||
modernize-*,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-use-trailing-return-type,
|
||||
performance-*,
|
||||
portability-*,
|
||||
CheckOptions:
|
||||
- key: bugprone-suspicious-include.HeaderFileExtensions
|
||||
value: ";h;hpp;ipp"
|
||||
53
.conan/build.py
Normal file
53
.conan/build.py
Normal file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import re
|
||||
import platform
|
||||
from cpt.packager import ConanMultiPackager
|
||||
|
||||
|
||||
def get_version():
|
||||
with open("CMakeLists.txt") as cmake:
|
||||
content = cmake.read()
|
||||
match = re.search(r'project\(uvw VERSION (.*)\)', content)
|
||||
if match:
|
||||
return match.group(1)
|
||||
tag_version = os.getenv("GITHUB_REF")
|
||||
package_version = tag_version.replace("refs/tags/v", "")
|
||||
return package_version
|
||||
|
||||
def get_username():
|
||||
return os.getenv("CONAN_USERNAME", "skypjack")
|
||||
|
||||
|
||||
def get_reference():
|
||||
version = get_version()
|
||||
username = get_username()
|
||||
return "uvw/{}@{}/stable".format(version, username)
|
||||
|
||||
|
||||
def get_upload():
|
||||
username = get_username()
|
||||
url = "https://api.bintray.com/conan/{}/conan".format(username)
|
||||
default_upload = url if os.getenv("GITHUB_REF") else False
|
||||
return os.getenv("CONAN_UPLOAD", default_upload)
|
||||
|
||||
|
||||
def upload_when_stable():
|
||||
return os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", "1").lower() not in ["0", "false", "no"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_folder = os.path.join(".conan", "test_package")
|
||||
builder = ConanMultiPackager(reference=get_reference(),
|
||||
username=get_username(),
|
||||
upload=get_upload(),
|
||||
test_folder=test_folder,
|
||||
stable_branch_pattern=r'v?\d+\.\d+\.\d+.*',
|
||||
upload_only_when_stable=upload_when_stable())
|
||||
if platform.system() == "Linux":
|
||||
builder.add(settings={"compiler": "gcc", "compiler.version": "8",
|
||||
"arch": "x86_64", "build_type": "Release"},
|
||||
options={}, env_vars={}, build_requires={})
|
||||
builder.run()
|
||||
10
.conan/test_package/CMakeLists.txt
Normal file
10
.conan/test_package/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
project(test_package)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE TRUE)
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup(TARGETS)
|
||||
|
||||
add_executable(${PROJECT_NAME} test_package.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} CONAN_PKG::uvw)
|
||||
18
.conan/test_package/conanfile.py
Normal file
18
.conan/test_package/conanfile.py
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from conans import ConanFile, CMake
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "cmake"
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def test(self):
|
||||
test_package = os.path.join("bin", "test_package")
|
||||
self.run(test_package, run_environment=True)
|
||||
48
.conan/test_package/test_package.cpp
Normal file
48
.conan/test_package/test_package.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <uvw.hpp>
|
||||
#include <memory>
|
||||
|
||||
void listen(uvw::loop &loop) {
|
||||
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
||||
|
||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||
std::shared_ptr<uvw::tcp_handle> client = srv.loop().resource<uvw::tcp_handle>();
|
||||
|
||||
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
|
||||
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
||||
|
||||
srv.accept(*client);
|
||||
client->read();
|
||||
});
|
||||
|
||||
tcp->bind("127.0.0.1", 4242);
|
||||
tcp->listen();
|
||||
}
|
||||
|
||||
void conn(uvw::loop &loop) {
|
||||
auto tcp = loop.resource<uvw::tcp_handle>();
|
||||
|
||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
|
||||
|
||||
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
|
||||
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
|
||||
tcp.write(std::move(dataWrite), 2);
|
||||
tcp.close();
|
||||
});
|
||||
|
||||
tcp->connect(std::string{"127.0.0.1"}, 4242);
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Getting UVW loop ...\n";
|
||||
auto loop = uvw::loop::get_default();
|
||||
std::cout << "Staring UVW listener ...\n";
|
||||
listen(*loop);
|
||||
std::cout << "Connecting ...\n";
|
||||
conn(*loop);
|
||||
loop->run();
|
||||
std::cout << "Done!\n";
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: skypjack
|
||||
patreon:
|
||||
open_collective:
|
||||
ko_fi:
|
||||
tidelift:
|
||||
community_bridge:
|
||||
liberapay:
|
||||
issuehunt:
|
||||
otechie:
|
||||
custom: https://www.paypal.me/skypjack
|
||||
21
.github/workflows/build-macos.yml
vendored
Normal file
21
.github/workflows/build-macos.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: build-macos
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
macos:
|
||||
timeout-minutes: 60
|
||||
runs-on: macOS-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF ..
|
||||
make -j2
|
||||
25
.github/workflows/build-meson.yml
vendored
Normal file
25
.github/workflows/build-meson.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: build-meson
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
meson:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Meson
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install -y meson
|
||||
- name: Meson Build (shared)
|
||||
run: |
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
- name: Meson Build (static)
|
||||
run: |
|
||||
rm -rf build/
|
||||
meson setup build --default-library=static
|
||||
meson compile -C build
|
||||
39
.github/workflows/build-ubuntu-20.04.yml
vendored
Normal file
39
.github/workflows/build-ubuntu-20.04.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: build-ubuntu-20.04
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
matrix:
|
||||
compiler:
|
||||
- { pkg: g++, exe: 'g++', version: 7 }
|
||||
- { pkg: g++, exe: 'g++', version: 8 }
|
||||
- { pkg: g++, exe: 'g++', version: 9 }
|
||||
- { pkg: clang, exe: 'clang++', version: 8 }
|
||||
- { pkg: clang, exe: 'clang++', version: 9 }
|
||||
- { pkg: clang, exe: 'clang++', version: 10 }
|
||||
- { pkg: clang, exe: 'clang++', version: 11 }
|
||||
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install ${{ matrix.compiler.exe }}
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
|
||||
- name: Compile tests
|
||||
env:
|
||||
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
|
||||
run: |
|
||||
cmake ${{ matrix.mode }} --preset ci-ubuntu
|
||||
cmake --build build/ --parallel 2
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 5 -C Debug -j2
|
||||
38
.github/workflows/build-ubuntu-latest.yml
vendored
Normal file
38
.github/workflows/build-ubuntu-latest.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: build-ubuntu-latest
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
matrix:
|
||||
compiler:
|
||||
- { pkg: g++, exe: 'g++', version: 10 }
|
||||
- { pkg: g++, exe: 'g++', version: 11 }
|
||||
- { pkg: g++, exe: 'g++', version: 12 }
|
||||
- { pkg: clang, exe: 'clang++', version: 12 }
|
||||
- { pkg: clang, exe: 'clang++', version: 13 }
|
||||
- { pkg: clang, exe: 'clang++', version: 14 }
|
||||
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install ${{ matrix.compiler.exe }}
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
|
||||
- name: Compile tests
|
||||
env:
|
||||
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
|
||||
run: |
|
||||
cmake ${{ matrix.mode }} --preset ci-ubuntu
|
||||
cmake --build build/ --parallel 2
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 5 -C Debug -j2
|
||||
22
.github/workflows/build-win.yml
vendored
Normal file
22
.github/workflows/build-win.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: build-win
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
windows:
|
||||
timeout-minutes: 60
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
generator: [Visual Studio 17 2022]
|
||||
mode: [-DUVW_BUILD_SHARED_LIB=ON, -DUVW_BUILD_LIBS=ON, -DUVW_BUILD_LIBS=OFF]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF -DCMAKE_CXX_FLAGS=/W1 -G"${{ matrix.generator }}" ..
|
||||
cmake --build . -j 2
|
||||
33
.github/workflows/coverage.yml
vendored
Normal file
33
.github/workflows/coverage.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: coverage
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
codecov:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXXFLAGS: "-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
|
||||
CXX: g++
|
||||
run: |
|
||||
cmake -DUVW_BUILD_TESTING=ON -Dlibuv_buildtests=OFF ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 5 -C Debug -j4
|
||||
- name: Upload coverage to Codecov
|
||||
working-directory: build
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
wget https://codecov.io/bash -O codecov
|
||||
chmod +x codecov
|
||||
./codecov -t $CODECOV_TOKEN -B $GITHUB_REF -s .
|
||||
32
.github/workflows/deploy.yml
vendored
Normal file
32
.github/workflows/deploy.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
|
||||
conan:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: docker://conanio/gcc8
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@master
|
||||
with:
|
||||
version: 3.7
|
||||
- name: Install
|
||||
run: |
|
||||
pip install --upgrade wheel
|
||||
pip install conan_package_tools
|
||||
- name: Deploy
|
||||
env:
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASSWORD }}
|
||||
CONAN_UPLOAD: ${{ secrets.CONAN_UPLOAD }}
|
||||
CONAN_GCC_VERSIONS: 8
|
||||
run: |
|
||||
python .conan/build.py
|
||||
30
.github/workflows/sanitizer.yml
vendored
Normal file
30
.github/workflows/sanitizer.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
clang:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [clang++]
|
||||
sanitizer: [ASAN, UBSAN]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
run: |
|
||||
cmake ${{ matrix.mode }} -DUVW_BUILD_TESTING=ON -DUVW_USE_${{ matrix.sanitizer }}=ON -Dlibuv_buildtests=OFF ..
|
||||
make -j2
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 5 -C Debug -j2
|
||||
78
.github/workflows/tools.yml
vendored
Normal file
78
.github/workflows/tools.yml
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
name: tools
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- tools
|
||||
|
||||
jobs:
|
||||
|
||||
iwyu:
|
||||
timeout-minutes: 60
|
||||
|
||||
env:
|
||||
IWYU: "0.22"
|
||||
LLVM: "18"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install llvm/clang
|
||||
# see: https://apt.llvm.org/
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main"
|
||||
sudo apt update
|
||||
sudo apt remove -y "llvm*"
|
||||
sudo apt remove -y "libclang-dev*"
|
||||
sudo apt remove -y "clang*"
|
||||
sudo apt install -y llvm-$LLVM-dev
|
||||
sudo apt install -y libclang-$LLVM-dev
|
||||
sudo apt install -y clang-$LLVM
|
||||
- name: Compile iwyu
|
||||
# see: https://github.com/include-what-you-use/include-what-you-use
|
||||
working-directory: build
|
||||
run: |
|
||||
git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1
|
||||
mkdir include-what-you-use/build
|
||||
cd include-what-you-use/build
|
||||
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
|
||||
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||
-DCMAKE_INSTALL_PREFIX=./ \
|
||||
..
|
||||
make -j4
|
||||
bin/include-what-you-use --version
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin
|
||||
cmake -DUVW_BUILD_TESTING=ON \
|
||||
-Dlibuv_buildtests=OFF \
|
||||
-DCMAKE_C_COMPILER=clang-$LLVM \
|
||||
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||
-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/uvw.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \
|
||||
..
|
||||
make -j4
|
||||
|
||||
clang-tidy:
|
||||
timeout-minutes: 60
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: clang++
|
||||
run: |
|
||||
cmake -DUVW_BUILD_TESTING=ON -DUVW_USE_CLANG_TIDY=ON -Dlibuv_buildtests=OFF ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest -C Debug -j4
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,2 +1,9 @@
|
||||
# QtCreator
|
||||
*.user
|
||||
CMakeSettings.json
|
||||
.conan/test_package/build
|
||||
cmake-build-debug/
|
||||
.idea/
|
||||
.vs/
|
||||
.vscode/
|
||||
.cache/
|
||||
out/
|
||||
|
||||
52
.travis.yml
52
.travis.yml
@ -1,52 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-5']
|
||||
env: COMPILER=g++-5
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6']
|
||||
env: COMPILER=g++-6
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
|
||||
packages: ['clang-3.8']
|
||||
env: COMPILER=clang++-3.8
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER=clang++
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER=clang++
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
||||
|
||||
install:
|
||||
- echo ${PATH}
|
||||
- ./travis.sh
|
||||
- cmake --version
|
||||
- export CXX=${COMPILER}
|
||||
- echo ${CXX}
|
||||
- ${CXX} --version
|
||||
- ${CXX} -v
|
||||
|
||||
script:
|
||||
- mkdir -p build && cd build
|
||||
- cmake .. && make -j4
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 make test
|
||||
33
AUTHORS
33
AUTHORS
@ -1,14 +1,29 @@
|
||||
# Author
|
||||
|
||||
Michele Caini aka skypjack
|
||||
skypjack
|
||||
|
||||
# Collaborators
|
||||
|
||||
morbo84
|
||||
stefanofiorentino
|
||||
|
||||
# Contributors
|
||||
|
||||
Federico Bertolucci aka lessness
|
||||
Luca Martini aka lordlukas
|
||||
Elia Mazzuoli aka Zikoel
|
||||
Francesco De Felice aka fradefe
|
||||
Tushar Maheshwari aka tusharpm
|
||||
Paolo Monteverde aka morbo84
|
||||
Jan Vcelak aka fcelda
|
||||
Raoul Hecky aka raoul
|
||||
lessness
|
||||
lordlukas
|
||||
lpmi-13
|
||||
Zikoel
|
||||
fradefe
|
||||
tusharpm
|
||||
fcelda
|
||||
raoul
|
||||
filonik
|
||||
yisonPylkita
|
||||
Miigon
|
||||
slyshykO
|
||||
bmagistro
|
||||
richardbmx
|
||||
wnsgml972
|
||||
ffontaine
|
||||
elindsey
|
||||
erez-o
|
||||
|
||||
361
CMakeLists.txt
361
CMakeLists.txt
@ -2,164 +2,263 @@
|
||||
# uvw
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
#
|
||||
# Building in-tree is not allowed (we take care of your craziness).
|
||||
#
|
||||
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Project configuration
|
||||
#
|
||||
set(UVW_VERSION_MAJOR 3)
|
||||
set(UVW_VERSION_MINOR 5)
|
||||
set(UVW_VERSION_PATCH 0)
|
||||
|
||||
project(uvw)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
project(
|
||||
uvw
|
||||
VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH}
|
||||
DESCRIPTION "Header-only, event based, tiny and easy to use libuv wrapper in modern C++ - now available also as static library!"
|
||||
HOMEPAGE_URL "https://github.com/skypjack/uvw"
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
set(PROJECT_NAME "uvw")
|
||||
set(PROJECT_VERSION_MAJOR 1)
|
||||
set(PROJECT_VERSION_MINOR 0)
|
||||
set(PROJECT_VERSION_PATCH 0)
|
||||
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
set(SETTINGS_ORGANIZATION "Michele Caini")
|
||||
set(SETTINGS_APPLICATION ${PROJECT_NAME})
|
||||
set(PROJECT_AUTHOR "Michele Caini")
|
||||
set(PROJECT_YEAR_COPYRIGHT "2017")
|
||||
set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
|
||||
option(UVW_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." ON)
|
||||
option(UVW_USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
|
||||
option(UVW_USE_UBSAN "Use address sanitizer by adding -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer flags" OFF)
|
||||
option(UVW_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF)
|
||||
option(UVW_BUILD_LIBS "Prepare targets for static library rather than for a header-only library." OFF)
|
||||
option(UVW_BUILD_SHARED_LIB "Prepare targets for shared library rather than for a header-only library." OFF)
|
||||
option(UVW_FIND_LIBUV "Try finding libuv library development files in the system" OFF)
|
||||
|
||||
set(PROJECT_BUILD_MESSAGE ${PROJECT_NAME} " v" ${PROJECT_VERSION} " (" ${CMAKE_BUILD_TYPE} ")")
|
||||
set(COPYRIGHT_BUILD_MESSAGE "Copyright (c) " ${PROJECT_YEAR_COPYRIGHT} " " ${PROJECT_AUTHOR} " <" ${PROJECT_AUTHOR_EMAIL} ">")
|
||||
if(UVW_BUILD_SHARED_LIB)
|
||||
set(UVW_BUILD_LIBS BOOL:ON)
|
||||
endif()
|
||||
|
||||
message("*")
|
||||
message("* " ${PROJECT_BUILD_MESSAGE})
|
||||
message("* " ${COPYRIGHT_BUILD_MESSAGE})
|
||||
message("*")
|
||||
#
|
||||
# Compiler stuff
|
||||
#
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined,dynamic_lookup")
|
||||
else(APPLE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
endif(APPLE)
|
||||
if(NOT WIN32 AND UVW_USE_LIBCPP)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
endif(NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -DDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -DRELEASE")
|
||||
cmake_push_check_state()
|
||||
|
||||
add_definitions(
|
||||
-DPROJECT_NAME=${PROJECT_NAME}
|
||||
-DPROJECT_VERSION=${PROJECT_VERSION}
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include<type_traits>
|
||||
int main() { return std::is_same_v<int, char>; }
|
||||
" UVW_HAS_LIBCPP)
|
||||
|
||||
if(NOT UVW_HAS_LIBCPP)
|
||||
message(WARNING "The option UVW_USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.")
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if(UVW_USE_CLANG_TIDY)
|
||||
find_program(UVW_CLANG_TIDY_EXECUTABLE "clang-tidy")
|
||||
|
||||
if(NOT UVW_CLANG_TIDY_EXECUTABLE)
|
||||
message(VERBOSE "The option UVW_USE_CLANG_TIDY is set but clang-tidy executable is not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Required minimal libuv version
|
||||
set(UVW_LIBUV_VERSION 1.49.0)
|
||||
|
||||
function(fetch_libuv)
|
||||
if (UVW_FETCH_LIBUV)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
libuv
|
||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||
GIT_TAG "v${UVW_LIBUV_VERSION}"
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(libuv)
|
||||
|
||||
if(NOT libuv_POPULATED)
|
||||
FetchContent_Populate(libuv)
|
||||
add_subdirectory(${libuv_SOURCE_DIR} ${libuv_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if(UVW_BUILD_SHARED_LIB)
|
||||
add_library(uv::uv-shared ALIAS uv)
|
||||
set_target_properties(uv PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
else()
|
||||
add_library(uv::uv-static ALIAS uv_a)
|
||||
set_target_properties(uv_a PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
endif()
|
||||
endif(UVW_FETCH_LIBUV)
|
||||
endfunction()
|
||||
|
||||
function(use_libuv)
|
||||
set(UVW_FETCH_LIBUV_DEFAULT ON)
|
||||
|
||||
if (UVW_FIND_LIBUV)
|
||||
find_package(libuv ${LIBUV_VERSION} QUIET)
|
||||
if (libuv_FOUND)
|
||||
add_library(uv::uv-shared ALIAS uv)
|
||||
set(UVW_FETCH_LIBUV_DEFAULT OFF)
|
||||
message(STATUS "libuv ${libuv_VERSION} found via cmake")
|
||||
else(libuv_FOUND)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PkgConfig_FOUND)
|
||||
pkg_check_modules(libuv IMPORTED_TARGET libuv>=${LIBUV_VERSION})
|
||||
if (libuv_FOUND)
|
||||
add_library(uv::uv-shared ALIAS PkgConfig::libuv)
|
||||
set(UVW_FETCH_LIBUV_DEFAULT OFF)
|
||||
message(STATUS "libuv ${libuv_VERSION} found via pkg-config")
|
||||
endif(libuv_FOUND)
|
||||
endif(PkgConfig_FOUND)
|
||||
endif(libuv_FOUND)
|
||||
endif(UVW_FIND_LIBUV)
|
||||
|
||||
option(UVW_FETCH_LIBUV "Fetch the libuv repo using CMake FetchContent facility" ${UVW_FETCH_LIBUV_DEFAULT})
|
||||
|
||||
fetch_libuv()
|
||||
endfunction()
|
||||
|
||||
#
|
||||
# Add uvw target
|
||||
#
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(UVW_BUILD_LIBS)
|
||||
use_libuv()
|
||||
|
||||
add_subdirectory(src)
|
||||
file(GLOB HEADERS src/uvw/*.h src/uvw/*.hpp)
|
||||
else()
|
||||
add_library(uvw INTERFACE)
|
||||
add_library(uvw::uvw ALIAS uvw)
|
||||
|
||||
target_compile_features(uvw INTERFACE cxx_std_17)
|
||||
|
||||
target_include_directories(
|
||||
uvw
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${uvw_SOURCE_DIR}/src>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
if(UVW_USE_ASAN)
|
||||
target_compile_options(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||
target_link_libraries(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=address>)
|
||||
endif()
|
||||
|
||||
if(UVW_USE_UBSAN)
|
||||
target_compile_options(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer>)
|
||||
target_link_libraries(uvw INTERFACE $<$<CONFIG:Debug>:-fsanitize=undefined>)
|
||||
endif()
|
||||
|
||||
if(UVW_CLANG_TIDY_EXECUTABLE)
|
||||
set(CMAKE_CXX_CLANG_TIDY "${UVW_CLANG_TIDY_EXECUTABLE};--config-file=${uvw_SOURCE_DIR}/.clang-tidy;--header-filter=${uvw_SOURCE_DIR}/src/uvw/.*")
|
||||
endif()
|
||||
|
||||
if(UVW_HAS_LIBCPP)
|
||||
target_compile_options(uvw BEFORE INTERFACE -stdlib=libc++)
|
||||
endif()
|
||||
|
||||
file(GLOB HEADERS src/uvw/*.h src/uvw/*.hpp)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Install targets
|
||||
#
|
||||
|
||||
install(
|
||||
FILES ${HEADERS}
|
||||
COMPONENT ${PROJECT_NAME}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uvw
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
)
|
||||
|
||||
install(
|
||||
FILES src/uvw.hpp
|
||||
COMPONENT ${PROJECT_NAME}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
)
|
||||
|
||||
#
|
||||
# CMake configuration
|
||||
# Install targets
|
||||
#
|
||||
|
||||
set(PROJECT_CMAKE_MODULES cmake/modules)
|
||||
set(PROJECT_CMAKE_IN cmake/in)
|
||||
set(PROJECT_BUILD_DIR build)
|
||||
set(PROJECT_DEPS_DIR deps)
|
||||
set(PROJECT_DOCS_DIR docs)
|
||||
set(PROJECT_SRC_DIR src)
|
||||
set(PROJECT_TEST_DIR test)
|
||||
if (UVW_BUILD_LIBS)
|
||||
set_target_properties(
|
||||
uvw PROPERTIES
|
||||
VERSION ${UVW_VERSION_MAJOR}.${UVW_VERSION_MINOR}.${UVW_VERSION_PATCH}
|
||||
SOVERSION ${UVW_VERSION_MAJOR}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(PROJECT_RUNTIME_OUTPUT_DIRECTORY bin)
|
||||
|
||||
set(
|
||||
CMAKE_MODULE_PATH
|
||||
${CMAKE_MODULE_PATH}
|
||||
${CMAKE_SOURCE_DIR}/${PROJECT_CMAKE_MODULES}
|
||||
install(
|
||||
EXPORT uvwConfig
|
||||
NAMESPACE uvw::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/uvw
|
||||
)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_RUNTIME_OUTPUT_DIRECTORY})
|
||||
|
||||
#
|
||||
# Enable test support using ctest
|
||||
#
|
||||
|
||||
enable_testing()
|
||||
|
||||
#
|
||||
# Referenced packages
|
||||
#
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(Doxygen 1.8)
|
||||
find_package(LibRt)
|
||||
|
||||
#
|
||||
# Download and unpack dependencies
|
||||
#
|
||||
|
||||
set(GOOGLETEST_DEPS_DIR ${CMAKE_SOURCE_DIR}/${PROJECT_DEPS_DIR}/googletest)
|
||||
set(LIBUV_DEPS_DIR ${CMAKE_SOURCE_DIR}/${PROJECT_DEPS_DIR}/libuv)
|
||||
|
||||
# gtest, gtest_main, gmock and gmock_main targets are available from now on
|
||||
configure_file(${PROJECT_CMAKE_IN}/googletest.in ${GOOGLETEST_DEPS_DIR}/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
add_subdirectory(${GOOGLETEST_DEPS_DIR}/src ${GOOGLETEST_DEPS_DIR}/build)
|
||||
|
||||
configure_file(${PROJECT_CMAKE_IN}/libuv.in ${LIBUV_DEPS_DIR}/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${LIBUV_DEPS_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${LIBUV_DEPS_DIR})
|
||||
include_directories(${LIBUV_DEPS_DIR}/src/include)
|
||||
find_library(libuv_static NAMES libuv.a libuv PATHS ${LIBUV_DEPS_DIR}/src PATH_SUFFIXES .libs Release NO_DEFAULT_PATH)
|
||||
find_library(libuv_shared NAMES uv libuv PATHS ${LIBUV_DEPS_DIR}/src PATH_SUFFIXES .libs Release NO_DEFAULT_PATH)
|
||||
|
||||
#
|
||||
# Referenced directories and targets
|
||||
#
|
||||
|
||||
if(${DOXYGEN_FOUND})
|
||||
add_subdirectory(${PROJECT_DOCS_DIR})
|
||||
endif(${DOXYGEN_FOUND})
|
||||
|
||||
add_subdirectory(${PROJECT_TEST_DIR})
|
||||
|
||||
#
|
||||
# Keep your stuff and go further away, foolish.
|
||||
#
|
||||
|
||||
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PACKAGE_VENDOR ${PROJECT_AUTHOR})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "uvw")
|
||||
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION})
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME}-src)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE)
|
||||
set(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/README.md)
|
||||
set(CPACK_GENERATOR TGZ)
|
||||
set(CPACK_SOURCE_GENERATOR TGZ)
|
||||
set(CPACK_PACKAGING_INSTALL_DIRECTORY "uvw-${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}")
|
||||
|
||||
include(CPack)
|
||||
|
||||
#
|
||||
# I use QtCreator and I need the lines below, so do not ask. :-)
|
||||
#
|
||||
|
||||
file(
|
||||
GLOB_RECURSE PROJECT_FILES FOLLOW_SYMLINKS
|
||||
*.txt *.c *.cpp *.hpp *.h *.in *.cmake *.sh *.md *.yml *.bat AUTHORS LICENSE
|
||||
install(
|
||||
TARGETS uvw
|
||||
EXPORT uvwConfig
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
QTCREATOR_FALLBACK ALL
|
||||
COMMENT "Feel free to ignore this target, but please do not remove it."
|
||||
SOURCES ${PROJECT_FILES}
|
||||
)
|
||||
if(UVW_FETCH_LIBUV AND UVW_BUILD_LIBS)
|
||||
# libuv is only fetched when both above conditions are true
|
||||
install(DIRECTORY ${libuv_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/uvw/uv/include)
|
||||
if (UVW_BUILD_SHARED_LIB)
|
||||
install(TARGETS uv EXPORT uvwConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/uvw)
|
||||
else()
|
||||
install(TARGETS uv_a EXPORT uvwConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/uvw)
|
||||
endif()
|
||||
endif(UVW_FETCH_LIBUV AND UVW_BUILD_LIBS)
|
||||
|
||||
export(EXPORT uvwConfig)
|
||||
|
||||
### Testing
|
||||
|
||||
option(UVW_BUILD_TESTING "Enable testing with ctest." OFF)
|
||||
|
||||
if(UVW_BUILD_TESTING)
|
||||
option(UVW_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
|
||||
|
||||
if (NOT UVW_BUILD_LIBS)
|
||||
use_libuv()
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Documentation
|
||||
#
|
||||
|
||||
option(UVW_BUILD_DOCS "Enable building with documentation." OFF)
|
||||
|
||||
if(UVW_BUILD_DOCS)
|
||||
find_package(Doxygen 1.10)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
59
CMakePresets.json
Normal file
59
CMakePresets.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"version": 2,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 13,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "cmake-pedantic",
|
||||
"description": "Enables all CMake warnings.`",
|
||||
"hidden": true,
|
||||
"warnings": {
|
||||
"dev": true,
|
||||
"deprecated": true,
|
||||
"uninitialized": true,
|
||||
"unusedCli": true,
|
||||
"systemVars": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-mode",
|
||||
"hidden": true,
|
||||
"description": "Common (non-OS specific) mode for development",
|
||||
"inherits": "cmake-pedantic",
|
||||
"cacheVariables": {
|
||||
"UVW_BUILD_TESTING": true,
|
||||
"libuv_buildtests": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "flags-linux",
|
||||
"hidden": true,
|
||||
"description": "Compiler flags for GNU and Clang compilers. When compiling in DEBUG mode, all warnings will be converted into errors.",
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wimplicit-fallthrough -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-Werror"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-linux",
|
||||
"generator": "Unix Makefiles",
|
||||
"hidden": true,
|
||||
"inherits": ["flags-linux"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-build",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu",
|
||||
"inherits": ["ci-build", "ci-linux", "dev-mode"]
|
||||
}
|
||||
]
|
||||
}
|
||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Michele Caini
|
||||
Copyright (c) 2016-2024 Michele Caini
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
451
README.md
451
README.md
@ -1,32 +1,49 @@
|
||||
 **Sponsored and contributed by [Cynny SpA](https://www.cynny.com/).**
|
||||

|
||||
|
||||
# uvw - libuv wrapper in modern C++
|
||||
[](https://github.com/skypjack/uvw/actions)
|
||||
[](https://codecov.io/gh/skypjack/uvw)
|
||||
[](https://skypjack.github.io/uvw/)
|
||||
[](https://vcpkg.link/ports/uvw)
|
||||
[](https://gitter.im/skypjack/uvw)
|
||||
[](https://www.paypal.me/skypjack)
|
||||
|
||||
[](https://travis-ci.org/skypjack/uvw)
|
||||
[](https://ci.appveyor.com/project/skypjack/uvw)
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=W2HF9FESD5LJY&lc=IT&item_name=Michele%20Caini¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted)
|
||||
Do you have a **question** that doesn't require you to open an issue? Join the
|
||||
[gitter channel](https://gitter.im/skypjack/uvw).<br/>
|
||||
If you use `uvw` and you want to say thanks or support the project, please
|
||||
**consider becoming a
|
||||
[sponsor](https://github.com/users/skypjack/sponsorship)**.<br/>
|
||||
You can help me make the difference.
|
||||
[Many thanks](https://skypjack.github.io/sponsorship/) to those who supported me
|
||||
and still support me today.
|
||||
|
||||
# Introduction
|
||||
|
||||
`uvw` is a header-only, event based, tiny and easy to use *libuv* wrapper in modern C++.<br/>
|
||||
The basic idea is to hide completely the *C-ish* interface of *libuv* behind a graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by the library.<br/>
|
||||
Note that `uvw` stays true to the API of *libuv* and it doesn't add anything to its interface. For the same reasons, users of the library must follow the same rules who are used to follow with *libuv*.<br/>
|
||||
As an example, a *handle* should be initialized before any other operation and closed once it is no longer in use.
|
||||
`uvw` started as a header-only, event based, tiny and easy to use wrapper for
|
||||
[`libuv`](https://github.com/libuv/libuv) written in modern C++.<br/>
|
||||
Now it's finally available also as a compilable static library.
|
||||
|
||||
The basic idea is to wrap the *C-ish* interface of `libuv` behind a graceful C++
|
||||
API.<br/>
|
||||
Note that `uvw` stays true to the API of `libuv` and it doesn't add anything to
|
||||
its interface. For the same reasons, users of the library must follow the same
|
||||
rules which are used with `libuv`.<br/>
|
||||
As an example, a *handle* should be initialized before any other operation and
|
||||
closed once it is no longer in use.
|
||||
|
||||
## Code Example
|
||||
|
||||
```
|
||||
```cpp
|
||||
#include <uvw.hpp>
|
||||
#include <memory>
|
||||
|
||||
void listen(uvw::Loop &loop) {
|
||||
std::shared_ptr<uvw::TcpHandle> tcp = loop.resource<uvw::TcpHandle>();
|
||||
void listen(uvw::loop &loop) {
|
||||
std::shared_ptr<uvw::tcp_handle> tcp = loop.resource<uvw::tcp_handle>();
|
||||
|
||||
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TcpHandle &srv) {
|
||||
std::shared_ptr<uvw::TcpHandle> client = srv.loop().resource<uvw::TcpHandle>();
|
||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||
|
||||
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::TcpHandle &) { ptr->close(); });
|
||||
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TcpHandle &client) { client.close(); });
|
||||
client->on<uvw::close_event>([ptr = srv.shared_from_this()](const uvw::close_event &, uvw::tcp_handle &) { ptr->close(); });
|
||||
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
||||
|
||||
srv.accept(*client);
|
||||
client->read();
|
||||
@ -36,12 +53,12 @@ void listen(uvw::Loop &loop) {
|
||||
tcp->listen();
|
||||
}
|
||||
|
||||
void conn(uvw::Loop &loop) {
|
||||
auto tcp = loop.resource<uvw::TcpHandle>();
|
||||
void conn(uvw::loop &loop) {
|
||||
auto tcp = loop.resource<uvw::tcp_handle>();
|
||||
|
||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TcpHandle &) { /* handle errors */ });
|
||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* handle errors */ });
|
||||
|
||||
tcp->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TcpHandle &tcp) {
|
||||
tcp->on<uvw::connect_event>([](const uvw::connect_event &, uvw::tcp_handle &tcp) {
|
||||
auto dataWrite = std::unique_ptr<char[]>(new char[2]{ 'b', 'c' });
|
||||
tcp.write(std::move(dataWrite), 2);
|
||||
tcp.close();
|
||||
@ -51,7 +68,7 @@ void conn(uvw::Loop &loop) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto loop = uvw::Loop::getDefault();
|
||||
auto loop = uvw::loop::get_default();
|
||||
listen(*loop);
|
||||
conn(*loop);
|
||||
loop->run();
|
||||
@ -60,7 +77,8 @@ int main() {
|
||||
|
||||
## Motivation
|
||||
|
||||
The main reason for which `uvw` has been written is the fact that it does not exist a valid *libuv* wrapper in C++. That's all.
|
||||
The main reason for which `uvw` has been written is the fact that there does not
|
||||
exist a valid `libuv` wrapper in C++. That's all.
|
||||
|
||||
# Build Instructions
|
||||
|
||||
@ -68,181 +86,303 @@ The main reason for which `uvw` has been written is the fact that it does not ex
|
||||
|
||||
To be able to use `uvw`, users must provide the following system-wide tools:
|
||||
|
||||
* A full-featured compiler that supports at least C++14.
|
||||
* `libuv` (which version depends on the tag of `uvw` in use).
|
||||
* A full-featured compiler that supports at least C++17.
|
||||
* `libuv` (which version depends on the tag of `uvw` in use)
|
||||
* If you use `meson`, libuv will be downloaded for you
|
||||
|
||||
The requirements below are mandatory to compile the tests and to extract the documentation:
|
||||
The requirements below are mandatory to compile the tests and to extract the
|
||||
documentation:
|
||||
|
||||
* CMake version 3.4 or later.
|
||||
* CMake version 3.13 or later.
|
||||
* Doxygen version 1.8 or later.
|
||||
|
||||
Note that `libuv` is part of the dependencies of the project and it will be cloned by `cmake` (see below for further details).<br/>
|
||||
Because of that, users have not to install it to compile and execute the tests.
|
||||
Note that `libuv` is part of the dependencies of the project and may be cloned
|
||||
by `CMake` in some cases (see below for further details).<br/>
|
||||
Because of that, users don't have to install it to run the tests or when `uvw`
|
||||
libraries are compiled through `CMake`.
|
||||
|
||||
## Meson
|
||||
|
||||
You can use `uvw` with [meson](https://mesonbuild.com/) by simply adding it to
|
||||
your `subprojects` directory in your project.
|
||||
|
||||
To compile `uvw` from source without using it as a subproject, in the `uvw`
|
||||
source directory, run:
|
||||
|
||||
* `$ meson setup build`
|
||||
* If you want a static library, add `--default-library=static`
|
||||
* `$ cd build`
|
||||
* `$ meson compile`
|
||||
|
||||
## Library
|
||||
|
||||
`uvw` is a header-only library.<br/>
|
||||
This means that including the `uvw.hpp` header or one of the other `uvw/*.hpp` headers is enough to use it.<br/>
|
||||
`uvw` is a dual-mode library. It can be used in its header-only form or as a
|
||||
compiled static library.<br/>
|
||||
The following sections describe what to do in both cases to get `uvw` up and
|
||||
runningin your own project.
|
||||
|
||||
### Header-only
|
||||
|
||||
To use `uvw` as a header-only library, all is needed is to include the `uvw.hpp`
|
||||
header or one of the other `uvw/*.hpp` files.<br/>
|
||||
It's a matter of adding the following line at the top of a file:
|
||||
|
||||
#include <uvw.hpp>
|
||||
```cpp
|
||||
#include <uvw.hpp>
|
||||
```
|
||||
|
||||
Then pass the proper `-I` argument to the compiler to add the `src` directory to the include paths.<br/>
|
||||
Note that users are demanded to correctly setup include directories and libraries search paths for *libuv*.
|
||||
Then pass the proper `-I` argument to the compiler to add the `src` directory to
|
||||
the include paths.<br/>
|
||||
Note that users are required to correctly setup the include directories and
|
||||
libraries search paths for `libuv` in this case.
|
||||
|
||||
When used through `CMake`, the `uvw::uvw` target is exported for convenience.
|
||||
|
||||
### Static
|
||||
|
||||
To use `uvw` as a compiled library, set the `UVW_BUILD_LIBS` options in cmake
|
||||
before including the project.<br/>
|
||||
This option triggers the generation of a targets named
|
||||
`uvw::uvw-static`. The matching version of `libuv` is also
|
||||
compiled and exported as `uv::uv-static` for convenience.
|
||||
|
||||
In case you don't use or don't want to use `CMake`, you can still compile all
|
||||
`.cpp` files and include all `.h` files to get the job done. In this case, users
|
||||
are required to correctly setup the include directories and libraries search
|
||||
paths for `libuv`.
|
||||
|
||||
## Versioning
|
||||
|
||||
Starting with tag _v1.12.0_ of `libuv`, `uvw` follows the [semantic versioning](http://semver.org/) scheme.<br/>
|
||||
The problem is that any version of `uvw` also requires to track explicitly the version of `libuv` to which it is bound.<br/>
|
||||
Because of that, the latter wil be appended to the version of `uvw`. As an example:
|
||||
Starting with tag _v1.12.0_ of `libuv`, `uvw` follows the
|
||||
[semantic versioning](http://semver.org/) scheme.<br/>
|
||||
The problem is that any version of `uvw` also requires to track explicitly the
|
||||
version of `libuv` to which it is bound.<br/>
|
||||
Because of that, the latter wil be appended to the version of `uvw`. As an
|
||||
example:
|
||||
|
||||
vU.V.W_libuv-vX.Y
|
||||
|
||||
In particular, the following applies:
|
||||
|
||||
* _U.V.W_ are major, minor and patch versions of `uvw`.
|
||||
* _X.Y_ is the version of `libuv` to which to refer (where any patch version is valid).
|
||||
* _X.Y_ is the version of `libuv` to which to refer (where any patch version is
|
||||
valid).
|
||||
|
||||
In other terms, tags will look like this from now on:
|
||||
|
||||
v1.0.0_libuv-v1.12
|
||||
|
||||
Branch `master` of `uvw` will be a work in progress branch that follows branch _v1.x_ of `libuv` (at least as long as it remains their _master_ branch).<br/>
|
||||
Branch `master` of `uvw` will be a work in progress branch that follows branch
|
||||
_v1.x_ of `libuv` (at least as long as it remains their _master_ branch).<br/>
|
||||
|
||||
## Documentation
|
||||
|
||||
### API Reference
|
||||
|
||||
The documentation is based on [`doxygen`](http://www.stack.nl/~dimitri/doxygen/). To build it:
|
||||
The documentation is based on
|
||||
[`doxygen`](https://www.doxygen.nl/). To build it:
|
||||
|
||||
* `$ cd build`
|
||||
* `$ cmake ..`
|
||||
* `$ make docs`
|
||||
|
||||
The API reference will be created in HTML format within the directory `build/docs/html`.<br/>
|
||||
The API reference will be created in HTML format within the directory
|
||||
`build/docs/html`.<br/>
|
||||
To navigate it with your favorite browser:
|
||||
|
||||
* `$ cd build`
|
||||
* `$ your_favorite_browser docs/html/index.html`
|
||||
|
||||
### Crash Course
|
||||
The same version is also available [online](https://skypjack.github.io/uvw/)
|
||||
for the latest release, that is the last stable tag.
|
||||
|
||||
#### Vademecum
|
||||
### Note
|
||||
|
||||
There is only one rule when using `uvw`: always initialize the resources and terminate them.
|
||||
The documentation is mostly inspired by the official
|
||||
[libuv API documentation](http://docs.libuv.org/en/v1.x/) for obvious
|
||||
reasons.
|
||||
|
||||
## Tests
|
||||
|
||||
To compile and run the tests, `uvw` requires `libuv` and `googletest`.<br/>
|
||||
`CMake` will download and compile both the libraries before compiling anything
|
||||
else.
|
||||
|
||||
To build the tests:
|
||||
|
||||
* `$ cd build`
|
||||
* `$ cmake .. -DUVW_BUILD_TESTING=ON`
|
||||
* `$ make`
|
||||
* `$ ctest -j4 -R uvw`
|
||||
|
||||
Omit `-R uvw` if you also want to test `libuv` and other dependencies.
|
||||
|
||||
# Crash Course
|
||||
|
||||
## Vademecum
|
||||
|
||||
There is only one rule when using `uvw`: always initialize the resources and
|
||||
terminate them.
|
||||
|
||||
Resources belong mainly to two families: _handles_ and _requests_.<br/>
|
||||
Handles represent long-lived objects capable of performing certain operations while active.<br/>
|
||||
Requests represent (typically) short-lived operations performed either over a handle or standalone.
|
||||
Handles represent long-lived objects capable of performing certain operations
|
||||
while active.<br/>
|
||||
Requests represent (typically) short-lived operations performed either over a
|
||||
handle or standalone.
|
||||
|
||||
The following sections will explain in short what it means to initialize and terminate these kinds of resources.
|
||||
The following sections will explain in short what it means to initialize and
|
||||
terminate these kinds of resources.<br/>
|
||||
For more details, please refer to the
|
||||
[online documentation](https://skypjack.github.io/uvw/).
|
||||
|
||||
#### Handles
|
||||
## Handles
|
||||
|
||||
Initialization is usually performed under the hood and can be even passed over, as far as handles are created using the `Loop::resource` member function.<br/>
|
||||
On the other side, handles keep themselves alive until one explicitly closes them. Because of that, memory usage will grow up if users simply forget about a handle.<br/>
|
||||
Therefore the rule quickly becomes *always close your handles*. It's as simple as calling the `close` member function on them.
|
||||
Initialization is usually performed under the hood and can be even passed over,
|
||||
as far as handles are created using the `loop::resource` member function.<br/>
|
||||
On the other side, handles keep themselves alive until one explicitly closes
|
||||
them. Because of that, memory usage will grow if users simply forget about a
|
||||
handle.<br/>
|
||||
Therefore the rule quickly becomes *always close your handles*. It's as simple
|
||||
as calling the `close` member function on them.
|
||||
|
||||
#### Requests
|
||||
## Requests
|
||||
|
||||
Usually initializing a request object is not required. Anyway, the recommended way to create a request is still through the `Loop::resource` member function.<br/>
|
||||
Requests will keep themselves alive as long as they are bound to unfinished underlying activities. This means that users have not to discard explicitly a request.<br/>
|
||||
Therefore the rule quickly becomes *feel free to make a request and forget about it*. It's as simple as calling a member function on them.
|
||||
Usually initializing a request object is not required. Anyway, the recommended
|
||||
way to create a request is still through the `loop::resource` member
|
||||
function.<br/>
|
||||
Requests will keep themselves alive as long as they are bound to unfinished
|
||||
underlying activities. This means that users don't have to discard a
|
||||
request explicitly .<br/>
|
||||
Therefore the rule quickly becomes *feel free to make a request and forget about
|
||||
it*. It's as simple as calling a member function on them.
|
||||
|
||||
#### The Loop and the Resource
|
||||
## The Loop and the Resource
|
||||
|
||||
The first thing to do to use `uvw` is to create a loop. In case the default one is enough, it's easy as doing this:
|
||||
The first thing to do to use `uvw` is to create a loop. In case the default one
|
||||
is enough, it's easy as doing this:
|
||||
|
||||
auto loop = uvw::Loop::getDefault();
|
||||
```cpp
|
||||
auto loop = uvw::loop::get_default();
|
||||
```
|
||||
|
||||
Note that loop objects don't require to be closed explicitly, even if they offer the `close` member function in case an user wants to do that.<br/>
|
||||
Loops can be started using the `run` member function. The two calls below are equivalent:
|
||||
Note that loop objects don't require being closed explicitly, even if they offer
|
||||
the `close` member function in case a user wants to do that.<br/>
|
||||
Loops can be started using the `run` member function. The two calls below are
|
||||
equivalent:
|
||||
|
||||
loop->run();
|
||||
loop->run<uvw::Loop::Mode::DEFAULT>
|
||||
```cpp
|
||||
loop->run();
|
||||
loop->run(uvw::loop::run_mode::DEFAULT);
|
||||
```
|
||||
|
||||
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the documentation of *libuv* for further details.
|
||||
Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the
|
||||
documentation of `libuv` for further details.
|
||||
|
||||
In order to create a resource and to bind it to the given loop, just do the following:
|
||||
In order to create a resource and to bind it to the given loop, just do the
|
||||
following:
|
||||
|
||||
auto tcp = loop.resource<uvw::TcpHandle>();
|
||||
```cpp
|
||||
auto tcp = loop->resource<uvw::tcp_handle>();
|
||||
```
|
||||
|
||||
The line above will create and initialize a tcp handle, then a shared pointer to that resource will be returned.<br/>
|
||||
Users should check if pointers have been correctly initialized: in case of errors, they won't be.<br/>
|
||||
Another way to create a resource is:
|
||||
The line above creates and initializes a tcp handle, then a shared pointer to
|
||||
that resource is returned.<br/>
|
||||
Users should check if pointers have been correctly initialized: in case of
|
||||
errors, they won't be.<br/>
|
||||
It also is possible to create uninitialized resources to init later on as:
|
||||
|
||||
auto tcp = TcpHandle::create(loop);
|
||||
tcp->init();
|
||||
```cpp
|
||||
auto tcp = loop->uninitialized_resource<uvw::tcp_handle>();
|
||||
tcp->init();
|
||||
```
|
||||
|
||||
Pretty annoying indeed. Using a loop is the recommended approach.
|
||||
|
||||
The resources also accept arbitrary user-data that won't be touched in any case.<br/>
|
||||
All resources also accept arbitrary user-data that won't be touched in any
|
||||
case.<br/>
|
||||
Users can set and get them through the `data` member function as it follows:
|
||||
|
||||
resource->data(std::make_shared<int>(42));
|
||||
std::shared_ptr<void> data = resource->data();
|
||||
```cpp
|
||||
resource->data(std::make_shared<int>(42));
|
||||
std::shared_ptr<void> data = resource->data();
|
||||
```
|
||||
|
||||
Resources expect a `std::shared_pointer<void>` and return it, therefore any kind of data is welcome.<br/>
|
||||
Users can explicitly specify a type other than `void` when calling the `data` member function:
|
||||
Resources expect a `std::shared_pointer<void>` and return it, therefore any kind
|
||||
of data is welcome.<br/>
|
||||
Users can explicitly specify a type other than `void` when calling the `data`
|
||||
member function:
|
||||
|
||||
std::shared_ptr<int> data = resource->data<int>();
|
||||
```cpp
|
||||
std::shared_ptr<int> data = resource->data<int>();
|
||||
```
|
||||
|
||||
Remember from the previous section that a handle will keep itself alive until one invokes the `close` member function on it.<br/>
|
||||
To know what are the handles that are still alive and bound to a given loop, just do the following:
|
||||
Remember from the previous section that a handle will keep itself alive until
|
||||
one invokes the `close` member function on it.<br/>
|
||||
To know what are the handles that are still alive and bound to a given loop,
|
||||
there exists the `walk` member function. It returns handles with their types.
|
||||
Therefore, the use of `overloaded` is recommended to be able to intercept all
|
||||
types of interest:
|
||||
|
||||
loop.walk([](uvw::BaseHandle &){ /* application code here */ });
|
||||
```cpp
|
||||
handle.parent().walk(uvw::overloaded{
|
||||
[](uvw::timer_handle &h){ /* application code for timers here */ },
|
||||
[](auto &&){ /* ignore all other types */ }
|
||||
});
|
||||
```
|
||||
|
||||
`BaseHandle` exposes a few methods and cannot be used to know the original type of the handle.<br/>
|
||||
Anyway, it can be used to close the handle that originated from it. As an example, all the pending handles can be closed easily as it follows:
|
||||
This function can also be used for a completely generic approach. For example,
|
||||
all the pending handles can be closed easily as it follows:
|
||||
|
||||
loop.walk([](uvw::BaseHandle &h){ h.close(); });
|
||||
```cpp
|
||||
loop->walk([](auto &&h){ h.close(); });
|
||||
```
|
||||
|
||||
No need to keep track of them.
|
||||
|
||||
To know what are the available resources' types, please refer the API reference.
|
||||
## The event-based approach
|
||||
|
||||
#### The event-based approach
|
||||
`uvw` offers an event-based approach where resources are small event emitters to
|
||||
which listeners are attached.<br/>
|
||||
Attaching listeners to resources is the recommended way to receive notifications
|
||||
about their operations.<br/>
|
||||
Listeners are callable objects of type `void(event_type &, resource_type &)`,
|
||||
where:
|
||||
|
||||
For `uvw` offers an event-based approach, resources are small event emitters to which listeners can be attached.<br/>
|
||||
Attaching a listener to a resource is the recommended way to be notified about changes.<br/>
|
||||
Listeners must be callable objects of type `void(EventType &, ResourceType &)`, where:
|
||||
|
||||
* `EventType` is the type of the event for which they have been designed.
|
||||
* `ResourceType` is the type of the resource that has originated the event.
|
||||
* `event_type` is the type of the event for which they have been designed.
|
||||
* `resource_type` is the type of the resource that has originated the event.
|
||||
|
||||
It means that the following function types are all valid:
|
||||
|
||||
* `void(EventType &, ResourceType &)`
|
||||
* `void(const EventType &, ResourceType &)`
|
||||
* `void(EventType &, const ResourceType &)`
|
||||
* `void(const EventType &, const ResourceType &)`
|
||||
* `void(event_type &, resource_type &)`
|
||||
* `void(const event_type &, resource_type &)`
|
||||
* `void(event_type &, const resource_type &)`
|
||||
* `void(const event_type &, const resource_type &)`
|
||||
|
||||
Once more, please note that there is no need to keep around references to the resources: they will pass themselves as an argument whenever an event is published.
|
||||
Please note that there is no need to keep around references to the resources,
|
||||
since they pass themselves as an argument whenever an event is published.<br/>
|
||||
The `on` member function is the way to go to register long-running listeners:
|
||||
|
||||
There exist two methods to attach an event to a resource:
|
||||
```cpp
|
||||
resource.on<event_type>(listener)
|
||||
```
|
||||
|
||||
* `resource.once<EventType>(listener)`: the listener will be automatically removed after the first event of the given type.
|
||||
* `resource.on<EventType>(listener)`: to be used for long-running listeners.
|
||||
To know if a listener exists for a given type, the class offers a `has` function
|
||||
template. Similarly, the `reset` function template is be used to reset and thus
|
||||
disconnect listeners, if any. A non-template version of `reset` also exists to
|
||||
clear an emitter as a whole.
|
||||
|
||||
Both of them return an object of type `ResourceType::Connection` (as an example, `TcpHandle::Connection`).<br/>
|
||||
A connection object can be used later as an argument to the `erase` member function of the resource to remove the listener.<br/>
|
||||
There exists also the `clear` member function to drop all the listeners at once.
|
||||
|
||||
Almost all the resources use to emit `ErrorEvent` events in case of errors.<br/>
|
||||
All the other events are specific for the given resource and documented in the API reference.
|
||||
Almost all the resources emit `error_event` in case of errors.<br/>
|
||||
All the other events are specific for the given resource and documented in the
|
||||
API reference.
|
||||
|
||||
The code below shows how to create a simple tcp server using `uvw`:
|
||||
|
||||
```
|
||||
auto loop = uvw::Loop::getDefault();
|
||||
auto tcp = loop.resource<uvw::TcpHandle>();
|
||||
```cpp
|
||||
auto loop = uvw::loop::get_default();
|
||||
auto tcp = loop->resource<uvw::tcp_handle>();
|
||||
|
||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TcpHandle &) { /* something went wrong */ });
|
||||
tcp->on<uvw::error_event>([](const uvw::error_event &, uvw::tcp_handle &) { /* something went wrong */ });
|
||||
|
||||
tcp->on<uvw::ListenEvent>([](const uvw::ListenEvent &, uvw::TcpHandle &srv) {
|
||||
std::shared_ptr<uvw::TcpHandle> client = srv.loop().resource<uvw::TcpHandle>();
|
||||
client->once<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TcpHandle &client) { client.close(); });
|
||||
client->on<uvw::DataEvent>([](const uvw::DataEvent &, uvw::TcpHandle &) { /* data received */ });
|
||||
tcp->on<uvw::listen_event>([](const uvw::listen_event &, uvw::tcp_handle &srv) {
|
||||
std::shared_ptr<uvw::tcp_handle> client = srv.parent().resource<uvw::tcp_handle>();
|
||||
client->on<uvw::end_event>([](const uvw::end_event &, uvw::tcp_handle &client) { client.close(); });
|
||||
client->on<uvw::data_event>([](const uvw::data_event &, uvw::tcp_handle &) { /* data received */ });
|
||||
srv.accept(*client);
|
||||
client->read();
|
||||
});
|
||||
@ -251,49 +391,66 @@ tcp->bind("127.0.0.1", 4242);
|
||||
tcp->listen();
|
||||
```
|
||||
|
||||
Note also that `uvw::TcpHandle` already supports _IPv6_ out-of-the-box. The statement above is equivalent to `tcp->bind<uvw::IPv4>("127.0.0.1", 4242)`.<br/>
|
||||
It's suffice to explicitly specify `uvw::IPv6` as the underlying protocol to use it.
|
||||
Note also that `uvw::tcp_handle` already supports _IPv6_ out-of-the-box.<br/>
|
||||
The API reference is the recommended documentation for further details about
|
||||
resources and their methods.
|
||||
|
||||
The API reference is the recommended documentation for further details about resources and their methods.
|
||||
## Going raw
|
||||
|
||||
## Tests
|
||||
In case users need to use functionalities not wrapped yet by `uvw` or if they
|
||||
want to get the underlying data structures as defined by `libuv` for some other
|
||||
reasons, almost all the classes in `uvw` give direct access to them.<br/>
|
||||
Please, note that this functions should not be used directly unless users know
|
||||
exactly what they are doing and what are the risks. Going raw is dangerous,
|
||||
mainly because the lifetime management of a loop, a handle or a request is
|
||||
completely controlled by the library and working around it could quickly break
|
||||
things.
|
||||
|
||||
To compile and run the tests, `uvw` requires *libuv* and *googletest*.<br/>
|
||||
`cmake` will download and compile both the libraries before to compile anything else.
|
||||
That being said, _going raw_ is a matter of using the `raw` member functions:
|
||||
|
||||
To build the tests:
|
||||
```cpp
|
||||
auto loop = uvw::loop::get_default();
|
||||
auto tcp = loop->resource<uvw::tcp_handle>();
|
||||
|
||||
* `$ cd build`
|
||||
* `$ cmake ..`
|
||||
* `$ make`
|
||||
* `$ make test`
|
||||
uv_loop_t *raw = loop->raw();
|
||||
uv_tcp_t *handle = tcp->raw();
|
||||
```
|
||||
|
||||
Go the raw way at your own risk, but do not expect any support in case of bugs.
|
||||
|
||||
|
||||
# Related projects
|
||||
|
||||
Interested in additional tools and libraries that build upon `uvw`? You might
|
||||
find the following useful then:
|
||||
|
||||
- [`uvw_net`](https://github.com/mincequi/uvw_net): a networking library with a
|
||||
collection of clients (HTTP/Modbus/SunSpec) that also includes discovery
|
||||
impementations like dns-sd/mdns.
|
||||
|
||||
Feel free to add your tool to the list if you like.
|
||||
|
||||
# Contributors
|
||||
|
||||
If you want to contribute, please send patches as pull requests against the branch master.<br/>
|
||||
Check the [contributors list](https://github.com/skypjack/uvw/blob/master/AUTHORS) to see who has partecipated so far.
|
||||
|
||||
# Projects that use `uvw`
|
||||
|
||||
Below an incomplete list of projects that use `uvw`:
|
||||
|
||||
* Internal tools (not publicly available) at [Cynny SpA](https://www.morphcast.com/) and [Cynny Space](http://www.cynnyspace.com/).
|
||||
* [Calaos.fr](https://www.calaos.fr/en/) (Open source home automation) on [GitHub](https://github.com/calaos).
|
||||
|
||||
If you know of other projects that use `libuv` through `uvw`, feel free to open a PR and I'll be glad to add them to the list.
|
||||
If you want to contribute, please send patches as pull requests against the
|
||||
branch master.<br/>
|
||||
Check the
|
||||
[contributors list](https://github.com/skypjack/uvw/blob/master/AUTHORS) to see
|
||||
who has partecipated so far.
|
||||
|
||||
# License
|
||||
|
||||
Code and documentation Copyright (c) 2017 Michele Caini.<br/>
|
||||
Code released under [the MIT license](https://github.com/skypjack/uvw/blob/master/LICENSE).<br/>
|
||||
Docs released under [Creative Commons](https://github.com/skypjack/uvw/blob/master/docs/LICENSE).
|
||||
Code and documentation Copyright (c) 2016-2024 Michele Caini.<br/>
|
||||
Logo Copyright (c) 2018-2021 Richard Caseres.
|
||||
|
||||
# Note
|
||||
Code and documentation released under
|
||||
[the MIT license](https://github.com/skypjack/uvw/blob/master/LICENSE).<br/>
|
||||
Logo released under
|
||||
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
The documentation is mostly inspired by the official [libuv API documentation](http://docs.libuv.org/en/v1.x/) for obvious reasons.
|
||||
# Support
|
||||
|
||||
# Donation
|
||||
|
||||
Developing and maintaining `uvw` takes some time and lots of coffee. It still lacks a proper test suite, documentation is partially incomplete and not all functionalities have been fully implemented yet.<br/>
|
||||
If you want to support this project, you can offer me an espresso. I'm from Italy, we're used to turning the best coffee ever in code.<br/>
|
||||
Take a look at the donation button at the top of the page for more details or just click [here](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=W2HF9FESD5LJY&lc=IT&item_name=Michele%20Caini¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted).
|
||||
If you want to support this project, you can
|
||||
[offer me](https://github.com/users/skypjack/sponsorship) an espresso.<br/>
|
||||
If you find that it's not enough, feel free to
|
||||
[help me](https://www.paypal.me/skypjack) the way you prefer.
|
||||
|
||||
5
TODO
Normal file
5
TODO
Normal file
@ -0,0 +1,5 @@
|
||||
* do not send error events when the return value is enough (still wip)
|
||||
* also cleanup error event mentions in the doc
|
||||
* Make all tests pass on all platforms
|
||||
* add iwyu and clean up everything
|
||||
* Allocator support
|
||||
22
appveyor.yml
22
appveyor.yml
@ -1,22 +0,0 @@
|
||||
# can use variables like {build} and {branch}
|
||||
version: 1.0.{build}
|
||||
|
||||
image: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
BUILD_DIR: "%APPVEYOR_BUILD_FOLDER%\\build"
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
before_build:
|
||||
- cd %BUILD_DIR%
|
||||
- cmake .. -G"Visual Studio 14 2015"
|
||||
|
||||
build:
|
||||
parallel: true
|
||||
project: build/uvw.sln
|
||||
verbosity: minimal
|
||||
@ -1,19 +0,0 @@
|
||||
project(googletest-download NONE)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
DOWNLOAD_DIR ${GOOGLETEST_DEPS_DIR}
|
||||
TMP_DIR ${GOOGLETEST_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${GOOGLETEST_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${GOOGLETEST_DEPS_DIR}/src
|
||||
BINARY_DIR ${GOOGLETEST_DEPS_DIR}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@ -1,36 +0,0 @@
|
||||
project(libuv-download NONE)
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
if(WIN32)
|
||||
ExternalProject_Add(
|
||||
libuv
|
||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||
GIT_TAG v1.12.0
|
||||
DOWNLOAD_DIR ${LIBUV_DEPS_DIR}
|
||||
TMP_DIR ${LIBUV_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${LIBUV_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${LIBUV_DEPS_DIR}/src
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND <SOURCE_DIR>/vcbuild.bat release x86 shared
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
else(WIN32)
|
||||
ExternalProject_Add(
|
||||
libuv
|
||||
GIT_REPOSITORY https://github.com/libuv/libuv.git
|
||||
GIT_TAG v1.12.0
|
||||
DOWNLOAD_DIR ${LIBUV_DEPS_DIR}
|
||||
TMP_DIR ${LIBUV_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${LIBUV_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${LIBUV_DEPS_DIR}/src
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND sh <SOURCE_DIR>/autogen.sh && ./configure
|
||||
BUILD_COMMAND make -j4
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
endif(WIN32)
|
||||
@ -1,32 +0,0 @@
|
||||
# FindLibRt
|
||||
# --------
|
||||
#
|
||||
# Find the native realtime includes and library.
|
||||
#
|
||||
# Result Variables
|
||||
# ^^^^^^^^^^^^^^^^
|
||||
#
|
||||
# This module defines the following variables:
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# LIBRT_INCLUDE_DIRS - where to find time.h, etc.
|
||||
# LIBRT_LIBRARIES - List of libraries when using librt.
|
||||
# LIBRT_FOUND - True if realtime library found.
|
||||
#
|
||||
# Hints
|
||||
# ^^^^^
|
||||
#
|
||||
# A user may set ``LIBRT_ROOT`` to a realtime installation root to tell this
|
||||
# module where to look.
|
||||
|
||||
find_path(
|
||||
LIBRT_INCLUDE_DIRS
|
||||
NAMES time.h
|
||||
PATHS ${LIBRT_ROOT}/include/
|
||||
)
|
||||
|
||||
find_library(LIBRT_LIBRARIES rt)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LibRt DEFAULT_MSG LIBRT_LIBRARIES LIBRT_INCLUDE_DIRS)
|
||||
mark_as_advanced(LIBRT_INCLUDE_DIRS LIBRT_LIBRARIES)
|
||||
23
conanfile.py
Normal file
23
conanfile.py
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from conans import ConanFile
|
||||
|
||||
class UVWConan(ConanFile):
|
||||
name = "uvw"
|
||||
description = "Header-only, event based, tiny and easy to use libuv wrapper in modern C++"
|
||||
homepage = "https://github.com/skypjack/uvw"
|
||||
url = homepage
|
||||
license = "MIT"
|
||||
topics = ("conan", "uvw", "libuv", "header-only", "wrapper", "event-loop")
|
||||
author = "Michele Caini <michele.caini@gmail.com>"
|
||||
exports = "LICENSE"
|
||||
exports_sources = "src/*"
|
||||
no_copy_source = True
|
||||
requires = "libuv/1.49.0@bincrafters/stable"
|
||||
|
||||
def package(self):
|
||||
self.copy(pattern="LICENSE", dst="licenses")
|
||||
self.copy(pattern="*.hpp", dst="include", src="src")
|
||||
|
||||
def package_id(self):
|
||||
self.info.header_only()
|
||||
@ -2,25 +2,22 @@
|
||||
# Doxygen configuration (documentation)
|
||||
#
|
||||
|
||||
set(TARGET_DOCS docs)
|
||||
|
||||
set(DOXY_IN_FILE doxy.in)
|
||||
|
||||
set(DOXY_SOURCE_DIRECTORY ${PROJECT_SRC_DIR})
|
||||
set(DOXY_DEPS_DIRECTORY ${uvw_SOURCE_DIR}/deps)
|
||||
set(DOXY_SOURCE_DIRECTORY ${uvw_SOURCE_DIR}/src)
|
||||
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(DOXY_CFG_FILE doxy.cfg)
|
||||
|
||||
configure_file(${DOXY_IN_FILE} ${DOXY_CFG_FILE} @ONLY)
|
||||
configure_file(doxy.in doxy.cfg @ONLY)
|
||||
|
||||
add_custom_target(
|
||||
${TARGET_DOCS}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/${DOXY_CFG_FILE}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
docs ALL
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
|
||||
WORKING_DIRECTORY ${uvw_SOURCE_DIR}
|
||||
VERBATIM
|
||||
SOURCES ${DOXY_IN_FILE}
|
||||
SOURCES doxy.in
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html
|
||||
DESTINATION ${PROJECT_SHARE_OUTPUT_DIRECTORY}/${PROJECT_NAME}-${PROJECT_VERSION}/
|
||||
DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/
|
||||
)
|
||||
|
||||
395
docs/LICENSE
395
docs/LICENSE
@ -1,395 +0,0 @@
|
||||
Attribution 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution 4.0 International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution 4.0 International Public License ("Public License"). To the
|
||||
extent this Public License may be interpreted as a contract, You are
|
||||
granted the Licensed Rights in consideration of Your acceptance of
|
||||
these terms and conditions, and the Licensor grants You such rights in
|
||||
consideration of benefits the Licensor receives from making the
|
||||
Licensed Material available under these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
d. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
f. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
g. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
4. If You Share Adapted Material You produce, the Adapter's
|
||||
License You apply must not prevent recipients of the Adapted
|
||||
Material from complying with this Public License.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
||||
1065
docs/doxy.in
1065
docs/doxy.in
File diff suppressed because it is too large
Load Diff
5
docs/extra.dox
Normal file
5
docs/extra.dox
Normal file
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @namespace uvw
|
||||
*
|
||||
* @brief `uvw` default namespace.
|
||||
*/
|
||||
54
meson.build
Normal file
54
meson.build
Normal file
@ -0,0 +1,54 @@
|
||||
project(
|
||||
'uvw',
|
||||
'cpp',
|
||||
version: '3.3.0',
|
||||
license: 'MIT',
|
||||
default_options: ['cpp_std=c++17'],
|
||||
)
|
||||
|
||||
libuv_dep = dependency('libuv', version: '1.48.0', required: true)
|
||||
|
||||
sources = [
|
||||
'src/uvw/async.cpp',
|
||||
'src/uvw/check.cpp',
|
||||
'src/uvw/dns.cpp',
|
||||
'src/uvw/emitter.cpp',
|
||||
'src/uvw/fs.cpp',
|
||||
'src/uvw/fs_event.cpp',
|
||||
'src/uvw/fs_poll.cpp',
|
||||
'src/uvw/idle.cpp',
|
||||
'src/uvw/lib.cpp',
|
||||
'src/uvw/loop.cpp',
|
||||
'src/uvw/pipe.cpp',
|
||||
'src/uvw/poll.cpp',
|
||||
'src/uvw/prepare.cpp',
|
||||
'src/uvw/process.cpp',
|
||||
'src/uvw/signal.cpp',
|
||||
'src/uvw/stream.cpp',
|
||||
'src/uvw/tcp.cpp',
|
||||
'src/uvw/thread.cpp',
|
||||
'src/uvw/timer.cpp',
|
||||
'src/uvw/tty.cpp',
|
||||
'src/uvw/udp.cpp',
|
||||
'src/uvw/util.cpp',
|
||||
'src/uvw/work.cpp',
|
||||
]
|
||||
|
||||
uvw_lib = library(
|
||||
'uvw',
|
||||
sources,
|
||||
include_directories: 'src',
|
||||
dependencies: [libuv_dep],
|
||||
cpp_args: ['-DUVW_AS_LIB'],
|
||||
install: true,
|
||||
)
|
||||
|
||||
uvw_dep = declare_dependency(
|
||||
include_directories: ['src'],
|
||||
dependencies: [libuv_dep],
|
||||
link_with: [uvw_lib],
|
||||
)
|
||||
|
||||
if meson.version().version_compare('>=0.54.0')
|
||||
meson.override_dependency('uvw', uvw_dep)
|
||||
endif
|
||||
82
src/CMakeLists.txt
Normal file
82
src/CMakeLists.txt
Normal file
@ -0,0 +1,82 @@
|
||||
#
|
||||
# Setup libraries
|
||||
#
|
||||
|
||||
function(add_uvw_library LIB_NAME)
|
||||
target_sources(
|
||||
${LIB_NAME}
|
||||
PRIVATE
|
||||
uvw/async.cpp
|
||||
uvw/check.cpp
|
||||
uvw/dns.cpp
|
||||
uvw/emitter.cpp
|
||||
uvw/fs.cpp
|
||||
uvw/fs_event.cpp
|
||||
uvw/fs_poll.cpp
|
||||
uvw/idle.cpp
|
||||
uvw/lib.cpp
|
||||
uvw/loop.cpp
|
||||
uvw/pipe.cpp
|
||||
uvw/poll.cpp
|
||||
uvw/prepare.cpp
|
||||
uvw/process.cpp
|
||||
uvw/signal.cpp
|
||||
uvw/stream.cpp
|
||||
uvw/tcp.cpp
|
||||
uvw/thread.cpp
|
||||
uvw/timer.cpp
|
||||
uvw/tty.cpp
|
||||
uvw/udp.cpp
|
||||
uvw/util.cpp
|
||||
uvw/work.cpp
|
||||
)
|
||||
|
||||
set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
target_compile_definitions(${LIB_NAME} PUBLIC UVW_AS_LIB)
|
||||
target_compile_features(${LIB_NAME} PUBLIC cxx_std_17)
|
||||
|
||||
target_include_directories(
|
||||
${LIB_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
if(UVW_USE_ASAN)
|
||||
target_compile_options(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||
target_link_libraries(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=address>)
|
||||
endif()
|
||||
|
||||
if(UVW_USE_UBSAN)
|
||||
target_compile_options(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer>)
|
||||
target_link_libraries(${LIB_NAME} PUBLIC $<$<CONFIG:Debug>:-fsanitize=undefined>)
|
||||
endif()
|
||||
|
||||
if(UVW_HAS_LIBCPP)
|
||||
target_compile_options(${LIB_NAME} BEFORE PUBLIC -stdlib=libc++)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
#
|
||||
# Build and install libraries
|
||||
#
|
||||
|
||||
if (UVW_BUILD_SHARED_LIB)
|
||||
add_library(uvw SHARED)
|
||||
add_library(uvw::uvw-shared ALIAS uvw)
|
||||
# If libuv is not fetched by ourselves, it's the caller's responsibility to make sure of the linkage.
|
||||
if(UVW_FETCH_LIBUV OR libuv_FOUND)
|
||||
target_link_libraries(uvw PUBLIC uv::uv-shared)
|
||||
endif()
|
||||
else()
|
||||
add_library(uvw STATIC)
|
||||
add_library(uvw::uvw-static ALIAS uvw)
|
||||
# If libuv is not fetched by ourselves, it's the caller's responsibility to make sure of the linkage.
|
||||
if(UVW_FETCH_LIBUV OR libuv_FOUND)
|
||||
target_link_libraries(uvw PUBLIC uv::uv-static)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(uvw::uvw ALIAS uvw)
|
||||
set_target_properties(uvw PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||
add_uvw_library(uvw)
|
||||
49
src/uvw.hpp
49
src/uvw.hpp
@ -1,21 +1,28 @@
|
||||
#include "uvw/async.hpp"
|
||||
#include "uvw/check.hpp"
|
||||
#include "uvw/dns.hpp"
|
||||
#include "uvw/fs.hpp"
|
||||
#include "uvw/fs_event.hpp"
|
||||
#include "uvw/fs_poll.hpp"
|
||||
#include "uvw/idle.hpp"
|
||||
#include "uvw/lib.hpp"
|
||||
#include "uvw/loop.hpp"
|
||||
#include "uvw/pipe.hpp"
|
||||
#include "uvw/poll.hpp"
|
||||
#include "uvw/prepare.hpp"
|
||||
#include "uvw/process.hpp"
|
||||
#include "uvw/signal.hpp"
|
||||
#include "uvw/tcp.hpp"
|
||||
#include "uvw/thread.hpp"
|
||||
#include "uvw/timer.hpp"
|
||||
#include "uvw/tty.hpp"
|
||||
#include "uvw/udp.hpp"
|
||||
#include "uvw/util.hpp"
|
||||
#include "uvw/work.hpp"
|
||||
#include "uvw/async.h"
|
||||
#include "uvw/check.h"
|
||||
#include "uvw/config.h"
|
||||
#include "uvw/dns.h"
|
||||
#include "uvw/emitter.h"
|
||||
#include "uvw/enum.hpp"
|
||||
#include "uvw/fs.h"
|
||||
#include "uvw/fs_event.h"
|
||||
#include "uvw/fs_poll.h"
|
||||
#include "uvw/handle.hpp"
|
||||
#include "uvw/idle.h"
|
||||
#include "uvw/lib.h"
|
||||
#include "uvw/loop.h"
|
||||
#include "uvw/pipe.h"
|
||||
#include "uvw/poll.h"
|
||||
#include "uvw/prepare.h"
|
||||
#include "uvw/process.h"
|
||||
#include "uvw/request.hpp"
|
||||
#include "uvw/resource.hpp"
|
||||
#include "uvw/signal.h"
|
||||
#include "uvw/tcp.h"
|
||||
#include "uvw/thread.h"
|
||||
#include "uvw/timer.h"
|
||||
#include "uvw/tty.h"
|
||||
#include "uvw/udp.h"
|
||||
#include "uvw/util.h"
|
||||
#include "uvw/uv_type.hpp"
|
||||
#include "uvw/work.h"
|
||||
|
||||
2
src/uvw/async.cpp
Normal file
2
src/uvw/async.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "async.h"
|
||||
#include "async.ipp"
|
||||
58
src/uvw/async.h
Normal file
58
src/uvw/async.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef UVW_ASYNC_INCLUDE_H
|
||||
#define UVW_ASYNC_INCLUDE_H
|
||||
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief Async event. */
|
||||
struct async_event {};
|
||||
|
||||
/**
|
||||
* @brief The async handle.
|
||||
*
|
||||
* Async handles allow the user to _wakeup_ the event loop and get an event
|
||||
* emitted from another thread.
|
||||
*
|
||||
* To create an `async_handle` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class async_handle final: public handle<async_handle, uv_async_t, async_event> {
|
||||
static void send_callback(uv_async_t *hndl);
|
||||
|
||||
public:
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
*
|
||||
* Unlike other handle initialization functions, it immediately starts the
|
||||
* handle.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Wakeups the event loop and emits the async event.
|
||||
*
|
||||
* It’s safe to call this function from any thread.<br/>
|
||||
* An async event is emitted on the loop thread.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send)
|
||||
* for further details.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int send();
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "async.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_ASYNC_INCLUDE_H
|
||||
@ -1,67 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief AsyncEvent event.
|
||||
*
|
||||
* It will be emitted by AsyncHandle according with its functionalities.
|
||||
*/
|
||||
struct AsyncEvent {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The AsyncHandle handle.
|
||||
*
|
||||
* Async handles allow the user to _wakeup_ the event loop and get an event
|
||||
* emitted from another thread.
|
||||
*
|
||||
* To create an `AsyncHandle` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
class AsyncHandle final: public Handle<AsyncHandle, uv_async_t> {
|
||||
static void sendCallback(uv_async_t *handle) {
|
||||
AsyncHandle &async = *(static_cast<AsyncHandle*>(handle->data));
|
||||
async.publish(AsyncEvent{});
|
||||
}
|
||||
|
||||
public:
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
*
|
||||
* Unlike other handle initialization functions, it immediately starts the
|
||||
* handle.
|
||||
*
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_async_init, &sendCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wakeups the event loop and emits the AsyncEvent event.
|
||||
*
|
||||
* It’s safe to call this function from any thread.<br/>
|
||||
* An AsyncEvent event will be emitted on the loop thread.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send)
|
||||
* for further details.
|
||||
*/
|
||||
void send() {
|
||||
invoke(&uv_async_send, get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
18
src/uvw/async.ipp
Normal file
18
src/uvw/async.ipp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE void async_handle::send_callback(uv_async_t *hndl) {
|
||||
async_handle &async = *(static_cast<async_handle *>(hndl->data));
|
||||
async.publish(async_event{});
|
||||
}
|
||||
|
||||
UVW_INLINE int async_handle::init() {
|
||||
return leak_if(uv_async_init(parent().raw(), raw(), &send_callback));
|
||||
}
|
||||
|
||||
UVW_INLINE int async_handle::send() {
|
||||
return uv_async_send(raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/check.cpp
Normal file
2
src/uvw/check.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "check.h"
|
||||
#include "check.ipp"
|
||||
56
src/uvw/check.h
Normal file
56
src/uvw/check.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef UVW_CHECK_INCLUDE_H
|
||||
#define UVW_CHECK_INCLUDE_H
|
||||
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief Check event. */
|
||||
struct check_event {};
|
||||
|
||||
/**
|
||||
* @brief The check handle.
|
||||
*
|
||||
* Check handles will emit a check event once per loop iteration, right after
|
||||
* polling for I/O.
|
||||
*
|
||||
* To create a `check_handle` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class check_handle final: public handle<check_handle, uv_check_t, check_event> {
|
||||
static void start_callback(uv_check_t *hndl);
|
||||
|
||||
public:
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* A check event will be emitted once per loop iteration, right after
|
||||
* polling for I/O.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start();
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "check.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_CHECK_INCLUDE_H
|
||||
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief CheckEvent event.
|
||||
*
|
||||
* It will be emitted by CheckHandle according with its functionalities.
|
||||
*
|
||||
* To create a `CheckHandle` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
struct CheckEvent {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The CheckHandle handle.
|
||||
*
|
||||
* Check handles will emit a CheckEvent event once per loop iteration, right
|
||||
* after polling for I/O.
|
||||
*/
|
||||
class CheckHandle final: public Handle<CheckHandle, uv_check_t> {
|
||||
static void startCallback(uv_check_t *handle) {
|
||||
CheckHandle &check = *(static_cast<CheckHandle*>(handle->data));
|
||||
check.publish(CheckEvent{});
|
||||
}
|
||||
|
||||
public:
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_check_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* A CheckEvent event will be emitted once per loop iteration, right after
|
||||
* polling for I/O.
|
||||
*/
|
||||
void start() {
|
||||
invoke(&uv_check_start, get(), &startCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_check_stop, get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
22
src/uvw/check.ipp
Normal file
22
src/uvw/check.ipp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE void check_handle::start_callback(uv_check_t *hndl) {
|
||||
check_handle &check = *(static_cast<check_handle *>(hndl->data));
|
||||
check.publish(check_event{});
|
||||
}
|
||||
|
||||
UVW_INLINE int check_handle::init() {
|
||||
return leak_if(uv_check_init(parent().raw(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE int check_handle::start() {
|
||||
return uv_check_start(raw(), &start_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE int check_handle::stop() {
|
||||
return uv_check_stop(raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
10
src/uvw/config.h
Normal file
10
src/uvw/config.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef UVW_CONFIG_H
|
||||
#define UVW_CONFIG_H
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# define UVW_INLINE inline
|
||||
#else
|
||||
# define UVW_INLINE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2
src/uvw/dns.cpp
Normal file
2
src/uvw/dns.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "dns.h"
|
||||
#include "dns.ipp"
|
||||
226
src/uvw/dns.h
Normal file
226
src/uvw/dns.h
Normal file
@ -0,0 +1,226 @@
|
||||
#ifndef UVW_DNS_INCLUDE_H
|
||||
#define UVW_DNS_INCLUDE_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <uv.h>
|
||||
#include "loop.h"
|
||||
#include "request.hpp"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief The addrinfo event. */
|
||||
struct addr_info_event {
|
||||
using deleter = void (*)(addrinfo *);
|
||||
|
||||
addr_info_event(std::unique_ptr<addrinfo, deleter> addr);
|
||||
|
||||
/**
|
||||
* @brief An initialized instance of `addrinfo`.
|
||||
*
|
||||
* See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further
|
||||
* details.
|
||||
*/
|
||||
std::unique_ptr<addrinfo, deleter> data;
|
||||
};
|
||||
|
||||
/*! @brief The nameinfo event. */
|
||||
struct name_info_event {
|
||||
name_info_event(const char *host, const char *serv);
|
||||
|
||||
/**
|
||||
* @brief A valid hostname.
|
||||
*
|
||||
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
||||
* details.
|
||||
*/
|
||||
const char *hostname;
|
||||
|
||||
/**
|
||||
* @brief A valid service name.
|
||||
*
|
||||
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
||||
* details.
|
||||
*/
|
||||
const char *service;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The getaddrinfo request.
|
||||
*
|
||||
* Wrapper for [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).<br/>
|
||||
* It offers either asynchronous and synchronous access methods.
|
||||
*
|
||||
* To create a `get_addr_info_req` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class get_addr_info_req final: public request<get_addr_info_req, uv_getaddrinfo_t, addr_info_event> {
|
||||
static void addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res);
|
||||
int node_addr_info(const char *node, const char *service, addrinfo *hints = nullptr);
|
||||
auto node_addr_info_sync(const char *node, const char *service, addrinfo *hints = nullptr);
|
||||
|
||||
public:
|
||||
using deleter = void (*)(addrinfo *);
|
||||
|
||||
using request::request;
|
||||
|
||||
/**
|
||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int node_addr_info(const std::string &node, addrinfo *hints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
*
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
|
||||
*/
|
||||
std::pair<bool, std::unique_ptr<addrinfo, deleter>> node_addr_info_sync(const std::string &node, addrinfo *hints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int service_addr_info(const std::string &service, addrinfo *hints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
*
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
|
||||
*/
|
||||
std::pair<bool, std::unique_ptr<addrinfo, deleter>> service_addr_info_sync(const std::string &service, addrinfo *hints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int addr_info(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
*
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::unique_ptr<addrinfo, deleter>` containing the data requested.
|
||||
*/
|
||||
std::pair<bool, std::unique_ptr<addrinfo, deleter>> addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints = nullptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The getnameinfo request.
|
||||
*
|
||||
* Wrapper for [getnameinfo](http://linux.die.net/man/3/getnameinfo).<br/>
|
||||
* It offers either asynchronous and synchronous access methods.
|
||||
*
|
||||
* To create a `get_name_info_req` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class get_name_info_req final: public request<get_name_info_req, uv_getnameinfo_t, name_info_event> {
|
||||
static void name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service);
|
||||
|
||||
public:
|
||||
using request::request;
|
||||
|
||||
/**
|
||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int name_info(const sockaddr &addr, int flags = 0);
|
||||
|
||||
/**
|
||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
* @param ip A valid IP address.
|
||||
* @param port A valid port number.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int name_info(const std::string &ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
* @param addr A valid instance of socket_address.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int name_info(const socket_address &addr, int flags = 0);
|
||||
|
||||
/**
|
||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
*
|
||||
* @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::pair` composed as it follows:
|
||||
* * A `const char *` containing a valid hostname.
|
||||
* * A `const char *` containing a valid service name.
|
||||
*/
|
||||
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const sockaddr &addr, int flags = 0);
|
||||
|
||||
/**
|
||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
*
|
||||
* @param ip A valid IP address.
|
||||
* @param port A valid port number.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::pair` composed as it follows:
|
||||
* * A `const char *` containing a valid hostname.
|
||||
* * A `const char *` containing a valid service name.
|
||||
*/
|
||||
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const std::string &ip, unsigned int port, int flags = 0);
|
||||
|
||||
/**
|
||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
*
|
||||
* @param addr A valid instance of socket_address.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::pair` composed as it follows:
|
||||
* * A `const char *` containing a valid hostname.
|
||||
* * A `const char *` containing a valid service name.
|
||||
*/
|
||||
std::pair<bool, std::pair<const char *, const char *>> name_info_sync(const socket_address &addr, int flags = 0);
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "dns.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_DNS_INCLUDE_H
|
||||
272
src/uvw/dns.hpp
272
src/uvw/dns.hpp
@ -1,272 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <uv.h>
|
||||
#include "request.hpp"
|
||||
#include "util.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief AddrInfoEvent event.
|
||||
*
|
||||
* It will be emitted by GetAddrInfoReq according with its functionalities.
|
||||
*/
|
||||
struct AddrInfoEvent {
|
||||
using Deleter = void(*)(addrinfo *);
|
||||
|
||||
AddrInfoEvent(std::unique_ptr<addrinfo, Deleter> addr)
|
||||
: data{std::move(addr)}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief An initialized instance of `addrinfo`.
|
||||
*
|
||||
* See [getaddrinfo](http://linux.die.net/man/3/getaddrinfo) for further
|
||||
* details.
|
||||
*/
|
||||
std::unique_ptr<addrinfo, Deleter> data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief NameInfoEvent event.
|
||||
*
|
||||
* It will be emitted by GetNameInfoReq according with its functionalities.
|
||||
*/
|
||||
struct NameInfoEvent {
|
||||
NameInfoEvent(const char *host, const char *serv)
|
||||
: hostname{host}, service{serv}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief A valid hostname.
|
||||
*
|
||||
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
||||
* details.
|
||||
*/
|
||||
const char * hostname;
|
||||
|
||||
/**
|
||||
* @brief A valid service name.
|
||||
*
|
||||
* See [getnameinfo](http://linux.die.net/man/3/getnameinfo) for further
|
||||
* details.
|
||||
*/
|
||||
const char * service;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The GetAddrInfoReq request.
|
||||
*
|
||||
* Wrapper for [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).<br/>
|
||||
* It offers either asynchronous and synchronous access methods.
|
||||
*
|
||||
* To create a `GetAddrInfoReq` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
class GetAddrInfoReq final: public Request<GetAddrInfoReq, uv_getaddrinfo_t> {
|
||||
static void addrInfoCallback(uv_getaddrinfo_t *req, int status, addrinfo *res) {
|
||||
auto ptr = reserve(req);
|
||||
|
||||
if(status) {
|
||||
ptr->publish(ErrorEvent{status});
|
||||
} else {
|
||||
auto data = std::unique_ptr<addrinfo, void(*)(addrinfo *)>{
|
||||
res, [](addrinfo *addr){ uv_freeaddrinfo(addr); }};
|
||||
|
||||
ptr->publish(AddrInfoEvent{std::move(data)});
|
||||
}
|
||||
}
|
||||
|
||||
void nodeAddrInfo(const char *node, const char *service, addrinfo *hints = nullptr) {
|
||||
invoke(&uv_getaddrinfo, parent(), get(), &addrInfoCallback, node, service, hints);
|
||||
}
|
||||
|
||||
auto nodeAddrInfoSync(const char *node, const char *service, addrinfo *hints = nullptr) {
|
||||
auto req = get();
|
||||
auto err = uv_getaddrinfo(parent(), req, nullptr, node, service, hints);
|
||||
auto data = std::unique_ptr<addrinfo, void(*)(addrinfo *)>{req->addrinfo, [](addrinfo *addr){ uv_freeaddrinfo(addr); }};
|
||||
return std::make_pair(!err, std::move(data));
|
||||
}
|
||||
|
||||
public:
|
||||
using Deleter = void(*)(addrinfo *);
|
||||
|
||||
using Request::Request;
|
||||
|
||||
/**
|
||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
void nodeAddrInfo(std::string node, addrinfo *hints = nullptr) {
|
||||
nodeAddrInfo(node.data(), nullptr, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
*
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested.
|
||||
*/
|
||||
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
||||
nodeAddrInfoSync(std::string node, addrinfo *hints = nullptr) {
|
||||
return nodeAddrInfoSync(node.data(), nullptr, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
void serviceAddrInfo(std::string service, addrinfo *hints = nullptr) {
|
||||
nodeAddrInfo(nullptr, service.data(), hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
*
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested.
|
||||
*/
|
||||
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
||||
serviceAddrInfoSync(std::string service, addrinfo *hints = nullptr) {
|
||||
return nodeAddrInfoSync(nullptr, service.data(), hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Async [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*/
|
||||
void addrInfo(std::string node, std::string service, addrinfo *hints = nullptr) {
|
||||
nodeAddrInfo(node.data(), service.data(), hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sync [getaddrinfo](http://linux.die.net/man/3/getaddrinfo).
|
||||
*
|
||||
* @param node Either a numerical network address or a network hostname.
|
||||
* @param service Either a service name or a port number as a string.
|
||||
* @param hints Optional `addrinfo` data structure with additional address
|
||||
* type constraints.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::unique_ptr<addrinfo, Deleter>` containing the data requested.
|
||||
*/
|
||||
std::pair<bool, std::unique_ptr<addrinfo, Deleter>>
|
||||
addrInfoSync(std::string node, std::string service, addrinfo *hints = nullptr) {
|
||||
return nodeAddrInfoSync(node.data(), service.data(), hints);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The GetNameInfoReq request.
|
||||
*
|
||||
* Wrapper for [getnameinfo](http://linux.die.net/man/3/getnameinfo).<br/>
|
||||
* It offers either asynchronous and synchronous access methods.
|
||||
*
|
||||
* To create a `GetNameInfoReq` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
class GetNameInfoReq final: public Request<GetNameInfoReq, uv_getnameinfo_t> {
|
||||
static void nameInfoCallback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) {
|
||||
auto ptr = reserve(req);
|
||||
if(status) { ptr->publish(ErrorEvent{status}); }
|
||||
else { ptr->publish(NameInfoEvent{hostname, service}); }
|
||||
}
|
||||
|
||||
public:
|
||||
using Request::Request;
|
||||
|
||||
/**
|
||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
* @param ip A valid IP address.
|
||||
* @param port A valid port number.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
template<typename I = IPv4>
|
||||
void nameInfo(std::string ip, unsigned int port, int flags = 0) {
|
||||
typename details::IpTraits<I>::Type addr;
|
||||
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
|
||||
auto saddr = reinterpret_cast<const sockaddr *>(&addr);
|
||||
invoke(&uv_getnameinfo, parent(), get(), &nameInfoCallback, saddr, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Async [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
* @param addr A valid instance of Addr.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*/
|
||||
template<typename I = IPv4>
|
||||
void nameInfo(Addr addr, int flags = 0) {
|
||||
nameInfo<I>(addr.ip, addr.port, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
*
|
||||
* @param ip A valid IP address.
|
||||
* @param port A valid port number.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::pair` composed as it follows:
|
||||
* * A `const char *` containing a valid hostname.
|
||||
* * A `const char *` containing a valid service name.
|
||||
*/
|
||||
template<typename I = IPv4>
|
||||
std::pair<bool, std::pair<const char *, const char *>>
|
||||
nameInfoSync(std::string ip, unsigned int port, int flags = 0) {
|
||||
typename details::IpTraits<I>::Type addr;
|
||||
details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
|
||||
auto req = get();
|
||||
auto saddr = reinterpret_cast<const sockaddr *>(&addr);
|
||||
auto err = uv_getnameinfo(parent(), req, nullptr, saddr, flags);
|
||||
return std::make_pair(!err, std::make_pair(req->host, req->service));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sync [getnameinfo](http://linux.die.net/man/3/getnameinfo).
|
||||
*
|
||||
* @param addr A valid instance of Addr.
|
||||
* @param flags Optional flags that modify the behavior of `getnameinfo`.
|
||||
*
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of success, false otherwise.
|
||||
* * A `std::pair` composed as it follows:
|
||||
* * A `const char *` containing a valid hostname.
|
||||
* * A `const char *` containing a valid service name.
|
||||
*/
|
||||
template<typename I = IPv4>
|
||||
std::pair<bool, std::pair<const char *, const char *>>
|
||||
nameInfoSync(Addr addr, int flags = 0) {
|
||||
return nameInfoSync<I>(addr.ip, addr.port, flags);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
89
src/uvw/dns.ipp
Normal file
89
src/uvw/dns.ipp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE addr_info_event::addr_info_event(std::unique_ptr<addrinfo, deleter> addr)
|
||||
: data{std::move(addr)} {}
|
||||
|
||||
UVW_INLINE name_info_event::name_info_event(const char *host, const char *serv)
|
||||
: hostname{host}, service{serv} {}
|
||||
|
||||
UVW_INLINE void get_addr_info_req::addr_info_callback(uv_getaddrinfo_t *req, int status, addrinfo *res) {
|
||||
if(auto ptr = reserve(req); status) {
|
||||
ptr->publish(error_event{status});
|
||||
} else {
|
||||
auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{res, [](addrinfo *addr) { uv_freeaddrinfo(addr); }};
|
||||
ptr->publish(addr_info_event{std::move(data)});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int get_addr_info_req::node_addr_info(const char *node, const char *service, addrinfo *hints) {
|
||||
return this->leak_if(uv_getaddrinfo(parent().raw(), raw(), &addr_info_callback, node, service, hints));
|
||||
}
|
||||
|
||||
UVW_INLINE auto get_addr_info_req::node_addr_info_sync(const char *node, const char *service, addrinfo *hints) {
|
||||
auto req = raw();
|
||||
auto err = uv_getaddrinfo(parent().raw(), req, nullptr, node, service, hints);
|
||||
auto data = std::unique_ptr<addrinfo, void (*)(addrinfo *)>{req->addrinfo, [](addrinfo *addr) { uv_freeaddrinfo(addr); }};
|
||||
return std::make_pair(!err, std::move(data));
|
||||
}
|
||||
|
||||
UVW_INLINE int get_addr_info_req::node_addr_info(const std::string &node, addrinfo *hints) {
|
||||
return node_addr_info(node.data(), nullptr, hints);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::node_addr_info_sync(const std::string &node, addrinfo *hints) {
|
||||
return node_addr_info_sync(node.data(), nullptr, hints);
|
||||
}
|
||||
|
||||
UVW_INLINE int get_addr_info_req::service_addr_info(const std::string &service, addrinfo *hints) {
|
||||
return node_addr_info(nullptr, service.data(), hints);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::service_addr_info_sync(const std::string &service, addrinfo *hints) {
|
||||
return node_addr_info_sync(nullptr, service.data(), hints);
|
||||
}
|
||||
|
||||
UVW_INLINE int get_addr_info_req::addr_info(const std::string &node, const std::string &service, addrinfo *hints) {
|
||||
return node_addr_info(node.data(), service.data(), hints);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::unique_ptr<addrinfo, get_addr_info_req::deleter>> get_addr_info_req::addr_info_sync(const std::string &node, const std::string &service, addrinfo *hints) {
|
||||
return node_addr_info_sync(node.data(), service.data(), hints);
|
||||
}
|
||||
|
||||
UVW_INLINE void get_name_info_req::name_info_callback(uv_getnameinfo_t *req, int status, const char *hostname, const char *service) {
|
||||
if(auto ptr = reserve(req); status) {
|
||||
ptr->publish(error_event{status});
|
||||
} else {
|
||||
ptr->publish(name_info_event{hostname, service});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int get_name_info_req::name_info(const sockaddr &addr, int flags) {
|
||||
return this->leak_if(uv_getnameinfo(parent().raw(), raw(), &name_info_callback, &addr, flags));
|
||||
}
|
||||
|
||||
UVW_INLINE int get_name_info_req::name_info(const std::string &ip, unsigned int port, int flags) {
|
||||
return name_info(details::ip_addr(ip.data(), port), flags);
|
||||
}
|
||||
|
||||
UVW_INLINE int get_name_info_req::name_info(const socket_address &addr, int flags) {
|
||||
return name_info(addr.ip, addr.port, flags);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const sockaddr &addr, int flags) {
|
||||
auto req = raw();
|
||||
auto err = uv_getnameinfo(parent().raw(), req, nullptr, &addr, flags);
|
||||
return std::make_pair(!err, std::make_pair(req->host, req->service));
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const std::string &ip, unsigned int port, int flags) {
|
||||
return name_info_sync(details::ip_addr(ip.data(), port), flags);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<const char *, const char *>> get_name_info_req::name_info_sync(const socket_address &addr, int flags) {
|
||||
return name_info_sync(addr.ip, addr.port, flags);
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/emitter.cpp
Normal file
2
src/uvw/emitter.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "emitter.h"
|
||||
#include "emitter.ipp"
|
||||
159
src/uvw/emitter.h
Normal file
159
src/uvw/emitter.h
Normal file
@ -0,0 +1,159 @@
|
||||
#ifndef UVW_EMITTER_INCLUDE_H
|
||||
#define UVW_EMITTER_INCLUDE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/**
|
||||
* @brief Error event.
|
||||
*
|
||||
* Custom wrapper around error constants of `libuv`.
|
||||
*/
|
||||
struct error_event {
|
||||
template<typename Type, typename = std::enable_if_t<std::is_integral_v<Type>>>
|
||||
explicit error_event(Type val) noexcept
|
||||
: ec{static_cast<int>(val)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the `libuv` error code equivalent to the given platform dependent error code.
|
||||
*
|
||||
* It returns:
|
||||
* * POSIX error codes on Unix (the ones stored in errno).
|
||||
* * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()).
|
||||
*
|
||||
* If `sys` is already a `libuv` error code, it is simply returned.
|
||||
*
|
||||
* @param sys A platform dependent error code.
|
||||
* @return The `libuv` error code equivalent to the given platform dependent error code.
|
||||
*/
|
||||
[[nodiscard]] static int translate(int sys) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Returns the error message for the given error code.
|
||||
*
|
||||
* Leaks a few bytes of memory when you call it with an unknown error code.
|
||||
*
|
||||
* @return The error message for the given error code.
|
||||
*/
|
||||
[[nodiscard]] const char *what() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Returns the error name for the given error code.
|
||||
*
|
||||
* Leaks a few bytes of memory when you call it with an unknown error code.
|
||||
*
|
||||
* @return The error name for the given error code.
|
||||
*/
|
||||
[[nodiscard]] const char *name() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying error code, that is an error constant of `libuv`.
|
||||
* @return The underlying error code.
|
||||
*/
|
||||
[[nodiscard]] int code() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Checks if the event contains a valid error code.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
private:
|
||||
int ec;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event emitter base class.
|
||||
*
|
||||
* Almost everything in `uvw` is an event emitter.<br/>
|
||||
* This is the base class from which resources and loops inherit.
|
||||
*/
|
||||
template<typename Elem, typename... Event>
|
||||
class emitter {
|
||||
public:
|
||||
template<typename Type>
|
||||
using listener_t = std::function<void(Type &, Elem &)>;
|
||||
|
||||
private:
|
||||
template<typename Type>
|
||||
[[nodiscard]] const auto &handler() const noexcept {
|
||||
return std::get<listener_t<Type>>(handlers);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] auto &handler() noexcept {
|
||||
return std::get<listener_t<Type>>(handlers);
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename Type>
|
||||
void publish(Type event) {
|
||||
if(auto &listener = handler<Type>(); listener) {
|
||||
listener(event, *static_cast<Elem *>(this));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~emitter() noexcept {
|
||||
static_assert(std::is_base_of_v<emitter<Elem, Event...>, Elem>);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers a long-lived listener with the event emitter.
|
||||
*
|
||||
* This method is used to register a listener with the emitter.<br/>
|
||||
* A listener is usually defined as a callable object assignable to a
|
||||
* `std::function<void(const Event &, Elem &)`, where `Event` is the type of
|
||||
* the event and `Elem` is the type of the resource.
|
||||
*
|
||||
* @param f A valid listener to be registered.
|
||||
*/
|
||||
template<typename Type>
|
||||
void on(listener_t<Type> f) {
|
||||
handler<Type>() = std::move(f);
|
||||
}
|
||||
|
||||
/*! @brief Disconnects the listener for the given event type. */
|
||||
template<typename Type>
|
||||
void reset() noexcept {
|
||||
handler<Type>() = nullptr;
|
||||
}
|
||||
|
||||
/*! @brief Disconnects all listeners. */
|
||||
void reset() noexcept {
|
||||
reset<error_event>();
|
||||
(reset<Event>(), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if there is a listener registered for the specific event.
|
||||
* @return True if there is a listener registered for the specific event,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] bool has() const noexcept {
|
||||
return static_cast<bool>(handler<Type>());
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<listener_t<error_event>, listener_t<Event>...> handlers{};
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "emitter.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_EMITTER_INCLUDE_H
|
||||
@ -1,318 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief The ErrorEvent event.
|
||||
*
|
||||
* Custom wrapper around error constants of `libuv`.
|
||||
*/
|
||||
struct ErrorEvent {
|
||||
template<typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
|
||||
explicit ErrorEvent(U val) noexcept
|
||||
: ec{static_cast<int>(val)}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Returns the `libuv` error code equivalent to the given platform dependent error code.
|
||||
*
|
||||
* It returns:
|
||||
* * POSIX error codes on Unix (the ones stored in errno).
|
||||
* * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()).
|
||||
*
|
||||
* If `sys` is already a `libuv` error code, it is simply returned.
|
||||
*
|
||||
* @param sys A platform dependent error code.
|
||||
* @return The `libuv` error code equivalent to the given platform dependent error code.
|
||||
*/
|
||||
static int translate(int sys) noexcept {
|
||||
return uv_translate_sys_error(sys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the error message for the given error code.
|
||||
*
|
||||
* Leaks a few bytes of memory when you call it with an unknown error code.
|
||||
*
|
||||
* @return The error message for the given error code.
|
||||
*/
|
||||
const char * what() const noexcept { return uv_strerror(ec); }
|
||||
|
||||
/**
|
||||
* @brief Returns the error name for the given error code.
|
||||
*
|
||||
* Leaks a few bytes of memory when you call it with an unknown error code.
|
||||
*
|
||||
* @return The error name for the given error code.
|
||||
*/
|
||||
const char * name() const noexcept { return uv_err_name(ec); }
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying error code, that is an error constant of `libuv`.
|
||||
* @return The underlying error code.
|
||||
*/
|
||||
int code() const noexcept { return ec; }
|
||||
|
||||
/**
|
||||
* @brief Checks if the event contains a valid error code.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const noexcept { return ec < 0; }
|
||||
|
||||
private:
|
||||
const int ec;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Event emitter base class.
|
||||
*
|
||||
* Almost everything in `uvw` is an event emitter.<br/>
|
||||
* This is the base class from which resources and loops inherit.
|
||||
*/
|
||||
template<typename T>
|
||||
class Emitter {
|
||||
struct BaseHandler {
|
||||
virtual ~BaseHandler() noexcept = default;
|
||||
virtual bool empty() const noexcept = 0;
|
||||
virtual void clear() noexcept = 0;
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
struct Handler final: BaseHandler {
|
||||
using Listener = std::function<void(E &, T &)>;
|
||||
using Element = std::pair<bool, Listener>;
|
||||
using ListenerList = std::list<Element>;
|
||||
using Connection = typename ListenerList::iterator;
|
||||
|
||||
bool empty() const noexcept override {
|
||||
auto pred = [](auto &&element){ return element.first; };
|
||||
|
||||
return std::all_of(onceL.cbegin(), onceL.cend(), pred) &&
|
||||
std::all_of(onL.cbegin(), onL.cend(), pred);
|
||||
}
|
||||
|
||||
void clear() noexcept override {
|
||||
if(publishing) {
|
||||
auto func = [](auto &&element){ element.first = true; };
|
||||
std::for_each(onceL.begin(), onceL.end(), func);
|
||||
std::for_each(onL.begin(), onL.end(), func);
|
||||
} else {
|
||||
onceL.clear();
|
||||
onL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Connection once(Listener f) {
|
||||
return onceL.emplace(onceL.cend(), false, std::move(f));
|
||||
}
|
||||
|
||||
Connection on(Listener f) {
|
||||
return onL.emplace(onL.cend(), false, std::move(f));
|
||||
}
|
||||
|
||||
void erase(Connection conn) noexcept {
|
||||
conn->first = true;
|
||||
|
||||
if(!publishing) {
|
||||
auto pred = [](auto &&element){ return element.first; };
|
||||
onceL.remove_if(pred);
|
||||
onL.remove_if(pred);
|
||||
}
|
||||
}
|
||||
|
||||
void publish(E event, T &ref) {
|
||||
ListenerList currentL;
|
||||
onceL.swap(currentL);
|
||||
|
||||
auto func = [&event, &ref](auto &&element) {
|
||||
return element.first ? void() : element.second(event, ref);
|
||||
};
|
||||
|
||||
publishing = true;
|
||||
|
||||
std::for_each(onL.rbegin(), onL.rend(), func);
|
||||
std::for_each(currentL.rbegin(), currentL.rend(), func);
|
||||
|
||||
publishing = false;
|
||||
|
||||
onL.remove_if([](auto &&element){ return element.first; });
|
||||
}
|
||||
|
||||
private:
|
||||
bool publishing{false};
|
||||
ListenerList onceL{};
|
||||
ListenerList onL{};
|
||||
};
|
||||
|
||||
static std::size_t next_type() noexcept {
|
||||
static std::size_t counter = 0;
|
||||
return counter++;
|
||||
}
|
||||
|
||||
template<typename>
|
||||
static std::size_t event_type() noexcept {
|
||||
static std::size_t value = next_type();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
Handler<E> & handler() noexcept {
|
||||
std::size_t type = event_type<E>();
|
||||
|
||||
if(!(type < handlers.size())) {
|
||||
handlers.resize(type+1);
|
||||
}
|
||||
|
||||
if(!handlers[type]) {
|
||||
handlers[type] = std::make_unique<Handler<E>>();
|
||||
}
|
||||
|
||||
return static_cast<Handler<E>&>(*handlers[type]);
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename E>
|
||||
void publish(E event) {
|
||||
handler<E>().publish(std::move(event), *static_cast<T*>(this));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename E>
|
||||
using Listener = typename Handler<E>::Listener;
|
||||
|
||||
/**
|
||||
* @brief Connection type for a given event type.
|
||||
*
|
||||
* Given an event type `E`, `Connection<E>` is the type of the connection
|
||||
* object returned by the event emitter whenever a listener for the given
|
||||
* type is registered.
|
||||
*/
|
||||
template<typename E>
|
||||
struct Connection: private Handler<E>::Connection {
|
||||
template<typename> friend class Emitter;
|
||||
|
||||
Connection() = default;
|
||||
Connection(const Connection &) = default;
|
||||
Connection(Connection &&) = default;
|
||||
|
||||
Connection(typename Handler<E>::Connection conn)
|
||||
: Handler<E>::Connection{std::move(conn)}
|
||||
{}
|
||||
|
||||
Connection & operator=(const Connection &) = default;
|
||||
Connection & operator=(Connection &&) = default;
|
||||
};
|
||||
|
||||
virtual ~Emitter() noexcept {
|
||||
static_assert(std::is_base_of<Emitter<T>, T>::value, "!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers a long-lived listener with the event emitter.
|
||||
*
|
||||
* This method can be used to register a listener that is meant to be
|
||||
* invoked more than once for the given event type.<br/>
|
||||
* The Connection object returned by the method can be freely discarded. It
|
||||
* can be used later to disconnect the listener, if needed.
|
||||
*
|
||||
* Listener is usually defined as a callable object assignable to a
|
||||
* `std::function<void(const E &, T &)`, where `E` is the type of the event
|
||||
* and `T` is the type of the resource.
|
||||
*
|
||||
* @param f A valid listener to be registered.
|
||||
* @return Connection object to be used later to disconnect the listener.
|
||||
*/
|
||||
template<typename E>
|
||||
Connection<E> on(Listener<E> f) {
|
||||
return handler<E>().on(std::move(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers a short-lived listener with the event emitter.
|
||||
*
|
||||
* This method can be used to register a listener that is meant to be
|
||||
* invoked only once for the given event type.<br/>
|
||||
* The Connection object returned by the method can be freely discarded. It
|
||||
* can be used later to disconnect the listener, if needed.
|
||||
*
|
||||
* Listener is usually defined as a callable object assignable to a
|
||||
* `std::function<void(const E &, T &)`, where `E` is the type of the event
|
||||
* and `T` is the type of the resource.
|
||||
*
|
||||
* @param f Avalid listener to be registered.
|
||||
* @return Connection object to be used later to disconnect the listener.
|
||||
*/
|
||||
template<typename E>
|
||||
Connection<E> once(Listener<E> f) {
|
||||
return handler<E>().once(std::move(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects a listener from the event emitter.
|
||||
* @param conn A valid Connection object
|
||||
*/
|
||||
template<typename E>
|
||||
void erase(Connection<E> conn) noexcept {
|
||||
handler<E>().erase(std::move(conn));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects all the listeners for the given event type.
|
||||
*/
|
||||
template<typename E>
|
||||
void clear() noexcept {
|
||||
handler<E>().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnects all the listeners.
|
||||
*/
|
||||
void clear() noexcept {
|
||||
std::for_each(handlers.begin(), handlers.end(),
|
||||
[](auto &&hdlr){ if(hdlr) { hdlr->clear(); } });
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if there are listeners registered for the specific event.
|
||||
* @return True if there are no listeners registered for the specific event,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename E>
|
||||
bool empty() const noexcept {
|
||||
std::size_t type = event_type<E>();
|
||||
|
||||
return (!(type < handlers.size()) ||
|
||||
!handlers[type] ||
|
||||
static_cast<Handler<E>&>(*handlers[type]).empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if there are listeners registered with the event emitter.
|
||||
* @return True if there are no listeners registered with the event emitter,
|
||||
* false otherwise.
|
||||
*/
|
||||
bool empty() const noexcept {
|
||||
return std::all_of(handlers.cbegin(), handlers.cend(),
|
||||
[](auto &&hdlr){ return !hdlr || hdlr->empty(); });
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<BaseHandler>> handlers{};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
25
src/uvw/emitter.ipp
Normal file
25
src/uvw/emitter.ipp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE int error_event::translate(int sys) noexcept {
|
||||
return uv_translate_sys_error(sys);
|
||||
}
|
||||
|
||||
UVW_INLINE const char *error_event::what() const noexcept {
|
||||
return uv_strerror(ec);
|
||||
}
|
||||
|
||||
UVW_INLINE const char *error_event::name() const noexcept {
|
||||
return uv_err_name(ec);
|
||||
}
|
||||
|
||||
UVW_INLINE int error_event::code() const noexcept {
|
||||
return ec;
|
||||
}
|
||||
|
||||
UVW_INLINE error_event::operator bool() const noexcept {
|
||||
return ec < 0;
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
76
src/uvw/enum.hpp
Normal file
76
src/uvw/enum.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef UVW_ENUM_INCLUDE_HPP
|
||||
#define UVW_ENUM_INCLUDE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param lhs The first value to use.
|
||||
* @param rhs The second value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* two values provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||
operator|(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||
operator&(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||
operator^(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param value The value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* value provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM)>
|
||||
operator~(const Type value) noexcept {
|
||||
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
|
||||
}
|
||||
|
||||
/*! @copydoc operator~ */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM, bool{})>
|
||||
operator!(const Type value) noexcept {
|
||||
return !static_cast<std::underlying_type_t<Type>>(value);
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM) &>
|
||||
operator|=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs | rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM) &>
|
||||
operator&=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs & rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Type>, decltype(Type::UVW_ENUM) &>
|
||||
operator^=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs ^ rhs));
|
||||
}
|
||||
|
||||
#endif
|
||||
2
src/uvw/fs.cpp
Normal file
2
src/uvw/fs.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "fs.h"
|
||||
#include "fs.ipp"
|
||||
1235
src/uvw/fs.h
Normal file
1235
src/uvw/fs.h
Normal file
File diff suppressed because it is too large
Load Diff
1212
src/uvw/fs.hpp
1212
src/uvw/fs.hpp
File diff suppressed because it is too large
Load Diff
550
src/uvw/fs.ipp
Normal file
550
src/uvw/fs.ipp
Normal file
@ -0,0 +1,550 @@
|
||||
#include <array>
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE void file_req::fs_open_callback(uv_fs_t *req) {
|
||||
if(auto ptr = reserve(req); req->result < 0) {
|
||||
ptr->publish(error_event{req->result});
|
||||
} else {
|
||||
ptr->file = static_cast<uv_file>(req->result);
|
||||
ptr->publish(fs_event{*req});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::fs_close_callback(uv_fs_t *req) {
|
||||
if(auto ptr = reserve(req); req->result < 0) {
|
||||
ptr->publish(error_event{req->result});
|
||||
} else {
|
||||
ptr->file = BAD_FD;
|
||||
ptr->publish(fs_event{*req});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::fs_read_callback(uv_fs_t *req) {
|
||||
if(auto ptr = reserve(req); req->result < 0) {
|
||||
ptr->publish(error_event{req->result});
|
||||
} else {
|
||||
ptr->publish(fs_event{*req, std::move(ptr->current)});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE file_req::~file_req() noexcept {
|
||||
uv_fs_req_cleanup(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::close() {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_close(parent().raw(), raw(), file, &fs_close_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::close_sync() {
|
||||
auto req = raw();
|
||||
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_close(parent().raw(), req, file, nullptr);
|
||||
|
||||
if(req->result >= 0) {
|
||||
file = BAD_FD;
|
||||
}
|
||||
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::open(const std::string &path, file_open_flags flags, int mode) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_open(parent().raw(), raw(), path.data(), static_cast<int>(flags), mode, &fs_open_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::open_sync(const std::string &path, file_open_flags flags, int mode) {
|
||||
auto req = raw();
|
||||
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_open(parent().raw(), req, path.data(), static_cast<int>(flags), mode, nullptr);
|
||||
|
||||
if(req->result >= 0) {
|
||||
file = static_cast<uv_file>(req->result);
|
||||
}
|
||||
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::read(int64_t offset, unsigned int len) {
|
||||
current = std::make_unique<char[]>(len);
|
||||
buffer = uv_buf_init(current.get(), len);
|
||||
std::array bufs{buffer};
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_read(parent().raw(), raw(), file, bufs.data(), 1, offset, &fs_read_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<std::unique_ptr<const char[]>, std::size_t>> file_req::read_sync(int64_t offset, unsigned int len) {
|
||||
current = std::make_unique<char[]>(len);
|
||||
buffer = uv_buf_init(current.get(), len);
|
||||
std::array bufs{buffer};
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_read(parent().raw(), req, file, bufs.data(), 1, offset, nullptr);
|
||||
bool err = req->result < 0;
|
||||
return std::make_pair(!err, std::make_pair(std::move(current), err ? 0 : std::size_t(req->result)));
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::write(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
|
||||
current = std::move(buf);
|
||||
std::array bufs{uv_buf_init(current.get(), len)};
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_write(parent().raw(), raw(), file, bufs.data(), 1, offset, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::write(char *buf, unsigned int len, int64_t offset) {
|
||||
std::array bufs{uv_buf_init(buf, len)};
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_write(parent().raw(), raw(), file, bufs.data(), 1, offset, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::size_t> file_req::write_sync(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
|
||||
current = std::move(buf);
|
||||
std::array bufs{uv_buf_init(current.get(), len)};
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_write(parent().raw(), req, file, bufs.data(), 1, offset, nullptr);
|
||||
bool err = req->result < 0;
|
||||
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::stat() {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fstat(parent().raw(), raw(), file, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, file_info> file_req::stat_sync() {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fstat(parent().raw(), req, file, nullptr);
|
||||
return std::make_pair(!(req->result < 0), req->statbuf);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::sync() {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fsync(parent().raw(), raw(), file, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::sync_sync() {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fsync(parent().raw(), req, file, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::datasync() {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fdatasync(parent().raw(), raw(), file, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::datasync_sync() {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fdatasync(parent().raw(), req, file, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::truncate(int64_t offset) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_ftruncate(parent().raw(), raw(), file, offset, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::truncate_sync(int64_t offset) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_ftruncate(parent().raw(), req, file, offset, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::sendfile(file_handle out, int64_t offset, std::size_t length) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_sendfile(parent().raw(), raw(), out, file, offset, length, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::size_t> file_req::sendfile_sync(file_handle out, int64_t offset, std::size_t length) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_sendfile(parent().raw(), req, out, file, offset, length, nullptr);
|
||||
bool err = req->result < 0;
|
||||
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::chmod(int mode) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fchmod(parent().raw(), raw(), file, mode, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::chmod_sync(int mode) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fchmod(parent().raw(), req, file, mode, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::futime(fs_request::time atime, fs_request::time mtime) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_futime(parent().raw(), raw(), file, atime.count(), mtime.count(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::futime_sync(fs_request::time atime, fs_request::time mtime) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_futime(parent().raw(), req, file, atime.count(), mtime.count(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void file_req::chown(uid_type uid, gid_type gid) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fchown(parent().raw(), raw(), file, uid, gid, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool file_req::chown_sync(uid_type uid, gid_type gid) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_fchown(parent().raw(), req, file, uid, gid, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE file_req::operator file_handle() const noexcept {
|
||||
return file;
|
||||
}
|
||||
|
||||
UVW_INLINE fs_req::~fs_req() noexcept {
|
||||
uv_fs_req_cleanup(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::unlink(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_unlink(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::unlink_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_unlink(parent().raw(), req, path.data(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::mkdir(const std::string &path, int mode) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_mkdir(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::mkdir_sync(const std::string &path, int mode) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_mkdir(parent().raw(), req, path.data(), mode, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::mkdtemp(const std::string &tpl) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_mkdtemp(parent().raw(), raw(), tpl.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, const char *> fs_req::mkdtemp_sync(const std::string &tpl) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_mkdtemp(parent().raw(), req, tpl.data(), nullptr);
|
||||
return std::make_pair(!(req->result < 0), req->path);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::mkstemp(const std::string &tpl) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_mkstemp(parent().raw(), raw(), tpl.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<std::string, std::size_t>> fs_req::mkstemp_sync(const std::string &tpl) {
|
||||
std::pair<bool, std::pair<std::string, std::size_t>> ret{false, {}};
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_mkstemp(parent().raw(), req, tpl.data(), nullptr);
|
||||
ret.first = !(req->result < 0);
|
||||
|
||||
if(ret.first) {
|
||||
ret.second.first = req->path;
|
||||
ret.second.second = static_cast<std::size_t>(req->result);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::lutime(const std::string &path, time atime, time mtime) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_lutime(parent().raw(), raw(), path.data(), atime.count(), mtime.count(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::lutime_sync(const std::string &path, time atime, time mtime) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_lutime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::rmdir(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_rmdir(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::rmdir_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_rmdir(parent().raw(), req, path.data(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::scandir(const std::string &path, int flags) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_scandir(parent().raw(), raw(), path.data(), flags, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::size_t> fs_req::scandir_sync(const std::string &path, int flags) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_scandir(parent().raw(), req, path.data(), flags, nullptr);
|
||||
bool err = req->result < 0;
|
||||
return std::make_pair(!err, err ? 0 : std::size_t(req->result));
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::scandir_next() {
|
||||
std::pair<bool, std::pair<entry_type, const char *>> ret{false, {entry_type::UNKNOWN, nullptr}};
|
||||
|
||||
uv_fs_req_cleanup(raw());
|
||||
auto res = uv_fs_scandir_next(raw(), &dirents);
|
||||
|
||||
if(UV_EOF != res) {
|
||||
ret.second.first = static_cast<entry_type>(dirents.type);
|
||||
ret.second.second = dirents.name;
|
||||
ret.first = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::stat(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_stat(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, file_info> fs_req::stat_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_stat(parent().raw(), req, path.data(), nullptr);
|
||||
return std::make_pair(!(req->result < 0), req->statbuf);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::lstat(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_lstat(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, file_info> fs_req::lstat_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_lstat(parent().raw(), req, path.data(), nullptr);
|
||||
return std::make_pair(!(req->result < 0), req->statbuf);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::statfs(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_statfs(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, fs_info> fs_req::statfs_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_statfs(parent().raw(), req, path.data(), nullptr);
|
||||
return std::make_pair(!(req->result < 0), *static_cast<uv_statfs_t *>(req->ptr));
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::rename(const std::string &old, const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_rename(parent().raw(), raw(), old.data(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::rename_sync(const std::string &old, const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_rename(parent().raw(), req, old.data(), path.data(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::copyfile(const std::string &old, const std::string &path, copy_file_flags flags) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_copyfile(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::copyfile_sync(const std::string &old, const std::string &path, copy_file_flags flags) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_copyfile(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::access(const std::string &path, int mode) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_access(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::access_sync(const std::string &path, int mode) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_access(parent().raw(), req, path.data(), mode, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::chmod(const std::string &path, int mode) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_chmod(parent().raw(), raw(), path.data(), mode, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::chmod_sync(const std::string &path, int mode) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_chmod(parent().raw(), req, path.data(), mode, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::utime(const std::string &path, fs_request::time atime, fs_request::time mtime) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_utime(parent().raw(), raw(), path.data(), atime.count(), mtime.count(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::utime_sync(const std::string &path, fs_request::time atime, fs_request::time mtime) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_utime(parent().raw(), req, path.data(), atime.count(), mtime.count(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::link(const std::string &old, const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_link(parent().raw(), raw(), old.data(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::link_sync(const std::string &old, const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_link(parent().raw(), req, old.data(), path.data(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::symlink(const std::string &old, const std::string &path, symlink_flags flags) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_symlink(parent().raw(), raw(), old.data(), path.data(), static_cast<int>(flags), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::symlink_sync(const std::string &old, const std::string &path, symlink_flags flags) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_symlink(parent().raw(), req, old.data(), path.data(), static_cast<int>(flags), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::readlink(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_readlink(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<const char *, std::size_t>> fs_req::readlink_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_readlink(parent().raw(), req, path.data(), nullptr);
|
||||
bool err = req->result < 0;
|
||||
return std::make_pair(!err, std::make_pair(static_cast<char *>(req->ptr), err ? 0 : std::size_t(req->result)));
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::realpath(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_realpath(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, const char *> fs_req::realpath_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_realpath(parent().raw(), req, path.data(), nullptr);
|
||||
return std::make_pair(!(req->result < 0), req->path);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::chown(const std::string &path, uid_type uid, gid_type gid) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_chown(parent().raw(), raw(), path.data(), uid, gid, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::chown_sync(const std::string &path, uid_type uid, gid_type gid) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_chown(parent().raw(), req, path.data(), uid, gid, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::lchown(const std::string &path, uid_type uid, gid_type gid) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_lchown(parent().raw(), raw(), path.data(), uid, gid, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::lchown_sync(const std::string &path, uid_type uid, gid_type gid) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_lchown(parent().raw(), req, path.data(), uid, gid, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::opendir(const std::string &path) {
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_opendir(parent().raw(), raw(), path.data(), &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::opendir_sync(const std::string &path) {
|
||||
auto req = raw();
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_opendir(parent().raw(), req, path.data(), nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::closedir() {
|
||||
auto req = raw();
|
||||
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_closedir(parent().raw(), req, dir, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE bool fs_req::closedir_sync() {
|
||||
auto req = raw();
|
||||
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_closedir(parent().raw(), req, dir, nullptr);
|
||||
return !(req->result < 0);
|
||||
}
|
||||
|
||||
UVW_INLINE void fs_req::readdir() {
|
||||
auto req = raw();
|
||||
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||
dir->dirents = &dirents;
|
||||
dir->nentries = 1;
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_readdir(parent().raw(), req, dir, &fs_request_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, std::pair<fs_req::entry_type, const char *>> fs_req::readdir_sync() {
|
||||
auto req = raw();
|
||||
auto *dir = static_cast<uv_dir_t *>(req->ptr);
|
||||
dir->dirents = &dirents;
|
||||
dir->nentries = 1;
|
||||
uv_fs_req_cleanup(this->raw());
|
||||
uv_fs_readdir(parent().raw(), req, dir, nullptr);
|
||||
return {req->result != 0, {static_cast<entry_type>(dirents.type), dirents.name}};
|
||||
}
|
||||
|
||||
UVW_INLINE os_file_descriptor fs_helper::handle(file_handle file) noexcept {
|
||||
return uv_get_osfhandle(file);
|
||||
}
|
||||
|
||||
UVW_INLINE file_handle fs_helper::open(os_file_descriptor descriptor) noexcept {
|
||||
return uv_open_osfhandle(descriptor);
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/fs_event.cpp
Normal file
2
src/uvw/fs_event.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "fs_event.h"
|
||||
#include "fs_event.ipp"
|
||||
120
src/uvw/fs_event.h
Normal file
120
src/uvw/fs_event.h
Normal file
@ -0,0 +1,120 @@
|
||||
#ifndef UVW_FS_EVENT_INCLUDE_H
|
||||
#define UVW_FS_EVENT_INCLUDE_H
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "enum.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
namespace details {
|
||||
|
||||
enum class uvw_fs_event_flags : std::underlying_type_t<uv_fs_event_flags> {
|
||||
WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY,
|
||||
STAT = UV_FS_EVENT_STAT,
|
||||
RECURSIVE = UV_FS_EVENT_RECURSIVE,
|
||||
UVW_ENUM = 0
|
||||
};
|
||||
|
||||
enum class uvw_fs_event : std::underlying_type_t<uv_fs_event> {
|
||||
RENAME = UV_RENAME,
|
||||
CHANGE = UV_CHANGE
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
/*! @brief Fs event event. */
|
||||
struct fs_event_event {
|
||||
fs_event_event(const char *pathname, details::uvw_fs_event events);
|
||||
|
||||
/**
|
||||
* @brief The path to the file being monitored.
|
||||
*
|
||||
* If the handle was started with a directory, the filename parameter will
|
||||
* be a relative path to a file contained in the directory.
|
||||
*/
|
||||
const char *filename;
|
||||
|
||||
/**
|
||||
* @brief Detected events all in one.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `fs_event_handle::watch::RENAME`
|
||||
* * `fs_event_handle::watch::CHANGE`
|
||||
*/
|
||||
details::uvw_fs_event flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The fs event handle.
|
||||
*
|
||||
* These handles allow the user to monitor a given path for changes, for
|
||||
* example, if the file was renamed or there was a generic change in it. The
|
||||
* best backend for the job on each platform is chosen by the handle.
|
||||
*
|
||||
* To create a `fs_event_handle` through a `loop`, no arguments are required.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
|
||||
* for further details.
|
||||
*/
|
||||
class fs_event_handle final: public handle<fs_event_handle, uv_fs_event_t, fs_event_event> {
|
||||
static void start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status);
|
||||
|
||||
public:
|
||||
using watch = details::uvw_fs_event;
|
||||
using event_flags = details::uvw_fs_event_flags;
|
||||
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts watching the specified path.
|
||||
*
|
||||
* It will watch the specified path for changes.<br/>
|
||||
* As soon as a change is observed, a fs_event_event is emitted by the
|
||||
* handle.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `fs_event_handle::event_flags::WATCH_ENTRY`
|
||||
* * `fs_event_handle::event_flags::STAT`
|
||||
* * `fs_event_handle::event_flags::RECURSIVE`
|
||||
*
|
||||
* @param path The file or directory to be monitored.
|
||||
* @param flags Additional flags to control the behavior.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start(const std::string &path, event_flags flags = event_flags::UVW_ENUM);
|
||||
|
||||
/**
|
||||
* @brief Stops polling the file descriptor.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
|
||||
/**
|
||||
* @brief Gets the path being monitored.
|
||||
* @return The path being monitored, an empty string in case of errors.
|
||||
*/
|
||||
std::string path() noexcept;
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "fs_event.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_FS_EVENT_INCLUDE_H
|
||||
@ -1,158 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "util.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
|
||||
enum class UVFsEventFlags: std::underlying_type_t<uv_fs_event_flags> {
|
||||
WATCH_ENTRY = UV_FS_EVENT_WATCH_ENTRY,
|
||||
STAT = UV_FS_EVENT_STAT,
|
||||
RECURSIVE = UV_FS_EVENT_RECURSIVE
|
||||
};
|
||||
|
||||
|
||||
enum class UVFsEvent: std::underlying_type_t<uv_fs_event> {
|
||||
RENAME = UV_RENAME,
|
||||
CHANGE = UV_CHANGE
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief FsEventEvent event.
|
||||
*
|
||||
* It will be emitted by FsEventHandle according with its functionalities.
|
||||
*/
|
||||
struct FsEventEvent {
|
||||
FsEventEvent(const char * pathname, Flags<details::UVFsEvent> events)
|
||||
: filename{pathname}, flags{std::move(events)}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief The path to the file being monitored.
|
||||
*
|
||||
* If the handle was started with a directory, the filename parameter will
|
||||
* be a relative path to a file contained in the directory.
|
||||
*/
|
||||
const char * filename;
|
||||
|
||||
/**
|
||||
* @brief Detected events all in one.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `FsEventHandle::Watch::RENAME`
|
||||
* * `FsEventHandle::Watch::CHANGE`
|
||||
*/
|
||||
Flags<details::UVFsEvent> flags;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The FsEventHandle handle.
|
||||
*
|
||||
* These handles allow the user to monitor a given path for changes, for
|
||||
* example, if the file was renamed or there was a generic change in it. The
|
||||
* best backend for the job on each platform is chosen by the handle.
|
||||
*
|
||||
* To create a `FsEventHandle` through a `Loop`, no arguments are required.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/fs_event.html)
|
||||
* for further details.
|
||||
*/
|
||||
class FsEventHandle final: public Handle<FsEventHandle, uv_fs_event_t> {
|
||||
static void startCallback(uv_fs_event_t *handle, const char *filename, int events, int status) {
|
||||
FsEventHandle &fsEvent = *(static_cast<FsEventHandle*>(handle->data));
|
||||
if(status) { fsEvent.publish(ErrorEvent{status}); }
|
||||
else { fsEvent.publish(FsEventEvent{filename, static_cast<std::underlying_type_t<Event>>(events)}); }
|
||||
}
|
||||
|
||||
public:
|
||||
using Watch = details::UVFsEvent;
|
||||
using Event = details::UVFsEventFlags;
|
||||
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_fs_event_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts watching the specified path.
|
||||
*
|
||||
* It will watch the specified path for changes.<br/>
|
||||
* As soon as a change is observed, a FsEventEvent is emitted by the
|
||||
* handle.<br>
|
||||
* It could happen that ErrorEvent events are emitted while running.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `FsEventHandle::Event::WATCH_ENTRY`
|
||||
* * `FsEventHandle::Event::STAT`
|
||||
* * `FsEventHandle::Event::RECURSIVE`
|
||||
*
|
||||
* @param path The file or directory to be monitored.
|
||||
* @param flags Additional flags to control the behavior.
|
||||
*/
|
||||
void start(std::string path, Flags<Watch> flags = Flags<Watch>{}) {
|
||||
invoke(&uv_fs_event_start, get(), &startCallback, path.data(), flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts watching the specified path.
|
||||
*
|
||||
* It will watch the specified path for changes.<br/>
|
||||
* As soon as a change is observed, a FsEventEvent is emitted by the
|
||||
* handle.<br>
|
||||
* It could happen that ErrorEvent events are emitted while running.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `FsEventHandle::Event::WATCH_ENTRY`
|
||||
* * `FsEventHandle::Event::STAT`
|
||||
* * `FsEventHandle::Event::RECURSIVE`
|
||||
*
|
||||
* @param path The file or directory to be monitored.
|
||||
* @param watch Additional flag to control the behavior.
|
||||
*/
|
||||
void start(std::string path, Watch watch) {
|
||||
start(std::move(path), Flags<Watch>{watch});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops polling the file descriptor.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_fs_event_stop, get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the path being monitored.
|
||||
* @return The path being monitored, an empty string in case of errors.
|
||||
*/
|
||||
std::string path() noexcept {
|
||||
return details::tryRead(&uv_fs_event_getpath, get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
33
src/uvw/fs_event.ipp
Normal file
33
src/uvw/fs_event.ipp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE fs_event_event::fs_event_event(const char *pathname, details::uvw_fs_event events)
|
||||
: filename{pathname}, flags{events} {}
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
UVW_INLINE void fs_event_handle::start_callback(uv_fs_event_t *hndl, const char *filename, int events, int status) {
|
||||
if(fs_event_handle &fsEvent = *(static_cast<fs_event_handle *>(hndl->data)); status) {
|
||||
fsEvent.publish(error_event{status});
|
||||
} else {
|
||||
fsEvent.publish(fs_event_event{filename, details::uvw_fs_event(events)});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int fs_event_handle::init() {
|
||||
return leak_if(uv_fs_event_init(parent().raw(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE int fs_event_handle::start(const std::string &path, event_flags flags) {
|
||||
return uv_fs_event_start(raw(), &start_callback, path.data(), static_cast<uv_fs_event_flags>(flags));
|
||||
}
|
||||
|
||||
UVW_INLINE int fs_event_handle::stop() {
|
||||
return uv_fs_event_stop(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE std::string fs_event_handle::path() noexcept {
|
||||
return details::try_read(&uv_fs_event_getpath, raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/fs_poll.cpp
Normal file
2
src/uvw/fs_poll.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "fs_poll.h"
|
||||
#include "fs_poll.ipp"
|
||||
76
src/uvw/fs_poll.h
Normal file
76
src/uvw/fs_poll.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef UVW_FS_POLL_INCLUDE_H
|
||||
#define UVW_FS_POLL_INCLUDE_H
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief Fs pos event. */
|
||||
struct fs_poll_event {
|
||||
explicit fs_poll_event(file_info previous, file_info current) noexcept;
|
||||
|
||||
file_info prev; /*!< The old file_info struct. */
|
||||
file_info curr; /*!< The new file_info struct. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The fs poll handle.
|
||||
*
|
||||
* It allows users to monitor a given path for changes. Unlike fs_event_handle,
|
||||
* fs_poll_handle uses stat to detect when a file has changed so it can work on
|
||||
* file systems where fs_event_handle handles can’t.
|
||||
*
|
||||
* To create a `fs_poll_handle` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class fs_poll_handle final: public handle<fs_poll_handle, uv_fs_poll_t, fs_poll_event> {
|
||||
static void start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr);
|
||||
|
||||
public:
|
||||
using time = std::chrono::duration<unsigned int, std::milli>;
|
||||
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* The handle will start emitting fs_poll_event when needed.
|
||||
*
|
||||
* @param file The path to the file to be checked.
|
||||
* @param interval Milliseconds between successive checks.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start(const std::string &file, time interval);
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
|
||||
/**
|
||||
* @brief Gets the path being monitored by the handle.
|
||||
* @return The path being monitored by the handle, an empty string in case
|
||||
* of errors.
|
||||
*/
|
||||
std::string path() noexcept;
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "fs_poll.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_FS_POLL_INCLUDE_H
|
||||
@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "util.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief FsPollEvent event.
|
||||
*
|
||||
* It will be emitted by FsPollHandle according with its functionalities.
|
||||
*/
|
||||
struct FsPollEvent {
|
||||
explicit FsPollEvent(Stat previous, Stat current) noexcept
|
||||
: prev{std::move(previous)}, curr{std::move(current)}
|
||||
{}
|
||||
|
||||
Stat prev; /*!< The old Stat struct. */
|
||||
Stat curr; /*!< The new Stat struct. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The FsPollHandle handle.
|
||||
*
|
||||
* It allows the user to monitor a given path for changes. Unlike FsEventHandle
|
||||
* handles, FsPollHandle handles use stat to detect when a file has changed so
|
||||
* they can work on file systems where FsEventHandle handles can’t.
|
||||
*
|
||||
* To create a `FsPollHandle` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
class FsPollHandle final: public Handle<FsPollHandle, uv_fs_poll_t> {
|
||||
static void startCallback(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr) {
|
||||
FsPollHandle &fsPoll = *(static_cast<FsPollHandle*>(handle->data));
|
||||
if(status) { fsPoll.publish(ErrorEvent{status}); }
|
||||
else { fsPoll.publish(FsPollEvent{ *prev, *curr }); }
|
||||
}
|
||||
|
||||
public:
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_fs_poll_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* The handle will start emitting FsPollEvent when needed.
|
||||
*
|
||||
* @param file The path to the file to be checked.
|
||||
* @param interval Milliseconds between successive checks.
|
||||
*/
|
||||
void start(std::string file, unsigned int interval) {
|
||||
invoke(&uv_fs_poll_start, get(), &startCallback, file.data(), interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_fs_poll_stop, get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the path being monitored by the handle.
|
||||
* @return The path being monitored by the handle, an empty string in case
|
||||
* of errors.
|
||||
*/
|
||||
std::string path() noexcept {
|
||||
return details::tryRead(&uv_fs_poll_getpath, get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
32
src/uvw/fs_poll.ipp
Normal file
32
src/uvw/fs_poll.ipp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE fs_poll_event::fs_poll_event(file_info previous, file_info current) noexcept
|
||||
: prev{previous}, curr{current} {}
|
||||
|
||||
UVW_INLINE void fs_poll_handle::start_callback(uv_fs_poll_t *hndl, int status, const uv_stat_t *prev, const uv_stat_t *curr) {
|
||||
if(fs_poll_handle &fsPoll = *(static_cast<fs_poll_handle *>(hndl->data)); status) {
|
||||
fsPoll.publish(error_event{status});
|
||||
} else {
|
||||
fsPoll.publish(fs_poll_event{*prev, *curr});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int fs_poll_handle::init() {
|
||||
return leak_if(uv_fs_poll_init(parent().raw(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE int fs_poll_handle::start(const std::string &file, fs_poll_handle::time interval) {
|
||||
return uv_fs_poll_start(raw(), &start_callback, file.data(), interval.count());
|
||||
}
|
||||
|
||||
UVW_INLINE int fs_poll_handle::stop() {
|
||||
return uv_fs_poll_stop(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE std::string fs_poll_handle::path() noexcept {
|
||||
return details::try_read(&uv_fs_poll_getpath, raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
@ -1,93 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef UVW_HANDLE_INCLUDE_H
|
||||
#define UVW_HANDLE_INCLUDE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "resource.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief CloseEvent event.
|
||||
*
|
||||
* It will be emitted by the handles according with their functionalities.
|
||||
*/
|
||||
struct CloseEvent {};
|
||||
|
||||
/*! @brief Close event. */
|
||||
struct close_event {};
|
||||
|
||||
/**
|
||||
* @brief Handle base class.
|
||||
*
|
||||
* Base type for all `uvw` handle types.
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
class Handle: public BaseHandle, public Resource<T, U>
|
||||
{
|
||||
static void closeCallback(uv_handle_t *handle) {
|
||||
Handle<T, U> &ref = *(static_cast<T*>(handle->data));
|
||||
auto ptr = ref.shared_from_this();
|
||||
(void)ptr;
|
||||
ref.reset();
|
||||
ref.publish(CloseEvent{});
|
||||
}
|
||||
|
||||
template<typename T, typename U, typename... E>
|
||||
class handle: public resource<T, U, close_event, E...> {
|
||||
protected:
|
||||
static void allocCallback(uv_handle_t *, std::size_t suggested, uv_buf_t *buf) {
|
||||
auto size = static_cast<unsigned int>(suggested);
|
||||
*buf = uv_buf_init(new char[size], size);
|
||||
static void close_callback(uv_handle_t *hndl) {
|
||||
handle<T, U, E...> &ref = *(static_cast<T *>(hndl->data));
|
||||
[[maybe_unused]] auto ptr = ref.shared_from_this();
|
||||
ref.self_reset();
|
||||
ref.publish(close_event{});
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
bool initialize(F &&f, Args&&... args) {
|
||||
if(!this->self()) {
|
||||
auto err = std::forward<F>(f)(this->parent(), this->get(), std::forward<Args>(args)...);
|
||||
|
||||
if(err) {
|
||||
this->publish(ErrorEvent{err});
|
||||
} else {
|
||||
this->leak();
|
||||
}
|
||||
}
|
||||
|
||||
return this->self();
|
||||
[[nodiscard]] uv_handle_t *as_uv_handle() {
|
||||
return reinterpret_cast<uv_handle_t *>(this->raw());
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
auto invoke(F &&f, Args&&... args) {
|
||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
||||
return err;
|
||||
[[nodiscard]] const uv_handle_t *as_uv_handle() const {
|
||||
return reinterpret_cast<const uv_handle_t *>(this->raw());
|
||||
}
|
||||
|
||||
public:
|
||||
using Resource<T, U>::Resource;
|
||||
using resource<T, U, close_event, E...>::resource;
|
||||
|
||||
/**
|
||||
* @brief Gets the category of the handle.
|
||||
*
|
||||
* A base handle offers no functionality to promote it to the actual handle
|
||||
* type. By means of this function, an opaque value that identifies the
|
||||
* category of the handle is made available to the users.
|
||||
*
|
||||
* @return The actual category of the handle.
|
||||
*/
|
||||
[[nodiscard]] handle_category category() const noexcept {
|
||||
return handle_category{as_uv_handle()->type};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the type of the handle.
|
||||
*
|
||||
* A base handle offers no functionality to promote it to the actual handle
|
||||
* type. By means of this function, the type of the underlying handle as
|
||||
* specified by handle_type is made available to the users.
|
||||
*
|
||||
* @return The actual type of the handle.
|
||||
*/
|
||||
[[nodiscard]] handle_type type() const noexcept {
|
||||
return utilities::guess_handle(category());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the handle is active.
|
||||
*
|
||||
* What _active_ means depends on the type of handle:
|
||||
*
|
||||
* * An AsyncHandle handle is always active and cannot be deactivated,
|
||||
* * An async_handle handle is always active and cannot be deactivated,
|
||||
* except by closing it with uv_close().
|
||||
* * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
|
||||
* that deals with I/O - is active when it is doing something that involves
|
||||
* I/O, like reading, writing, connecting, accepting new connections, etc.
|
||||
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
|
||||
* has been started with a call to `start()`.
|
||||
* * A pipe, tcp, udp, etc. handle - basically any handle that deals with
|
||||
* I/O - is active when it is doing something that involves I/O, like
|
||||
* reading, writing, connecting, accepting new connections, etc.
|
||||
* * A check, idle, timer, etc. handle is active when it has been started
|
||||
* with a call to `start()`.
|
||||
*
|
||||
* Rule of thumb: if a handle of type `FooHandle` has a `start()` member
|
||||
* Rule of thumb: if a handle of type `foo_handle` has a `start()` member
|
||||
* method, then it’s active from the moment that method is called. Likewise,
|
||||
* `stop()` deactivates the handle again.
|
||||
*
|
||||
* @return True if the handle is active, false otherwise.
|
||||
*/
|
||||
bool active() const noexcept override {
|
||||
return !(uv_is_active(this->template get<uv_handle_t>()) == 0);
|
||||
[[nodiscard]] bool active() const noexcept {
|
||||
return !!uv_is_active(as_uv_handle());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,22 +97,21 @@ public:
|
||||
*
|
||||
* @return True if the handle is closing or closed, false otherwise.
|
||||
*/
|
||||
bool closing() const noexcept override {
|
||||
return !(uv_is_closing(this->template get<uv_handle_t>()) == 0);
|
||||
[[nodiscard]] bool closing() const noexcept {
|
||||
return !!uv_is_closing(as_uv_handle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request handle to be closed.
|
||||
*
|
||||
* This **must** be called on each handle before memory is released.<br/>
|
||||
* In-progress requests are cancelled and this can result in an ErrorEvent
|
||||
* emitted.
|
||||
* In-progress requests are cancelled and this can result in errors.
|
||||
*
|
||||
* The handle will emit a CloseEvent when finished.
|
||||
* The handle will emit a close event when finished.
|
||||
*/
|
||||
void close() noexcept override {
|
||||
void close() noexcept {
|
||||
if(!closing()) {
|
||||
uv_close(this->template get<uv_handle_t>(), &Handle<T, U>::closeCallback);
|
||||
uv_close(as_uv_handle(), &handle<T, U, E...>::close_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,8 +121,8 @@ public:
|
||||
* References are idempotent, that is, if a handle is already referenced
|
||||
* calling this function again will have no effect.
|
||||
*/
|
||||
void reference() noexcept override {
|
||||
uv_ref(this->template get<uv_handle_t>());
|
||||
void reference() noexcept {
|
||||
uv_ref(as_uv_handle());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,24 +131,24 @@ public:
|
||||
* References are idempotent, that is, if a handle is not referenced calling
|
||||
* this function again will have no effect.
|
||||
*/
|
||||
void unreference() noexcept override {
|
||||
uv_unref(this->template get<uv_handle_t>());
|
||||
void unreference() noexcept {
|
||||
uv_unref(as_uv_handle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the given handle referenced.
|
||||
* @return True if the handle referenced, false otherwise.
|
||||
*/
|
||||
bool referenced() const noexcept override {
|
||||
return !(uv_has_ref(this->template get<uv_handle_t>()) == 0);
|
||||
[[nodiscard]] bool referenced() const noexcept {
|
||||
return !!uv_has_ref(as_uv_handle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the underlying handle type.
|
||||
* @return The size of the underlying handle type.
|
||||
*/
|
||||
std::size_t size() const noexcept {
|
||||
return uv_handle_size(this->template get<uv_handle_t>()->type);
|
||||
[[nodiscard]] std::size_t size() const noexcept {
|
||||
return uv_handle_size(as_uv_handle()->type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -158,16 +156,17 @@ public:
|
||||
*
|
||||
* Gets the size of the send buffer that the operating system uses for the
|
||||
* socket.<br/>
|
||||
* This function works for TcpHandle, PipeHandle and UDPHandle handles on
|
||||
* Unix and for TcpHandle and UDPHandle handles on Windows.<br/>
|
||||
* This function works for tcp, pipeand udp handles on Unix and for tcp and
|
||||
* udp handles on Windows.<br/>
|
||||
* Note that Linux will return double the size of the original set value.
|
||||
*
|
||||
* @return The size of the send buffer, 0 in case of errors.
|
||||
* @return The size of the send buffer, the underlying return value in case
|
||||
* of errors.
|
||||
*/
|
||||
int sendBufferSize() {
|
||||
[[nodiscard]] int send_buffer_size() {
|
||||
int value = 0;
|
||||
auto err = uv_send_buffer_size(this->template get<uv_handle_t>(), &value);
|
||||
return err ? 0 : value;
|
||||
auto err = uv_send_buffer_size(as_uv_handle(), &value);
|
||||
return err ? err : value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,14 +174,14 @@ public:
|
||||
*
|
||||
* Sets the size of the send buffer that the operating system uses for the
|
||||
* socket.<br/>
|
||||
* This function works for TcpHandle, PipeHandle and UDPHandle handles on
|
||||
* Unix and for TcpHandle and UDPHandle handles on Windows.<br/>
|
||||
* This function works for tcp, pipe and udp handles on Unix and for tcp and
|
||||
* udp handles on Windows.<br/>
|
||||
* Note that Linux will set double the size.
|
||||
*
|
||||
* @return True in case of success, false otherwise.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
bool sendBufferSize(int value) {
|
||||
return (0 == uv_send_buffer_size(this->template get<uv_handle_t>(), &value));
|
||||
[[nodiscard]] int send_buffer_size(int value) {
|
||||
return uv_send_buffer_size(as_uv_handle(), &value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,16 +189,17 @@ public:
|
||||
*
|
||||
* Gets the size of the receive buffer that the operating system uses for
|
||||
* the socket.<br/>
|
||||
* This function works for TcpHandle, PipeHandle and UDPHandle handles on
|
||||
* Unix and for TcpHandle and UDPHandle handles on Windows.<br/>
|
||||
* This function works for tcp, pipe and udp handles on Unix and for tcp and
|
||||
* udp handles on Windows.<br/>
|
||||
* Note that Linux will return double the size of the original set value.
|
||||
*
|
||||
* @return The size of the receive buffer, 0 in case of errors.
|
||||
* @return The size of the receive buffer, the underlying return value in
|
||||
* case of errors.
|
||||
*/
|
||||
int recvBufferSize() {
|
||||
[[nodiscard]] int recv_buffer_size() {
|
||||
int value = 0;
|
||||
auto err = uv_recv_buffer_size(this->template get<uv_handle_t>(), &value);
|
||||
return err ? 0 : value;
|
||||
auto err = uv_recv_buffer_size(as_uv_handle(), &value);
|
||||
return err ? err : value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,14 +207,14 @@ public:
|
||||
*
|
||||
* Sets the size of the receive buffer that the operating system uses for
|
||||
* the socket.<br/>
|
||||
* This function works for TcpHandle, PipeHandle and UDPHandle handles on
|
||||
* Unix and for TcpHandle and UDPHandle handles on Windows.<br/>
|
||||
* This function works for tcp, pipe and udp handles on Unix and for tcp and
|
||||
* udp handles on Windows.<br/>
|
||||
* Note that Linux will set double the size.
|
||||
*
|
||||
* @return True in case of success, false otherwise.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
bool recvBufferSize(int value) {
|
||||
return (0 == uv_recv_buffer_size(this->template get<uv_handle_t>(), &value));
|
||||
[[nodiscard]] int recv_buffer_size(int value) {
|
||||
return uv_recv_buffer_size(as_uv_handle(), &value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,15 +222,14 @@ public:
|
||||
*
|
||||
* Supported handles:
|
||||
*
|
||||
* * TcpHandle
|
||||
* * PipeHandle
|
||||
* * TTYHandle
|
||||
* * UDPHandle
|
||||
* * PollHandle
|
||||
* * tcp_handle
|
||||
* * pipe_handle
|
||||
* * tty_handle
|
||||
* * udp_handle
|
||||
* * poll_handle
|
||||
*
|
||||
* It will emit an ErrorEvent event if invoked on any other handle.<br/>
|
||||
* If a handle doesn’t have an attached file descriptor yet or the handle
|
||||
* itself has been closed, an ErrorEvent event will be emitted.
|
||||
* If invoked on a different handle, one that doesn’t have an attached file
|
||||
* descriptor yet or one which was closed, an invalid value is returned.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/handle.html#c.uv_fileno)
|
||||
@ -239,12 +238,13 @@ public:
|
||||
* @return The file descriptor attached to the hande or a negative value in
|
||||
* case of errors.
|
||||
*/
|
||||
OSFileDescriptor fileno() const {
|
||||
[[nodiscard]] os_file_descriptor fd() const {
|
||||
uv_os_fd_t fd;
|
||||
uv_fileno(this->template get<uv_handle_t>(), &fd);
|
||||
uv_fileno(as_uv_handle(), &fd);
|
||||
return fd;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
}
|
||||
#endif // UVW_HANDLE_INCLUDE_H
|
||||
|
||||
2
src/uvw/idle.cpp
Normal file
2
src/uvw/idle.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "idle.h"
|
||||
#include "idle.ipp"
|
||||
65
src/uvw/idle.h
Normal file
65
src/uvw/idle.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef UVW_IDLE_INCLUDE_H
|
||||
#define UVW_IDLE_INCLUDE_H
|
||||
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief Idle event. */
|
||||
struct idle_event {};
|
||||
|
||||
/**
|
||||
* @brief The idle handle.
|
||||
*
|
||||
* Idle handles will emit a idle event once per loop iteration, right before the
|
||||
* prepare handles.
|
||||
*
|
||||
* The notable difference with prepare handles is that when there are active
|
||||
* idle handles, the loop will perform a zero timeout poll instead of blocking
|
||||
* for I/O.
|
||||
*
|
||||
* @note
|
||||
* Despite the name, idle handles will emit events on every loop iteration, not
|
||||
* when the loop is actually _idle_.
|
||||
*
|
||||
* To create an `idle_handle` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class idle_handle final: public handle<idle_handle, uv_idle_t, idle_event> {
|
||||
static void start_callback(uv_idle_t *hndl);
|
||||
|
||||
public:
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* An idle event will be emitted once per loop iteration, right before
|
||||
* polling the prepare handles.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start();
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "idle.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_IDLE_INCLUDE_H
|
||||
@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief IdleEvent event.
|
||||
*
|
||||
* It will be emitted by IdleHandle according with its functionalities.
|
||||
*/
|
||||
struct IdleEvent {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The IdleHandle handle.
|
||||
*
|
||||
* Idle handles will emit a IdleEvent event once per loop iteration, right
|
||||
* before the PrepareHandle handles.
|
||||
*
|
||||
* The notable difference with prepare handles is that when there are active
|
||||
* idle handles, the loop will perform a zero timeout poll instead of blocking
|
||||
* for I/O.
|
||||
*
|
||||
* **Note**: despite the name, idle handles will emit events on every loop
|
||||
* iteration, not when the loop is actually _idle_.
|
||||
*
|
||||
* To create an `IdleHandle` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
class IdleHandle final: public Handle<IdleHandle, uv_idle_t> {
|
||||
static void startCallback(uv_idle_t *handle) {
|
||||
IdleHandle &idle = *(static_cast<IdleHandle*>(handle->data));
|
||||
idle.publish(IdleEvent{});
|
||||
}
|
||||
|
||||
public:
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_idle_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* A IdleEvent event will be emitted once per loop iteration, right before
|
||||
* polling the PrepareHandle handles.
|
||||
*/
|
||||
void start() {
|
||||
invoke(&uv_idle_start, get(), &startCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_idle_stop, get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
22
src/uvw/idle.ipp
Normal file
22
src/uvw/idle.ipp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE void idle_handle::start_callback(uv_idle_t *hndl) {
|
||||
idle_handle &idle = *(static_cast<idle_handle *>(hndl->data));
|
||||
idle.publish(idle_event{});
|
||||
}
|
||||
|
||||
UVW_INLINE int idle_handle::init() {
|
||||
return leak_if(uv_idle_init(parent().raw(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE int idle_handle::start() {
|
||||
return uv_idle_start(raw(), &start_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE int idle_handle::stop() {
|
||||
return uv_idle_stop(raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/lib.cpp
Normal file
2
src/uvw/lib.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "lib.h"
|
||||
#include "lib.ipp"
|
||||
68
src/uvw/lib.h
Normal file
68
src/uvw/lib.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef UVW_LIB_INCLUDE_H
|
||||
#define UVW_LIB_INCLUDE_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "loop.h"
|
||||
#include "uv_type.hpp"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/**
|
||||
* @brief The shared lib class.
|
||||
*
|
||||
* `uvw` provides cross platform utilities for loading shared libraries and
|
||||
* retrieving symbols from them, by means of the API offered by `libuv`.
|
||||
*/
|
||||
class shared_lib final: public uv_type<uv_lib_t> {
|
||||
public:
|
||||
explicit shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept;
|
||||
|
||||
~shared_lib() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Checks if the library has been correctly opened.
|
||||
* @return True if the library is opened, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Retrieves a data pointer from a dynamic library.
|
||||
*
|
||||
* `F` shall be a valid function type (as an example, `void(int)`).<br/>
|
||||
* It is legal for a symbol to map to `nullptr`.
|
||||
*
|
||||
* @param name The symbol to be retrieved.
|
||||
* @return A valid function pointer in case of success, `nullptr` otherwise.
|
||||
*/
|
||||
template<typename F>
|
||||
F *sym(const std::string &name) {
|
||||
static_assert(std::is_function_v<F>);
|
||||
F *func;
|
||||
auto err = uv_dlsym(raw(), name.data(), reinterpret_cast<void **>(&func));
|
||||
if(err) {
|
||||
func = nullptr;
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last error message, if any.
|
||||
* @return The last error message, if any.
|
||||
*/
|
||||
[[nodiscard]] const char *error() const noexcept;
|
||||
|
||||
private:
|
||||
bool opened;
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "lib.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_LIB_INCLUDE_H
|
||||
@ -1,94 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <uv.h>
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief The SharedLib class.
|
||||
*
|
||||
* `uvw` provides cross platform utilities for loading shared libraries and
|
||||
* retrieving symbols from them, by means of the API offered by `libuv`.
|
||||
*/
|
||||
class SharedLib final {
|
||||
explicit SharedLib(std::shared_ptr<Loop> ref, std::string filename) noexcept
|
||||
: pLoop{std::move(ref)}, lib{}
|
||||
{
|
||||
opened = (0 == uv_dlopen(filename.data(), &lib));
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a new shared library object.
|
||||
* @param loop A pointer to the loop from which the handle generated.
|
||||
* @param filename The filename of the library in UTF8.
|
||||
* @return A pointer to the newly created handle.
|
||||
*/
|
||||
static std::shared_ptr<SharedLib> create(std::shared_ptr<Loop> loop, std::string filename) noexcept {
|
||||
return std::shared_ptr<SharedLib>{new SharedLib{std::move(loop), std::move(filename)}};
|
||||
}
|
||||
|
||||
SharedLib(const SharedLib &) = delete;
|
||||
SharedLib(SharedLib &&) = delete;
|
||||
|
||||
~SharedLib() noexcept {
|
||||
uv_dlclose(&lib);
|
||||
}
|
||||
|
||||
SharedLib& operator=(const SharedLib &) = delete;
|
||||
SharedLib& operator=(SharedLib &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Checks if the library has been correctly opened.
|
||||
* @return True if the library is opened, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const noexcept { return !opened; }
|
||||
|
||||
/**
|
||||
* @brief Retrieves a data pointer from a dynamic library.
|
||||
*
|
||||
* `F` shall be a valid function type (as an example, `void(int)`).<br/>
|
||||
* It is legal for a symbol to map to `nullptr`.
|
||||
*
|
||||
* @param name The symbol to be retrieved.
|
||||
* @return A valid function pointer in case of success, `nullptr` otherwise.
|
||||
*/
|
||||
template<typename F>
|
||||
F * sym(std::string name) {
|
||||
static_assert(std::is_function<F>::value, "!");
|
||||
F *func;
|
||||
auto err = uv_dlsym(&lib, name.data(), reinterpret_cast<void**>(&func));
|
||||
if(err) { func = nullptr; }
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last error message, if any.
|
||||
* @return The last error message, if any.
|
||||
*/
|
||||
const char * error() const noexcept {
|
||||
return uv_dlerror(&lib);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the loop from which the object was originated.
|
||||
* @return A reference to a loop instance.
|
||||
*/
|
||||
Loop& loop() const noexcept { return *pLoop; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Loop> pLoop;
|
||||
uv_lib_t lib;
|
||||
bool opened;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
23
src/uvw/lib.ipp
Normal file
23
src/uvw/lib.ipp
Normal file
@ -0,0 +1,23 @@
|
||||
#include <utility>
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE shared_lib::shared_lib(loop::token token, std::shared_ptr<loop> ref, const std::string &filename) noexcept
|
||||
: uv_type{token, std::move(ref)} {
|
||||
opened = (0 == uv_dlopen(filename.data(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE shared_lib::~shared_lib() noexcept {
|
||||
uv_dlclose(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE shared_lib::operator bool() const noexcept {
|
||||
return opened;
|
||||
}
|
||||
|
||||
UVW_INLINE const char *shared_lib::error() const noexcept {
|
||||
return uv_dlerror(raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/loop.cpp
Normal file
2
src/uvw/loop.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "loop.h"
|
||||
#include "loop.ipp"
|
||||
439
src/uvw/loop.h
Normal file
439
src/uvw/loop.h
Normal file
@ -0,0 +1,439 @@
|
||||
#ifndef UVW_LOOP_INCLUDE_H
|
||||
#define UVW_LOOP_INCLUDE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <ciso646>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "emitter.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
class async_handle;
|
||||
class check_handle;
|
||||
class fs_event_handle;
|
||||
class fs_poll_handle;
|
||||
class idle_handle;
|
||||
class pipe_handle;
|
||||
class poll_handle;
|
||||
class prepare_handle;
|
||||
class process_handle;
|
||||
class signal_handle;
|
||||
class tcp_handle;
|
||||
class timer_handle;
|
||||
class tty_handle;
|
||||
class udp_handle;
|
||||
|
||||
namespace details {
|
||||
|
||||
enum class uvw_loop_option : std::underlying_type_t<uv_loop_option> {
|
||||
BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL,
|
||||
IDLE_TIME = UV_METRICS_IDLE_TIME
|
||||
};
|
||||
|
||||
enum class uvw_run_mode : std::underlying_type_t<uv_run_mode> {
|
||||
DEFAULT = UV_RUN_DEFAULT,
|
||||
ONCE = UV_RUN_ONCE,
|
||||
NOWAIT = UV_RUN_NOWAIT
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
using metrics_type = uv_metrics_t; /*!< Library equivalent for uv_metrics_t. */
|
||||
|
||||
/**
|
||||
* @brief The loop class.
|
||||
*
|
||||
* The event loop is the central part of `uvw`'s functionalities, as well as
|
||||
* `libuv`'s ones.<br/>
|
||||
* It takes care of polling for I/O and scheduling callbacks to be run based on
|
||||
* different sources of events.
|
||||
*/
|
||||
class loop final: public emitter<loop>, public std::enable_shared_from_this<loop> {
|
||||
using deleter = void (*)(uv_loop_t *);
|
||||
|
||||
template<typename, typename, typename...>
|
||||
friend class resource;
|
||||
|
||||
class uv_token {
|
||||
friend class loop;
|
||||
explicit uv_token(int) {}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
auto init(int, Type &value) -> decltype(value.init()) {
|
||||
return value.init();
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
int init(char, Type &) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept;
|
||||
|
||||
public:
|
||||
using token = uv_token;
|
||||
using time = std::chrono::duration<uint64_t, std::milli>;
|
||||
using option = details::uvw_loop_option;
|
||||
using run_mode = details::uvw_run_mode;
|
||||
|
||||
/**
|
||||
* @brief Initializes a new loop instance.
|
||||
* @return A pointer to the newly created loop.
|
||||
*/
|
||||
static std::shared_ptr<loop> create();
|
||||
|
||||
/**
|
||||
* @brief Initializes a new loop instance from an existing resource.
|
||||
*
|
||||
* The lifetime of the resource must exceed that of the instance to which
|
||||
* it's associated. Management of the memory associated with the resource is
|
||||
* in charge of the user.
|
||||
*
|
||||
* @param res A valid pointer to a correctly initialized resource.
|
||||
* @return A pointer to the newly created loop.
|
||||
*/
|
||||
static std::shared_ptr<loop> create(uv_loop_t *res);
|
||||
|
||||
/**
|
||||
* @brief Gets the initialized default loop.
|
||||
*
|
||||
* It may return an empty pointer in case of failure.<br>
|
||||
* This function is just a convenient way for having a global loop
|
||||
* throughout an application, the default loop is in no way different than
|
||||
* the ones initialized with `create()`.<br>
|
||||
* As such, the default loop can be closed with `close()` so the resources
|
||||
* associated with it are freed (even if it is not strictly necessary).
|
||||
*
|
||||
* @return The initialized default loop.
|
||||
*/
|
||||
static std::shared_ptr<loop> get_default();
|
||||
|
||||
loop(const loop &) = delete;
|
||||
loop(loop &&other) = delete;
|
||||
|
||||
loop &operator=(const loop &) = delete;
|
||||
loop &operator=(loop &&other) = delete;
|
||||
|
||||
~loop() noexcept override;
|
||||
|
||||
/**
|
||||
* @brief Sets additional loop options.
|
||||
*
|
||||
* You should normally call this before the first call to uv_run() unless
|
||||
* mentioned otherwise.<br/>
|
||||
* Supported options:
|
||||
*
|
||||
* * `loop::option::BLOCK_SIGNAL`: Block a signal when polling for new
|
||||
* events. A second argument is required and it is the signal number.
|
||||
* * `loop::option::IDLE_TIME`: Accumulate the amount of idle time the event
|
||||
* loop spends in the event provider. This option is necessary to use
|
||||
* `idle_time()`.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
|
||||
* for further details.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
template<typename... Args>
|
||||
int configure(option flag, Args &&...args) {
|
||||
return uv_loop_configure(uv_loop.get(), static_cast<uv_loop_option>(flag), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates resources of any type.
|
||||
*
|
||||
* This should be used as a default method to create resources.<br/>
|
||||
* The arguments are the ones required for the specific resource.
|
||||
*
|
||||
* Use it as `loop->resource<uvw::timer_handle>()`.
|
||||
*
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
std::shared_ptr<R> resource(Args &&...args) {
|
||||
auto ptr = uninitialized_resource<R>(std::forward<Args>(args)...);
|
||||
return (init(0, *ptr) == 0) ? ptr : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates uninitialized resources of any type.
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
std::shared_ptr<R> uninitialized_resource(Args &&...args) {
|
||||
return std::make_shared<R>(token{0}, shared_from_this(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases all internal loop resources.
|
||||
*
|
||||
* Call this function only when the loop has finished executing and all open
|
||||
* handles and requests have been closed, or the loop will error.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int close();
|
||||
|
||||
/**
|
||||
* @brief Runs the event loop.
|
||||
*
|
||||
* Available modes are:
|
||||
*
|
||||
* * `loop::run_mode::DEFAULT`: Runs the event loop until there are no more
|
||||
* active and referenced handles or requests.
|
||||
* * `loop::run_mode::ONCE`: Poll for i/o once. Note that this function
|
||||
* blocks if there are no pending callbacks.
|
||||
* * `loop::run_mode::NOWAIT`: Poll for i/o once but don’t block if there
|
||||
* are no pending callbacks.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
|
||||
* for further details.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int run(run_mode mode = run_mode::DEFAULT) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Checks if there are active resources.
|
||||
* @return True if there are active resources in the loop.
|
||||
*/
|
||||
bool alive() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Stops the event loop.
|
||||
*
|
||||
* It causes `run()` to end as soon as possible.<br/>
|
||||
* This will happen not sooner than the next loop iteration.<br/>
|
||||
* If this function was called before blocking for I/O, the loop won’t block
|
||||
* for I/O on this iteration.
|
||||
*/
|
||||
void stop() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get backend file descriptor.
|
||||
*
|
||||
* Only kqueue, epoll and event ports are supported.<br/>
|
||||
* This can be used in conjunction with `run(loop::run_mode::NOWAIT)` to
|
||||
* poll in one thread and run the event loop’s callbacks in another.
|
||||
*
|
||||
* @return The backend file descriptor.
|
||||
*/
|
||||
int descriptor() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the poll timeout.
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of valid timeout, false otherwise.
|
||||
* * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
std::pair<bool, time> timeout() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of time the event loop has been idle. The call
|
||||
* is thread safe.
|
||||
* @return The accumulated time spent idle.
|
||||
*/
|
||||
time idle_time() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Tracks various internal operations of the event loop.
|
||||
* @return Event loop metrics.
|
||||
*/
|
||||
metrics_type metrics() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Returns the current timestamp in milliseconds.
|
||||
*
|
||||
* The timestamp is cached at the start of the event loop tick.<br/>
|
||||
* The timestamp increases monotonically from some arbitrary point in
|
||||
* time.<br/>
|
||||
* Don’t make assumptions about the starting point, you will only get
|
||||
* disappointed.
|
||||
*
|
||||
* @return The current timestamp in milliseconds (actual type is
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
time now() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Updates the event loop’s concept of _now_.
|
||||
*
|
||||
* The current time is cached at the start of the event loop tick in order
|
||||
* to reduce the number of time-related system calls.<br/>
|
||||
* You won’t normally need to call this function unless you have callbacks
|
||||
* that block the event loop for longer periods of time, where _longer_ is
|
||||
* somewhat subjective but probably on the order of a millisecond or more.
|
||||
*/
|
||||
void update() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Walks the list of handles.
|
||||
*
|
||||
* The callback is invoked once for each handle that is still active.
|
||||
*
|
||||
* @param callback A function to invoke once for each active handle.
|
||||
*/
|
||||
template<typename Func>
|
||||
void walk(Func callback) {
|
||||
auto func = [](uv_handle_t *hndl, void *callback_func) {
|
||||
if(hndl->data) {
|
||||
auto &cb = *static_cast<Func *>(callback_func);
|
||||
|
||||
switch(utilities::guess_handle(handle_category{hndl->type})) {
|
||||
case handle_type::ASYNC:
|
||||
cb(*static_cast<async_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::CHECK:
|
||||
cb(*static_cast<check_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::FS_EVENT:
|
||||
cb(*static_cast<fs_event_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::FS_POLL:
|
||||
cb(*static_cast<fs_poll_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::IDLE:
|
||||
cb(*static_cast<idle_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::PIPE:
|
||||
cb(*static_cast<pipe_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::POLL:
|
||||
cb(*static_cast<poll_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::PREPARE:
|
||||
cb(*static_cast<prepare_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::PROCESS:
|
||||
cb(*static_cast<process_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::SIGNAL:
|
||||
cb(*static_cast<signal_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::TCP:
|
||||
cb(*static_cast<tcp_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::TIMER:
|
||||
cb(*static_cast<timer_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::TTY:
|
||||
cb(*static_cast<tty_handle *>(hndl->data));
|
||||
break;
|
||||
case handle_type::UDP:
|
||||
cb(*static_cast<udp_handle *>(hndl->data));
|
||||
break;
|
||||
default:
|
||||
// this handle isn't managed by uvw, let it be...
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uv_walk(uv_loop.get(), func, &callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reinitialize any kernel state necessary in the child process after
|
||||
* a fork(2) system call.
|
||||
*
|
||||
* Previously started watchers will continue to be started in the child
|
||||
* process.
|
||||
*
|
||||
* It is necessary to explicitly call this function on every event loop
|
||||
* created in the parent process that you plan to continue to use in the
|
||||
* child, including the default loop (even if you don’t continue to use it
|
||||
* in the parent). This function must be called before calling any API
|
||||
* function using the loop in the child. Failure to do so will result in
|
||||
* undefined behaviour, possibly including duplicate events delivered to
|
||||
* both parent and child or aborting the child process.
|
||||
*
|
||||
* When possible, it is preferred to create a new loop in the child process
|
||||
* instead of reusing a loop created in the parent. New loops created in the
|
||||
* child process after the fork should not use this function.
|
||||
*
|
||||
* Note that this function is not implemented on Windows.<br/>
|
||||
* Note also that this function is experimental in `libuv`. It may contain
|
||||
* bugs, and is subject to change or removal. API and ABI stability is not
|
||||
* guaranteed.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
|
||||
* for further details.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int fork() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets user-defined data. `uvw` won't use this field in any case.
|
||||
* @return User-defined data if any, an invalid pointer otherwise.
|
||||
*/
|
||||
template<typename R = void>
|
||||
std::shared_ptr<R> data() const {
|
||||
return std::static_pointer_cast<R>(user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets arbitrary data. `uvw` won't use this field in any case.
|
||||
* @param ud User-defined arbitrary data.
|
||||
*/
|
||||
void data(std::shared_ptr<void> ud);
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying raw data structure.
|
||||
*
|
||||
* This function should not be used, unless you know exactly what you are
|
||||
* doing and what are the risks.<br/>
|
||||
* Going raw is dangerous, mainly because the lifetime management of a loop,
|
||||
* a handle or a request is in charge to the library itself and users should
|
||||
* not work around it.
|
||||
*
|
||||
* @warning
|
||||
* Use this function at your own risk, but do not expect any support in case
|
||||
* of bugs.
|
||||
*
|
||||
* @return The underlying raw data structure.
|
||||
*/
|
||||
const uv_loop_t *raw() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying raw data structure.
|
||||
*
|
||||
* This function should not be used, unless you know exactly what you are
|
||||
* doing and what are the risks.<br/>
|
||||
* Going raw is dangerous, mainly because the lifetime management of a loop,
|
||||
* a handle or a request is in charge to the library itself and users should
|
||||
* not work around it.
|
||||
*
|
||||
* @warning
|
||||
* Use this function at your own risk, but do not expect any support in case
|
||||
* of bugs.
|
||||
*
|
||||
* @return The underlying raw data structure.
|
||||
*/
|
||||
uv_loop_t *raw() noexcept;
|
||||
|
||||
private:
|
||||
std::unique_ptr<uv_loop_t, deleter> uv_loop;
|
||||
std::shared_ptr<void> user_data{nullptr};
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "loop.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_LOOP_INCLUDE_H
|
||||
417
src/uvw/loop.hpp
417
src/uvw/loop.hpp
@ -1,417 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ciso646>
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <chrono>
|
||||
#include <uv.h>
|
||||
#include "emitter.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
|
||||
enum class UVLoopOption: std::underlying_type_t<uv_loop_option> {
|
||||
BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL
|
||||
};
|
||||
|
||||
|
||||
enum class UVRunMode: std::underlying_type_t<uv_run_mode> {
|
||||
DEFAULT = UV_RUN_DEFAULT,
|
||||
ONCE = UV_RUN_ONCE,
|
||||
NOWAIT = UV_RUN_NOWAIT
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Untyped handle class
|
||||
*
|
||||
* Handles' types are unknown from the point of view of the loop.<br/>
|
||||
* Anyway, a loop maintains a list of all the associated handles and let the
|
||||
* users walk them as untyped instances.<br/>
|
||||
* This can help to end all the pending requests by closing the handles.
|
||||
*/
|
||||
class BaseHandle {
|
||||
public:
|
||||
/**
|
||||
* @brief Checks if the handle is active.
|
||||
*
|
||||
* What _active_ means depends on the type of handle:
|
||||
*
|
||||
* * An AsyncHandle handle is always active and cannot be deactivated,
|
||||
* except by closing it with uv_close().
|
||||
* * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
|
||||
* that deals with I/O - is active when it is doing something that involves
|
||||
* I/O, like reading, writing, connecting, accepting new connections, etc.
|
||||
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
|
||||
* has been started with a call to `start()`.
|
||||
*
|
||||
* Rule of thumb: if a handle of type `FooHandle` has a `start()` member
|
||||
* method, then it’s active from the moment that method is called. Likewise,
|
||||
* `stop()` deactivates the handle again.
|
||||
*
|
||||
* @return True if the handle is active, false otherwise.
|
||||
*/
|
||||
virtual bool active() const noexcept = 0;
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle is closing or closed.
|
||||
*
|
||||
* This function should only be used between the initialization of the
|
||||
* handle and the arrival of the close callback.
|
||||
*
|
||||
* @return True if the handle is closing or closed, false otherwise.
|
||||
*/
|
||||
virtual bool closing() const noexcept = 0;
|
||||
|
||||
/**
|
||||
* @brief Reference the given handle.
|
||||
*
|
||||
* References are idempotent, that is, if a handle is already referenced
|
||||
* calling this function again will have no effect.
|
||||
*/
|
||||
virtual void reference() noexcept = 0;
|
||||
|
||||
/**
|
||||
* @brief Unreference the given handle.
|
||||
*
|
||||
* References are idempotent, that is, if a handle is not referenced calling
|
||||
* this function again will have no effect.
|
||||
*/
|
||||
virtual void unreference() noexcept = 0;
|
||||
|
||||
/**
|
||||
* @brief Checks if the given handle referenced.
|
||||
* @return True if the handle referenced, false otherwise.
|
||||
*/
|
||||
virtual bool referenced() const noexcept = 0;
|
||||
|
||||
/**
|
||||
* @brief Request handle to be closed.
|
||||
*
|
||||
* This **must** be called on each handle before memory is released.<br/>
|
||||
* In-progress requests are cancelled and this can result in an ErrorEvent
|
||||
* emitted.
|
||||
*/
|
||||
virtual void close() noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The Loop class.
|
||||
*
|
||||
* The event loop is the central part of `uvw`'s functionalities, as well as
|
||||
* `libuv`'s ones.<br/>
|
||||
* It takes care of polling for I/O and scheduling callbacks to be run based on
|
||||
* different sources of events.
|
||||
*/
|
||||
class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop> {
|
||||
using Deleter = void(*)(uv_loop_t *);
|
||||
|
||||
template<typename, typename>
|
||||
friend class Resource;
|
||||
|
||||
Loop(std::unique_ptr<uv_loop_t, Deleter> ptr) noexcept
|
||||
: loop{std::move(ptr)}
|
||||
{}
|
||||
|
||||
public:
|
||||
using Time = std::chrono::duration<uint64_t, std::milli>;
|
||||
using Configure = details::UVLoopOption;
|
||||
using Mode = details::UVRunMode;
|
||||
|
||||
/**
|
||||
* @brief Initializes a new Loop instance.
|
||||
* @return A pointer to the newly created loop.
|
||||
*/
|
||||
static std::shared_ptr<Loop> create() {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l){ delete l; }};
|
||||
auto loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}};
|
||||
|
||||
if(uv_loop_init(loop->loop.get())) {
|
||||
loop = nullptr;
|
||||
}
|
||||
|
||||
return loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the initialized default loop.
|
||||
*
|
||||
* It may return an empty pointer in case of failure.<br>
|
||||
* This function is just a convenient way for having a global loop
|
||||
* throughout an application, the default loop is in no way different than
|
||||
* the ones initialized with `create()`.<br>
|
||||
* As such, the default loop can be closed with `close()` so the resources
|
||||
* associated with it are freed (even if it is not strictly necessary).
|
||||
*
|
||||
* @return The initialized default loop.
|
||||
*/
|
||||
static std::shared_ptr<Loop> getDefault() {
|
||||
static std::weak_ptr<Loop> ref;
|
||||
std::shared_ptr<Loop> loop;
|
||||
|
||||
if(ref.expired()) {
|
||||
auto def = uv_default_loop();
|
||||
|
||||
if(def) {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, Deleter>(def, [](uv_loop_t *){});
|
||||
loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}};
|
||||
}
|
||||
|
||||
ref = loop;
|
||||
} else {
|
||||
loop = ref.lock();
|
||||
}
|
||||
|
||||
return loop;
|
||||
}
|
||||
|
||||
Loop(const Loop &) = delete;
|
||||
Loop(Loop &&other) = delete;
|
||||
Loop& operator=(const Loop &) = delete;
|
||||
Loop& operator=(Loop &&other) = delete;
|
||||
|
||||
~Loop() noexcept {
|
||||
if(loop) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets additional loop options.
|
||||
*
|
||||
* You should normally call this before the first call to uv_run() unless
|
||||
* mentioned otherwise.<br/>
|
||||
* Supported options:
|
||||
*
|
||||
* * `Loop::Configure::BLOCK_SIGNAL`: Block a signal when polling for new
|
||||
* events. A second argument is required and it is the signal number.
|
||||
*
|
||||
* An ErrorEvent will be emitted in case of errors.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
|
||||
* for further details.
|
||||
*/
|
||||
template<typename... Args>
|
||||
void configure(Configure flag, Args&&... args) {
|
||||
auto err = uv_loop_configure(loop.get(), static_cast<std::underlying_type_t<Configure>>(flag), std::forward<Args>(args)...);
|
||||
if(err) { publish(ErrorEvent{err}); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates resources of handles' types.
|
||||
*
|
||||
* This should be used as a default method to create resources.<br/>
|
||||
* The arguments are the ones required for the specific resource.
|
||||
*
|
||||
* Use it as `loop->resource<uvw::TimerHandle>()`.
|
||||
*
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
std::enable_if_t<std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
resource(Args&&... args) {
|
||||
auto ptr = R::create(shared_from_this(), std::forward<Args>(args)...);
|
||||
ptr = ptr->init() ? ptr : nullptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates resources of types other than handles' ones.
|
||||
*
|
||||
* This should be used as a default method to create resources.<br/>
|
||||
* The arguments are the ones required for the specific resource.
|
||||
*
|
||||
* Use it as `loop->resource<uvw::WorkReq>()`.
|
||||
*
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
std::enable_if_t<not std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
resource(Args&&... args) {
|
||||
return R::create(shared_from_this(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases all internal loop resources.
|
||||
*
|
||||
* Call this function only when the loop has finished executing and all open
|
||||
* handles and requests have been closed, or the loop will emit an error.
|
||||
*
|
||||
* An ErrorEvent will be emitted in case of errors.
|
||||
*/
|
||||
void close() {
|
||||
auto err = uv_loop_close(loop.get());
|
||||
if(err) { publish(ErrorEvent{err}); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Runs the event loop.
|
||||
*
|
||||
* Available modes are:
|
||||
*
|
||||
* * `Loop::Mode::DEFAULT`: Runs the event loop until there are no more
|
||||
* active and referenced handles or requests.
|
||||
* * `Loop::Mode::ONCE`: Poll for i/o once. Note that this function blocks
|
||||
* if there are no pending callbacks.
|
||||
* * `Loop::Mode::NOWAIT`: Poll for i/o once but don’t block if there are no
|
||||
* pending callbacks.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
|
||||
* for further details.
|
||||
*
|
||||
* @return True when done, false in all other cases.
|
||||
*/
|
||||
template<Mode mode = Mode::DEFAULT>
|
||||
bool run() noexcept {
|
||||
auto utm = static_cast<std::underlying_type_t<Mode>>(mode);
|
||||
auto uvrm = static_cast<uv_run_mode>(utm);
|
||||
return (uv_run(loop.get(), uvrm) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if there are active resources.
|
||||
* @return True if there are active resources in the loop.
|
||||
*/
|
||||
bool alive() const noexcept {
|
||||
return !(uv_loop_alive(loop.get()) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the event loop.
|
||||
*
|
||||
* It causes `run()` to end as soon as possible.<br/>
|
||||
* This will happen not sooner than the next loop iteration.<br/>
|
||||
* If this function was called before blocking for I/O, the loop won’t block
|
||||
* for I/O on this iteration.
|
||||
*/
|
||||
void stop() noexcept {
|
||||
uv_stop(loop.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get backend file descriptor.
|
||||
*
|
||||
* Only kqueue, epoll and event ports are supported.<br/>
|
||||
* This can be used in conjunction with `run<Loop::Mode::NOWAIT>()` to poll
|
||||
* in one thread and run the event loop’s callbacks in another.
|
||||
*
|
||||
* @return The backend file descriptor.
|
||||
*/
|
||||
int descriptor() const noexcept {
|
||||
return uv_backend_fd(loop.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the poll timeout.
|
||||
* @return A `std::pair` composed as it follows:
|
||||
* * A boolean value that is true in case of valid timeout, false otherwise.
|
||||
* * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
std::pair<bool, Time> timeout() const noexcept {
|
||||
auto to = uv_backend_timeout(loop.get());
|
||||
return std::make_pair(to == -1, Time{to});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current timestamp in milliseconds.
|
||||
*
|
||||
* The timestamp is cached at the start of the event loop tick.<br/>
|
||||
* The timestamp increases monotonically from some arbitrary point in
|
||||
* time.<br/>
|
||||
* Don’t make assumptions about the starting point, you will only get
|
||||
* disappointed.
|
||||
*
|
||||
* @return The current timestamp in milliseconds (actual type is
|
||||
* `std::chrono::duration<uint64_t, std::milli>`).
|
||||
*/
|
||||
Time now() const noexcept {
|
||||
return Time{uv_now(loop.get())};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the event loop’s concept of _now_.
|
||||
*
|
||||
* The current time is cached at the start of the event loop tick in order
|
||||
* to reduce the number of time-related system calls.<br/>
|
||||
* You won’t normally need to call this function unless you have callbacks
|
||||
* that block the event loop for longer periods of time, where _longer_ is
|
||||
* somewhat subjective but probably on the order of a millisecond or more.
|
||||
*/
|
||||
void update() const noexcept {
|
||||
return uv_update_time(loop.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Walks the list of handles.
|
||||
*
|
||||
* The callback will be executed once for each handle that is still active.
|
||||
*
|
||||
* @param callback A function to be invoked once for each active handle.
|
||||
*/
|
||||
void walk(std::function<void(BaseHandle &)> callback) {
|
||||
// remember: non-capturing lambdas decay to pointers to functions
|
||||
uv_walk(loop.get(), [](uv_handle_t *handle, void *func) {
|
||||
BaseHandle &ref = *static_cast<BaseHandle*>(handle->data);
|
||||
std::function<void(BaseHandle &)> &f =
|
||||
*static_cast<std::function<void(BaseHandle &)>*>(func);
|
||||
f(ref);
|
||||
}, &callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reinitialize any kernel state necessary in the child process after
|
||||
* a fork(2) system call.
|
||||
*
|
||||
* Previously started watchers will continue to be started in the child
|
||||
* process.
|
||||
*
|
||||
* It is necessary to explicitly call this function on every event loop
|
||||
* created in the parent process that you plan to continue to use in the
|
||||
* child, including the default loop (even if you don’t continue to use it
|
||||
* in the parent). This function must be called before calling any API
|
||||
* function using the loop in the child. Failure to do so will result in
|
||||
* undefined behaviour, possibly including duplicate events delivered to
|
||||
* both parent and child or aborting the child process.
|
||||
*
|
||||
* When possible, it is preferred to create a new loop in the child process
|
||||
* instead of reusing a loop created in the parent. New loops created in the
|
||||
* child process after the fork should not use this function.
|
||||
*
|
||||
* Note that this function is not implemented on Windows.<br/>
|
||||
* Note also that this function is experimental in `libuv`. It may contain
|
||||
* bugs, and is subject to change or removal. API and ABI stability is not
|
||||
* guaranteed.
|
||||
*
|
||||
* An ErrorEvent will be emitted in case of errors.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
|
||||
* for further details.
|
||||
*/
|
||||
void fork() noexcept {
|
||||
auto err = uv_loop_fork(loop.get());
|
||||
if(err) { publish(ErrorEvent{err}); }
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<uv_loop_t, Deleter> loop;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
116
src/uvw/loop.ipp
Normal file
116
src/uvw/loop.ipp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE loop::loop(std::unique_ptr<uv_loop_t, deleter> ptr) noexcept
|
||||
: uv_loop{std::move(ptr)} {}
|
||||
|
||||
UVW_INLINE std::shared_ptr<loop> loop::create() {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, deleter>{new uv_loop_t, [](uv_loop_t *l) { delete l; }};
|
||||
auto curr = std::shared_ptr<loop>{new loop{std::move(ptr)}};
|
||||
|
||||
if(uv_loop_init(curr->uv_loop.get())) {
|
||||
curr = nullptr;
|
||||
}
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
UVW_INLINE std::shared_ptr<loop> loop::create(uv_loop_t *res) {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, deleter>{res, [](uv_loop_t *) {}};
|
||||
return std::shared_ptr<loop>{new loop{std::move(ptr)}};
|
||||
}
|
||||
|
||||
UVW_INLINE std::shared_ptr<loop> loop::get_default() {
|
||||
static std::weak_ptr<loop> ref;
|
||||
std::shared_ptr<loop> curr;
|
||||
|
||||
if(ref.expired()) {
|
||||
auto def = uv_default_loop();
|
||||
|
||||
if(def) {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, deleter>(def, [](uv_loop_t *) {});
|
||||
curr = std::shared_ptr<loop>{new loop{std::move(ptr)}};
|
||||
}
|
||||
|
||||
ref = curr;
|
||||
} else {
|
||||
curr = ref.lock();
|
||||
}
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
UVW_INLINE loop::~loop() noexcept {
|
||||
if(uv_loop) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int loop::close() {
|
||||
int ret = 0;
|
||||
|
||||
if(uv_loop) {
|
||||
ret = uv_loop_close(uv_loop.get());
|
||||
uv_loop.reset();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UVW_INLINE int loop::run(run_mode mode) noexcept {
|
||||
return uv_run(uv_loop.get(), static_cast<uv_run_mode>(mode));
|
||||
}
|
||||
|
||||
UVW_INLINE bool loop::alive() const noexcept {
|
||||
return !!uv_loop_alive(uv_loop.get());
|
||||
}
|
||||
|
||||
UVW_INLINE void loop::stop() noexcept {
|
||||
uv_stop(uv_loop.get());
|
||||
}
|
||||
|
||||
UVW_INLINE int loop::descriptor() const noexcept {
|
||||
return uv_backend_fd(uv_loop.get());
|
||||
}
|
||||
|
||||
UVW_INLINE std::pair<bool, loop::time> loop::timeout() const noexcept {
|
||||
auto to = uv_backend_timeout(uv_loop.get());
|
||||
return std::make_pair(to == -1, time{to});
|
||||
}
|
||||
|
||||
UVW_INLINE loop::time loop::idle_time() const noexcept {
|
||||
return time{uv_metrics_idle_time(uv_loop.get())};
|
||||
}
|
||||
|
||||
UVW_INLINE metrics_type loop::metrics() const noexcept {
|
||||
metrics_type res{};
|
||||
uv_metrics_info(uv_loop.get(), &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
UVW_INLINE loop::time loop::now() const noexcept {
|
||||
return time{uv_now(uv_loop.get())};
|
||||
}
|
||||
|
||||
UVW_INLINE void loop::update() const noexcept {
|
||||
return uv_update_time(uv_loop.get());
|
||||
}
|
||||
|
||||
UVW_INLINE int loop::fork() noexcept {
|
||||
return uv_loop_fork(uv_loop.get());
|
||||
}
|
||||
|
||||
UVW_INLINE void loop::data(std::shared_ptr<void> ud) {
|
||||
user_data = std::move(ud);
|
||||
}
|
||||
|
||||
UVW_INLINE const uv_loop_t *loop::raw() const noexcept {
|
||||
return uv_loop.get();
|
||||
}
|
||||
|
||||
UVW_INLINE uv_loop_t *loop::raw() noexcept {
|
||||
return const_cast<uv_loop_t *>(const_cast<const loop *>(this)->raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/pipe.cpp
Normal file
2
src/uvw/pipe.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "pipe.h"
|
||||
#include "pipe.ipp"
|
||||
@ -1,44 +1,51 @@
|
||||
#pragma once
|
||||
#ifndef UVW_PIPE_INCLUDE_H
|
||||
#define UVW_PIPE_INCLUDE_H
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "enum.hpp"
|
||||
#include "loop.h"
|
||||
#include "request.hpp"
|
||||
#include "stream.hpp"
|
||||
#include "util.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
#include "stream.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
namespace details {
|
||||
|
||||
enum class uvw_chmod_flags : std::underlying_type_t<uv_poll_event> {
|
||||
READABLE = UV_READABLE,
|
||||
WRITABLE = UV_WRITABLE,
|
||||
UVW_ENUM = 0
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The PipeHandle handle.
|
||||
* @brief The pipe handle.
|
||||
*
|
||||
* Pipe handles provide an abstraction over local domain sockets on Unix and
|
||||
* named pipes on Windows.
|
||||
*
|
||||
* To create a `PipeHandle` through a `Loop`, arguments follow:
|
||||
* To create a `pipe_handle` through a `loop`, arguments follow:
|
||||
*
|
||||
* * An optional boolean value that indicates if this pipe will be used for
|
||||
* handle passing between processes.
|
||||
*/
|
||||
class PipeHandle final: public StreamHandle<PipeHandle, uv_pipe_t> {
|
||||
class pipe_handle final: public stream_handle<pipe_handle, uv_pipe_t> {
|
||||
public:
|
||||
explicit PipeHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool pass = false)
|
||||
: StreamHandle{std::move(ca), std::move(ref)}, ipc{pass}
|
||||
{}
|
||||
using chmod_flags = details::uvw_chmod_flags;
|
||||
|
||||
explicit pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass = false);
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_pipe_init, ipc);
|
||||
}
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Opens an existing file descriptor or HANDLE as a pipe.
|
||||
@ -47,10 +54,9 @@ public:
|
||||
* it’s required that it represents a valid pipe.
|
||||
*
|
||||
* @param file A valid file handle (either a file descriptor or a HANDLE).
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
void open(FileHandle file) {
|
||||
invoke(&uv_pipe_open, get(), file);
|
||||
}
|
||||
int open(file_handle file);
|
||||
|
||||
/**
|
||||
* @brief bind Binds the pipe to a file path (Unix) or a name (Windows).
|
||||
@ -58,37 +64,30 @@ public:
|
||||
* Paths on Unix get truncated typically between 92 and 108 bytes.
|
||||
*
|
||||
* @param name A valid file path.
|
||||
* @param no_truncate Force an error rather than allow truncating a path.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
void bind(std::string name) {
|
||||
invoke(&uv_pipe_bind, get(), name.data());
|
||||
}
|
||||
int bind(const std::string &name, const bool no_truncate = false);
|
||||
|
||||
/**
|
||||
* @brief Connects to the Unix domain socket or the named pipe.
|
||||
*
|
||||
* Paths on Unix get truncated typically between 92 and 108 bytes.
|
||||
* Paths on Unix get truncated typically between 92 and 108 bytes.<br/>
|
||||
* A connect event is emitted when the connection has been
|
||||
* established.
|
||||
*
|
||||
* @param name A valid domain socket or named pipe.
|
||||
* @param no_truncate Force an error rather than allow truncating a path.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
void connect(std::string name) {
|
||||
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
auto connect = loop().resource<details::ConnectReq>();
|
||||
connect->once<ErrorEvent>(listener);
|
||||
connect->once<ConnectEvent>(listener);
|
||||
connect->connect(&uv_pipe_connect, get(), name.data());
|
||||
}
|
||||
int connect(const std::string &name, const bool no_truncate = false);
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the Unix domain socket or the named pipe.
|
||||
* @return The name of the Unix domain socket or the named pipe, an empty
|
||||
* string in case of errors.
|
||||
*/
|
||||
std::string sock() const noexcept {
|
||||
return details::tryRead(&uv_pipe_getsockname, get());
|
||||
}
|
||||
std::string sock() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the Unix domain socket or the named pipe to which
|
||||
@ -96,9 +95,7 @@ public:
|
||||
* @return The name of the Unix domain socket or the named pipe to which
|
||||
* the handle is connected, an empty string in case of errors.
|
||||
*/
|
||||
std::string peer() const noexcept {
|
||||
return details::tryRead(&uv_pipe_getpeername, get());
|
||||
}
|
||||
std::string peer() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the number of pending pipe this instance can handle.
|
||||
@ -109,17 +106,13 @@ public:
|
||||
*
|
||||
* @param count The number of accepted pending pipe.
|
||||
*/
|
||||
void pending(int count) noexcept {
|
||||
uv_pipe_pending_instances(get(), count);
|
||||
}
|
||||
void pending(int count) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of pending pipe this instance can handle.
|
||||
* @return The number of pending pipe this instance can handle.
|
||||
*/
|
||||
int pending() noexcept {
|
||||
return uv_pipe_pending_count(get());
|
||||
}
|
||||
int pending() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Used to receive handles over IPC pipes.
|
||||
@ -132,19 +125,40 @@ public:
|
||||
*
|
||||
* @return The type of the pending handle. Possible values are:
|
||||
*
|
||||
* * `HandleType::PIPE`
|
||||
* * `HandleType::TCP`
|
||||
* * `HandleType::UDP`
|
||||
* * `HandleType::UNKNOWN`
|
||||
* * `handle_type::PIPE`
|
||||
* * `handle_type::TCP`
|
||||
* * `handle_type::UDP`
|
||||
* * `handle_type::UNKNOWN`
|
||||
*/
|
||||
HandleType receive() noexcept {
|
||||
auto type = uv_pipe_pending_type(get());
|
||||
return Utilities::guessHandle(type);
|
||||
}
|
||||
handle_type receive() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Alters pipe permissions.
|
||||
*
|
||||
* It allows the pipe to be accessed from processes run by different users.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `pipe_handle::chmod_flags::READABLE`
|
||||
* * `pipe_handle::chmod_flags::WRITABLE`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod)
|
||||
* for further details.
|
||||
*
|
||||
* @param flags A valid set of flags.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int chmod(chmod_flags flags) noexcept;
|
||||
|
||||
private:
|
||||
bool ipc;
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
}
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "pipe.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_PIPE_INCLUDE_H
|
||||
59
src/uvw/pipe.ipp
Normal file
59
src/uvw/pipe.ipp
Normal file
@ -0,0 +1,59 @@
|
||||
#include <utility>
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE pipe_handle::pipe_handle(loop::token token, std::shared_ptr<loop> ref, bool pass)
|
||||
: stream_handle{token, std::move(ref)}, ipc{pass} {}
|
||||
|
||||
UVW_INLINE int pipe_handle::init() {
|
||||
return leak_if(uv_pipe_init(parent().raw(), raw(), ipc));
|
||||
}
|
||||
|
||||
UVW_INLINE int pipe_handle::open(file_handle file) {
|
||||
return uv_pipe_open(raw(), file);
|
||||
}
|
||||
|
||||
UVW_INLINE int pipe_handle::bind(const std::string &name, const bool no_truncate) {
|
||||
return uv_pipe_bind2(raw(), name.data(), name.size(), no_truncate * UV_PIPE_NO_TRUNCATE);
|
||||
}
|
||||
|
||||
UVW_INLINE int pipe_handle::connect(const std::string &name, const bool no_truncate) {
|
||||
auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
|
||||
ptr->publish(event);
|
||||
};
|
||||
|
||||
auto connect = parent().resource<details::connect_req>();
|
||||
connect->on<error_event>(listener);
|
||||
connect->on<connect_event>(listener);
|
||||
|
||||
unsigned int flags = no_truncate * UV_PIPE_NO_TRUNCATE;
|
||||
return connect->connect(&uv_pipe_connect2, raw(), name.data(), name.size(), flags);
|
||||
}
|
||||
|
||||
UVW_INLINE std::string pipe_handle::sock() const noexcept {
|
||||
return details::try_read(&uv_pipe_getsockname, raw());
|
||||
}
|
||||
|
||||
UVW_INLINE std::string pipe_handle::peer() const noexcept {
|
||||
return details::try_read(&uv_pipe_getpeername, raw());
|
||||
}
|
||||
|
||||
UVW_INLINE void pipe_handle::pending(int count) noexcept {
|
||||
uv_pipe_pending_instances(raw(), count);
|
||||
}
|
||||
|
||||
UVW_INLINE int pipe_handle::pending() noexcept {
|
||||
return uv_pipe_pending_count(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE handle_type pipe_handle::receive() noexcept {
|
||||
handle_category category = uv_pipe_pending_type(raw());
|
||||
return utilities::guess_handle(category);
|
||||
}
|
||||
|
||||
UVW_INLINE int pipe_handle::chmod(chmod_flags flags) noexcept {
|
||||
return uv_pipe_chmod(raw(), static_cast<uv_poll_event>(flags));
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/poll.cpp
Normal file
2
src/uvw/poll.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "poll.h"
|
||||
#include "poll.ipp"
|
||||
119
src/uvw/poll.h
Normal file
119
src/uvw/poll.h
Normal file
@ -0,0 +1,119 @@
|
||||
#ifndef UVW_POLL_INCLUDE_H
|
||||
#define UVW_POLL_INCLUDE_H
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "enum.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
namespace details {
|
||||
|
||||
enum class uvw_poll_event : std::underlying_type_t<uv_poll_event> {
|
||||
READABLE = UV_READABLE,
|
||||
WRITABLE = UV_WRITABLE,
|
||||
DISCONNECT = UV_DISCONNECT,
|
||||
PRIORITIZED = UV_PRIORITIZED,
|
||||
UVW_ENUM = 0
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @brief Poll event. */
|
||||
struct poll_event {
|
||||
explicit poll_event(details::uvw_poll_event events) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Detected events all in one.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `poll_handle::event::READABLE`
|
||||
* * `poll_handle::event::WRITABLE`
|
||||
* * `poll_handle::event::DISCONNECT`
|
||||
* * `poll_handle::event::PRIORITIZED`
|
||||
*/
|
||||
details::uvw_poll_event flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The poll handle.
|
||||
*
|
||||
* Poll handles are used to watch file descriptors for readability, writability
|
||||
* and disconnection.
|
||||
*
|
||||
* To create a `poll_handle` through a `loop`, arguments follow:
|
||||
*
|
||||
* * A descriptor that can be:
|
||||
* * either an `int` file descriptor
|
||||
* * or a `os_socket_handle` socket descriptor
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/poll.html)
|
||||
* for further details.
|
||||
*/
|
||||
class poll_handle final: public handle<poll_handle, uv_poll_t, poll_event> {
|
||||
static void start_callback(uv_poll_t *hndl, int status, int events);
|
||||
|
||||
public:
|
||||
using poll_event_flags = details::uvw_poll_event;
|
||||
|
||||
explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, int desc);
|
||||
explicit poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock);
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts polling the file descriptor.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `poll_handle::event::READABLE`
|
||||
* * `poll_handle::event::WRITABLE`
|
||||
* * `poll_handle::event::DISCONNECT`
|
||||
* * `poll_handle::event::PRIORITIZED`
|
||||
*
|
||||
* As soon as an event is detected, a poll event is emitted by the
|
||||
* handle.
|
||||
*
|
||||
* Calling more than once this method will update the flags to which the
|
||||
* caller is interested.
|
||||
*
|
||||
* @param flags The events to which the caller is interested.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start(poll_event_flags flags);
|
||||
|
||||
/**
|
||||
* @brief Stops polling the file descriptor.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
|
||||
private:
|
||||
enum {
|
||||
FD,
|
||||
SOCKET
|
||||
} tag;
|
||||
|
||||
union {
|
||||
int file_desc;
|
||||
os_socket_handle socket;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "poll.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_POLL_INCLUDE_H
|
||||
155
src/uvw/poll.hpp
155
src/uvw/poll.hpp
@ -1,155 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
|
||||
enum class UVPollEvent: std::underlying_type_t<uv_poll_event> {
|
||||
READABLE = UV_READABLE,
|
||||
WRITABLE = UV_WRITABLE,
|
||||
DISCONNECT = UV_DISCONNECT
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief PollEvent event.
|
||||
*
|
||||
* It will be emitted by PollHandle according with its functionalities.
|
||||
*/
|
||||
struct PollEvent {
|
||||
explicit PollEvent(Flags<details::UVPollEvent> events) noexcept
|
||||
: flags{std::move(events)}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Detected events all in one.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `PollHandle::Event::READABLE`
|
||||
* * `PollHandle::Event::WRITABLE`
|
||||
* * `PollHandle::Event::DISCONNECT`
|
||||
*/
|
||||
Flags<details::UVPollEvent> flags;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The PollHandle handle.
|
||||
*
|
||||
* Poll handles are used to watch file descriptors for readability, writability
|
||||
* and disconnection.
|
||||
*
|
||||
* To create a `PollHandle` through a `Loop`, arguments follow:
|
||||
*
|
||||
* * A descriptor that can be:
|
||||
* * either an `int` file descriptor
|
||||
* * or a `OSSocketHandle` socket descriptor
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/poll.html)
|
||||
* for further details.
|
||||
*/
|
||||
class PollHandle final: public Handle<PollHandle, uv_poll_t> {
|
||||
static void startCallback(uv_poll_t *handle, int status, int events) {
|
||||
PollHandle &poll = *(static_cast<PollHandle*>(handle->data));
|
||||
if(status) { poll.publish(ErrorEvent{status}); }
|
||||
else { poll.publish(PollEvent{static_cast<std::underlying_type_t<Event>>(events)}); }
|
||||
}
|
||||
|
||||
public:
|
||||
using Event = details::UVPollEvent;
|
||||
|
||||
explicit PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, int desc)
|
||||
: Handle{std::move(ca), std::move(ref)}, tag{FD}, fd{desc}
|
||||
{}
|
||||
|
||||
explicit PollHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, OSSocketHandle sock)
|
||||
: Handle{std::move(ca), std::move(ref)}, tag{SOCKET}, socket{sock}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return (tag == SOCKET)
|
||||
? initialize(&uv_poll_init_socket, socket)
|
||||
: initialize(&uv_poll_init, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts polling the file descriptor.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `PollHandle::Event::READABLE`
|
||||
* * `PollHandle::Event::WRITABLE`
|
||||
* * `PollHandle::Event::DISCONNECT`
|
||||
*
|
||||
* As soon as an event is detected, a PollEvent is emitted by the
|
||||
* handle.<br>
|
||||
* It could happen that ErrorEvent events are emitted while running.
|
||||
*
|
||||
* Calling more than once this method will update the flags to which the
|
||||
* caller is interested.
|
||||
*
|
||||
* @param flags The events to which the caller is interested.
|
||||
*/
|
||||
void start(Flags<Event> flags) {
|
||||
invoke(&uv_poll_start, get(), flags, &startCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts polling the file descriptor.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `PollHandle::Event::READABLE`
|
||||
* * `PollHandle::Event::WRITABLE`
|
||||
* * `PollHandle::Event::DISCONNECT`
|
||||
*
|
||||
* As soon as an event is detected, a PollEvent is emitted by the
|
||||
* handle.<br>
|
||||
* It could happen that ErrorEvent events are emitted while running.
|
||||
*
|
||||
* Calling more than once this method will update the flags to which the
|
||||
* caller is interested.
|
||||
*
|
||||
* @param event The event to which the caller is interested.
|
||||
*/
|
||||
void start(Event event) {
|
||||
start(Flags<Event>{event});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops polling the file descriptor.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_poll_stop, get());
|
||||
}
|
||||
|
||||
private:
|
||||
enum { FD, SOCKET } tag;
|
||||
union {
|
||||
int fd;
|
||||
OSSocketHandle::Type socket;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
40
src/uvw/poll.ipp
Normal file
40
src/uvw/poll.ipp
Normal file
@ -0,0 +1,40 @@
|
||||
#include <utility>
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE poll_event::poll_event(details::uvw_poll_event events) noexcept
|
||||
: flags{events} {}
|
||||
|
||||
UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr<loop> ref, int desc)
|
||||
: handle{token, std::move(ref)}, tag{FD}, file_desc{desc} {}
|
||||
|
||||
UVW_INLINE poll_handle::poll_handle(loop::token token, std::shared_ptr<loop> ref, os_socket_handle sock)
|
||||
: handle{token, std::move(ref)}, tag{SOCKET}, socket{sock} {}
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
UVW_INLINE void poll_handle::start_callback(uv_poll_t *hndl, int status, int events) {
|
||||
if(poll_handle &poll = *(static_cast<poll_handle *>(hndl->data)); status) {
|
||||
poll.publish(error_event{status});
|
||||
} else {
|
||||
poll.publish(poll_event{poll_event_flags(events)});
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int poll_handle::init() {
|
||||
if(tag == SOCKET) {
|
||||
return leak_if(uv_poll_init_socket(parent().raw(), raw(), socket));
|
||||
} else {
|
||||
return leak_if(uv_poll_init(parent().raw(), raw(), file_desc));
|
||||
}
|
||||
}
|
||||
|
||||
UVW_INLINE int poll_handle::start(poll_event_flags flags) {
|
||||
return uv_poll_start(raw(), static_cast<uv_poll_event>(flags), &start_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE int poll_handle::stop() {
|
||||
return uv_poll_stop(raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/prepare.cpp
Normal file
2
src/uvw/prepare.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "prepare.h"
|
||||
#include "prepare.ipp"
|
||||
58
src/uvw/prepare.h
Normal file
58
src/uvw/prepare.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef UVW_PREPARE_INCLUDE_H
|
||||
#define UVW_PREPARE_INCLUDE_H
|
||||
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief Prepare event. */
|
||||
struct prepare_event {};
|
||||
|
||||
/**
|
||||
* @brief The prepare handle.
|
||||
*
|
||||
* Prepare handles will emit a prepare event once per loop iteration, right
|
||||
* before polling for I/O.
|
||||
*
|
||||
* To create a `prepare_handle` through a `loop`, no arguments are required.
|
||||
*/
|
||||
class prepare_handle final: public handle<prepare_handle, uv_prepare_t, prepare_event> {
|
||||
static void start_callback(uv_prepare_t *hndl);
|
||||
|
||||
public:
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* A prepare event will be emitted once per loop iteration, right before
|
||||
* polling for I/O.
|
||||
*
|
||||
* The handle will start emitting prepare events when needed.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start();
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "prepare.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_PREPARE_INCLUDE_H
|
||||
@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief PrepareEvent event.
|
||||
*
|
||||
* It will be emitted by PrepareHandle according with its functionalities.
|
||||
*
|
||||
* To create a `PrepareHandle` through a `Loop`, no arguments are required.
|
||||
*/
|
||||
struct PrepareEvent {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The PrepareHandle handle.
|
||||
*
|
||||
* Prepare handles will emit a PrepareEvent event once per loop iteration, right
|
||||
* before polling for I/O.
|
||||
*/
|
||||
class PrepareHandle final: public Handle<PrepareHandle, uv_prepare_t> {
|
||||
static void startCallback(uv_prepare_t *handle) {
|
||||
PrepareHandle &prepare = *(static_cast<PrepareHandle*>(handle->data));
|
||||
prepare.publish(PrepareEvent{});
|
||||
}
|
||||
|
||||
public:
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_prepare_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* A PrepareEvent event will be emitted once per loop iteration, right
|
||||
* before polling for I/O.
|
||||
*
|
||||
* The handle will start emitting PrepareEvent when needed.
|
||||
*/
|
||||
void start() {
|
||||
invoke(&uv_prepare_start, get(), &startCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_prepare_stop, get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
22
src/uvw/prepare.ipp
Normal file
22
src/uvw/prepare.ipp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE void prepare_handle::start_callback(uv_prepare_t *hndl) {
|
||||
prepare_handle &prepare = *(static_cast<prepare_handle *>(hndl->data));
|
||||
prepare.publish(prepare_event{});
|
||||
}
|
||||
|
||||
UVW_INLINE int prepare_handle::init() {
|
||||
return leak_if(uv_prepare_init(parent().raw(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE int prepare_handle::start() {
|
||||
return uv_prepare_start(raw(), &start_callback);
|
||||
}
|
||||
|
||||
UVW_INLINE int prepare_handle::stop() {
|
||||
return uv_prepare_stop(raw());
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
2
src/uvw/process.cpp
Normal file
2
src/uvw/process.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "process.h"
|
||||
#include "process.ipp"
|
||||
245
src/uvw/process.h
Normal file
245
src/uvw/process.h
Normal file
@ -0,0 +1,245 @@
|
||||
#ifndef UVW_PROCESS_INCLUDE_H
|
||||
#define UVW_PROCESS_INCLUDE_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "enum.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
#include "stream.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
namespace details {
|
||||
|
||||
enum class uvw_process_flags : std::underlying_type_t<uv_process_flags> {
|
||||
SETUID = UV_PROCESS_SETUID,
|
||||
SETGID = UV_PROCESS_SETGID,
|
||||
WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
|
||||
DETACHED = UV_PROCESS_DETACHED,
|
||||
WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE,
|
||||
WINDOWS_HIDE_CONSOLE = UV_PROCESS_WINDOWS_HIDE_CONSOLE,
|
||||
WINDOWS_HIDE_GUI = UV_PROCESS_WINDOWS_HIDE_GUI,
|
||||
WINDOWS_FILE_PATH_EXACT_NAME = UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME,
|
||||
UVW_ENUM = 0
|
||||
};
|
||||
|
||||
enum class uvw_stdio_flags : std::underlying_type_t<uv_stdio_flags> {
|
||||
IGNORE_STREAM = UV_IGNORE,
|
||||
CREATE_PIPE = UV_CREATE_PIPE,
|
||||
INHERIT_FD = UV_INHERIT_FD,
|
||||
INHERIT_STREAM = UV_INHERIT_STREAM,
|
||||
READABLE_PIPE = UV_READABLE_PIPE,
|
||||
WRITABLE_PIPE = UV_WRITABLE_PIPE,
|
||||
OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE,
|
||||
UVW_ENUM = 0
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
/*! @brief Exit event. */
|
||||
struct exit_event {
|
||||
explicit exit_event(int64_t code, int sig) noexcept;
|
||||
|
||||
int64_t status; /*!< The exit status. */
|
||||
int signal; /*!< The signal that caused the process to terminate, if any. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The process handle.
|
||||
*
|
||||
* Process handles will spawn a new process and allow the user to control it and
|
||||
* establish communication channels with it using streams.
|
||||
*/
|
||||
class process_handle final: public handle<process_handle, uv_process_t, exit_event> {
|
||||
static void exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal);
|
||||
|
||||
public:
|
||||
using process_flags = details::uvw_process_flags;
|
||||
using stdio_flags = details::uvw_stdio_flags;
|
||||
|
||||
process_handle(loop::token token, std::shared_ptr<loop> ref);
|
||||
|
||||
/**
|
||||
* @brief Disables inheritance for file descriptors/handles.
|
||||
*
|
||||
* Disables inheritance for file descriptors/handles that this process
|
||||
* inherited from its parent. The effect is that child processes spawned by
|
||||
* this process don’t accidentally inherit these handles.<br/>
|
||||
* It is recommended to call this function as early in your program as
|
||||
* possible, before the inherited file descriptors can be closed or
|
||||
* duplicated.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
|
||||
* for further details.
|
||||
*/
|
||||
static void disable_stdio_inheritance() noexcept;
|
||||
|
||||
/**
|
||||
* @brief kill Sends the specified signal to the given PID.
|
||||
* @param pid A valid process id.
|
||||
* @param signum A valid signal identifier.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
static bool kill(int pid, int signum) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief spawn Starts the process.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html)
|
||||
* for further details.
|
||||
*
|
||||
* @param file Path pointing to the program to be executed.
|
||||
* @param args Command line arguments.
|
||||
* @param env Optional environment for the new process.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int spawn(const char *file, char **args, char **env = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sends the specified signal to the internal process handle.
|
||||
* @param signum A valid signal identifier.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int kill(int signum);
|
||||
|
||||
/**
|
||||
* @brief Gets the PID of the spawned process.
|
||||
*
|
||||
* It’s set after calling `spawn()`.
|
||||
*
|
||||
* @return The PID of the spawned process.
|
||||
*/
|
||||
int pid() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the current working directory for the subprocess.
|
||||
* @param path The working directory to be used when `spawn()` is invoked.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
process_handle &cwd(const std::string &path) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets flags that control how `spawn()` behaves.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `process_handle::process_flags::SETUID`
|
||||
* * `process_handle::process_flags::SETGID`
|
||||
* * `process_handle::process_flags::WINDOWS_VERBATIM_ARGUMENTS`
|
||||
* * `process_handle::process_flags::DETACHED`
|
||||
* * `process_handle::process_flags::WINDOWS_HIDE`
|
||||
* * `process_handle::process_flags::WINDOWS_HIDE_CONSOLE`
|
||||
* * `process_handle::process_flags::WINDOWS_HIDE_GUI`
|
||||
* * `process_handle::process_flags::WINDOWS_FILE_PATH_EXACT_NAME`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
|
||||
* for further details.
|
||||
*
|
||||
* @param flags A valid set of flags.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
process_handle &flags(process_flags flags) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Makes a `stdio` handle available to the child process.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `process_handle::stdio_flags::IGNORE_STREAM`
|
||||
* * `process_handle::stdio_flags::CREATE_PIPE`
|
||||
* * `process_handle::stdio_flags::INHERIT_FD`
|
||||
* * `process_handle::stdio_flags::INHERIT_STREAM`
|
||||
* * `process_handle::stdio_flags::READABLE_PIPE`
|
||||
* * `process_handle::stdio_flags::WRITABLE_PIPE`
|
||||
* * `process_handle::stdio_flags::OVERLAPPED_PIPE`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
||||
* for further details.
|
||||
*
|
||||
* @param stream A valid `stdio` handle.
|
||||
* @param flags A valid set of flags.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
template<typename T, typename U, typename... E>
|
||||
process_handle &stdio(stream_handle<T, U, E...> &stream, stdio_flags flags) {
|
||||
uv_stdio_container_t container;
|
||||
container.flags = static_cast<uv_stdio_flags>(flags);
|
||||
container.data.stream = reinterpret_cast<uv_stream_t *>(stream.raw());
|
||||
po_stream_stdio.push_back(container);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes a file descriptor available to the child process.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `process_handle::stdio_flags::IGNORE_STREAM`
|
||||
* * `process_handle::stdio_flags::CREATE_PIPE`
|
||||
* * `process_handle::stdio_flags::INHERIT_FD`
|
||||
* * `process_handle::stdio_flags::INHERIT_STREAM`
|
||||
* * `process_handle::stdio_flags::READABLE_PIPE`
|
||||
* * `process_handle::stdio_flags::WRITABLE_PIPE`
|
||||
* * `process_handle::stdio_flags::OVERLAPPED_PIPE`
|
||||
*
|
||||
* Default file descriptors are:
|
||||
* * `uvw::std_in` for `stdin`
|
||||
* * `uvw::std_out` for `stdout`
|
||||
* * `uvw::std_err` for `stderr`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
||||
* for further details.
|
||||
*
|
||||
* @param fd A valid file descriptor.
|
||||
* @param flags A valid set of flags.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
process_handle &stdio(file_handle fd, stdio_flags flags);
|
||||
|
||||
/**
|
||||
* @brief Sets the child process' user id.
|
||||
* @param id A valid user id to be used.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
process_handle &uid(uid_type id);
|
||||
|
||||
/**
|
||||
* @brief Sets the child process' group id.
|
||||
* @param id A valid group id to be used.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
process_handle &gid(gid_type id);
|
||||
|
||||
private:
|
||||
std::string po_cwd;
|
||||
process_flags po_flags;
|
||||
std::vector<uv_stdio_container_t> po_fd_stdio;
|
||||
std::vector<uv_stdio_container_t> po_stream_stdio;
|
||||
uid_type po_uid;
|
||||
gid_type po_gid;
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "process.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_PROCESS_INCLUDE_H
|
||||
@ -1,324 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "stream.hpp"
|
||||
#include "util.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
|
||||
enum class UVProcessFlags: std::underlying_type_t<uv_process_flags> {
|
||||
SETUID = UV_PROCESS_SETUID,
|
||||
SETGID = UV_PROCESS_SETGID,
|
||||
WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
|
||||
DETACHED = UV_PROCESS_DETACHED,
|
||||
WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE
|
||||
};
|
||||
|
||||
|
||||
enum class UVStdIOFlags: std::underlying_type_t<uv_stdio_flags> {
|
||||
IGNORE_STREAM = UV_IGNORE,
|
||||
CREATE_PIPE = UV_CREATE_PIPE,
|
||||
INHERIT_FD = UV_INHERIT_FD,
|
||||
INHERIT_STREAM = UV_INHERIT_STREAM,
|
||||
READABLE_PIPE = UV_READABLE_PIPE,
|
||||
WRITABLE_PIPE = UV_WRITABLE_PIPE
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief ExitEvent event.
|
||||
*
|
||||
* It will be emitted by ProcessHandle according with its functionalities.
|
||||
*/
|
||||
struct ExitEvent {
|
||||
explicit ExitEvent(int64_t code, int sig) noexcept
|
||||
: status{code}, signal{sig}
|
||||
{}
|
||||
|
||||
int64_t status; /*!< The exit status. */
|
||||
int signal; /*!< The signal that caused the process to terminate, if any. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The ProcessHandle handle.
|
||||
*
|
||||
* Process handles will spawn a new process and allow the user to control it and
|
||||
* establish communication channels with it using streams.
|
||||
*/
|
||||
class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
|
||||
static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
|
||||
ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
|
||||
process.publish(ExitEvent{exitStatus, termSignal});
|
||||
}
|
||||
|
||||
public:
|
||||
using Process = details::UVProcessFlags;
|
||||
using StdIO = details::UVStdIOFlags;
|
||||
|
||||
ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
|
||||
: Handle{std::move(ca), std::move(ref)}, poFdStdio{1}
|
||||
{
|
||||
// stdin container default initialization
|
||||
poFdStdio[0].flags = static_cast<uv_stdio_flags>(StdIO::IGNORE_STREAM);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables inheritance for file descriptors/handles.
|
||||
*
|
||||
* Disables inheritance for file descriptors/handles that this process
|
||||
* inherited from its parent. The effect is that child processes spawned by
|
||||
* this process don’t accidentally inherit these handles.<br/>
|
||||
* It is recommended to call this function as early in your program as
|
||||
* possible, before the inherited file descriptors can be closed or
|
||||
* duplicated.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
|
||||
* for further details.
|
||||
*/
|
||||
static void disableStdIOInheritance() noexcept {
|
||||
uv_disable_stdio_inheritance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief kill Sends the specified signal to the given PID.
|
||||
* @param pid A valid process id.
|
||||
* @param signum A valid signal identifier.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
static bool kill(int pid, int signum) noexcept {
|
||||
return (0 == uv_kill(pid, signum));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
// fake initialization so as to have leak invoked
|
||||
return initialize([](auto...){ return 0; });
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief spawn Starts the process.
|
||||
*
|
||||
* If the process isn't successfully spawned, an ErrorEvent event will be
|
||||
* emitted by the handle.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html)
|
||||
* for further details.
|
||||
*
|
||||
* @param file Path pointing to the program to be executed.
|
||||
* @param args Command line arguments.
|
||||
* @param env Optional environment for the new process.
|
||||
*/
|
||||
void spawn(const char *file, char **args, char **env = nullptr) {
|
||||
uv_process_options_t po;
|
||||
|
||||
po.exit_cb = &exitCallback;
|
||||
|
||||
po.file = file;
|
||||
po.args = args;
|
||||
po.env = env;
|
||||
po.cwd = poCwd.empty() ? nullptr : poCwd.data();
|
||||
po.flags = poFlags;
|
||||
po.uid = poUid;
|
||||
po.gid = poGid;
|
||||
|
||||
/**
|
||||
* See the constructor, poFdStdio[0] is stdin. It must be poStdio[0] by
|
||||
* convention. From the official documentation:
|
||||
*
|
||||
* > The convention is that stdio[0] points to stdin, fd 1 is used
|
||||
* > for stdout, and fd 2 is stderr.
|
||||
*/
|
||||
std::vector<uv_stdio_container_t> poStdio{poFdStdio.size() + poStreamStdio.size()};
|
||||
poStdio.insert(poStdio.begin(), poStreamStdio.cbegin(), poStreamStdio.cend());
|
||||
poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());
|
||||
po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
|
||||
po.stdio = poStdio.data();
|
||||
|
||||
invoke(&uv_spawn, parent(), get(), &po);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends the specified signal to the internal process handle.
|
||||
* @param signum A valid signal identifier.
|
||||
*/
|
||||
void kill(int signum) {
|
||||
invoke(&uv_process_kill, get(), signum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the PID of the spawned process.
|
||||
*
|
||||
* It’s set after calling `spawn()`.
|
||||
*
|
||||
* @return The PID of the spawned process.
|
||||
*/
|
||||
int pid() noexcept {
|
||||
return get()->pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the current working directory for the subprocess.
|
||||
* @param path The working directory to be used when `spawn()` is invoked.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
ProcessHandle& cwd(std::string &path) noexcept {
|
||||
poCwd = path;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets flags that control how `spawn()` behaves.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `ProcessHandle::Process::SETUID`
|
||||
* * `ProcessHandle::Process::SETGID`
|
||||
* * `ProcessHandle::Process::WINDOWS_VERBATIM_ARGUMENTS`
|
||||
* * `ProcessHandle::Process::DETACHED`
|
||||
* * `ProcessHandle::Process::WINDOWS_HIDE`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
|
||||
* for further details.
|
||||
*
|
||||
* @param flags A valid set of flags.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
ProcessHandle& flags(Flags<Process> flags) noexcept {
|
||||
poFlags = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes a `stdio` handle available to the child process.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `ProcessHandle::StdIO::IGNORE_STREAM`
|
||||
* * `ProcessHandle::StdIO::CREATE_PIPE`
|
||||
* * `ProcessHandle::StdIO::INHERIT_FD`
|
||||
* * `ProcessHandle::StdIO::INHERIT_STREAM`
|
||||
* * `ProcessHandle::StdIO::READABLE_PIPE`
|
||||
* * `ProcessHandle::StdIO::WRITABLE_PIPE`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
||||
* for further details.
|
||||
*
|
||||
* @param stream A valid `stdio` handle.
|
||||
* @param flags A valid set of flags.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
ProcessHandle& stdio(StreamHandle<T, U> &stream, Flags<StdIO> flags) {
|
||||
uv_stdio_container_t container;
|
||||
Flags<StdIO>::Type fgs = flags;
|
||||
container.flags = static_cast<uv_stdio_flags>(fgs);
|
||||
container.data.stream = get<uv_stream_t>(stream);
|
||||
poStreamStdio.push_back(std::move(container));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes a file descriptor available to the child process.
|
||||
*
|
||||
* Available flags are:
|
||||
*
|
||||
* * `ProcessHandle::StdIO::IGNORE_STREAM`
|
||||
* * `ProcessHandle::StdIO::CREATE_PIPE`
|
||||
* * `ProcessHandle::StdIO::INHERIT_FD`
|
||||
* * `ProcessHandle::StdIO::INHERIT_STREAM`
|
||||
* * `ProcessHandle::StdIO::READABLE_PIPE`
|
||||
* * `ProcessHandle::StdIO::WRITABLE_PIPE`
|
||||
*
|
||||
* Default file descriptors are:
|
||||
* * `uvw::StdIN` for `stdin`
|
||||
* * `uvw::StdOUT` for `stdout`
|
||||
* * `uvw::StdERR` for `stderr`
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
|
||||
* for further details.
|
||||
*
|
||||
* @param fd A valid file descriptor.
|
||||
* @param flags A valid set of flags.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
ProcessHandle& stdio(FileHandle fd, Flags<StdIO> flags) {
|
||||
auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});
|
||||
|
||||
auto actual = FileHandle::Type{fd};
|
||||
|
||||
if(actual == FileHandle::Type{StdIN}) {
|
||||
poFdStdio[0].flags = fgs;
|
||||
} else {
|
||||
auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
|
||||
return container.data.fd == actual;
|
||||
});
|
||||
|
||||
if(it == poFdStdio.cend()) {
|
||||
uv_stdio_container_t container;
|
||||
container.flags = fgs;
|
||||
container.data.fd = actual;
|
||||
poFdStdio.push_back(std::move(container));
|
||||
} else {
|
||||
it->flags = fgs;
|
||||
it->data.fd = actual;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the child process' user id.
|
||||
* @param id A valid user id to be used.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
ProcessHandle& uid(Uid id) {
|
||||
poUid = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the child process' group id.
|
||||
* @param id A valid group id to be used.
|
||||
* @return A reference to this process handle.
|
||||
*/
|
||||
ProcessHandle& gid(Gid id) {
|
||||
poGid = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string poCwd;
|
||||
Flags<Process> poFlags;
|
||||
std::vector<uv_stdio_container_t> poFdStdio;
|
||||
std::vector<uv_stdio_container_t> poStreamStdio;
|
||||
Uid poUid;
|
||||
Gid poGid;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
107
src/uvw/process.ipp
Normal file
107
src/uvw/process.ipp
Normal file
@ -0,0 +1,107 @@
|
||||
#include <algorithm>
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE exit_event::exit_event(int64_t code, int sig) noexcept
|
||||
: status{code}, signal{sig} {}
|
||||
|
||||
UVW_INLINE void process_handle::exit_callback(uv_process_t *hndl, int64_t exit_status, int term_signal) {
|
||||
process_handle &process = *(static_cast<process_handle *>(hndl->data));
|
||||
process.publish(exit_event{exit_status, term_signal});
|
||||
}
|
||||
|
||||
UVW_INLINE process_handle::process_handle(loop::token token, std::shared_ptr<loop> ref)
|
||||
: handle{token, std::move(ref)} {}
|
||||
|
||||
UVW_INLINE void process_handle::disable_stdio_inheritance() noexcept {
|
||||
uv_disable_stdio_inheritance();
|
||||
}
|
||||
|
||||
UVW_INLINE bool process_handle::kill(int pid, int signum) noexcept {
|
||||
return (0 == uv_kill(pid, signum));
|
||||
}
|
||||
|
||||
UVW_INLINE int process_handle::init() {
|
||||
// deferred initialization: libuv initializes process handles only when
|
||||
// uv_spawn is invoked and uvw stays true to the underlying library
|
||||
return 0;
|
||||
}
|
||||
|
||||
UVW_INLINE int process_handle::spawn(const char *file, char **args, char **env) {
|
||||
uv_process_options_t po;
|
||||
|
||||
po.exit_cb = &exit_callback;
|
||||
po.file = file;
|
||||
po.args = args;
|
||||
po.env = env;
|
||||
po.cwd = po_cwd.empty() ? nullptr : po_cwd.data();
|
||||
po.flags = static_cast<uv_process_flags>(po_flags);
|
||||
po.uid = po_uid;
|
||||
po.gid = po_gid;
|
||||
|
||||
std::vector<uv_stdio_container_t> poStdio;
|
||||
poStdio.reserve(po_fd_stdio.size() + po_stream_stdio.size());
|
||||
poStdio.insert(poStdio.begin(), po_fd_stdio.cbegin(), po_fd_stdio.cend());
|
||||
poStdio.insert(poStdio.end(), po_stream_stdio.cbegin(), po_stream_stdio.cend());
|
||||
|
||||
po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
|
||||
po.stdio = poStdio.data();
|
||||
|
||||
// see init member function for more details
|
||||
static_cast<void>(leak_if(0));
|
||||
|
||||
return uv_spawn(parent().raw(), raw(), &po);
|
||||
}
|
||||
|
||||
UVW_INLINE int process_handle::kill(int signum) {
|
||||
return uv_process_kill(raw(), signum);
|
||||
}
|
||||
|
||||
UVW_INLINE int process_handle::pid() noexcept {
|
||||
return raw()->pid;
|
||||
}
|
||||
|
||||
UVW_INLINE process_handle &process_handle::cwd(const std::string &path) noexcept {
|
||||
po_cwd = path;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UVW_INLINE process_handle &process_handle::flags(process_flags flags) noexcept {
|
||||
po_flags = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UVW_INLINE process_handle &process_handle::stdio(file_handle fd, stdio_flags flags) {
|
||||
auto fgs = static_cast<uv_stdio_flags>(flags);
|
||||
|
||||
auto actual = uvw::file_handle{fd};
|
||||
|
||||
auto it = std::find_if(po_fd_stdio.begin(), po_fd_stdio.end(), [actual](auto &&container) {
|
||||
return static_cast<const uvw::details::uv_type_wrapper<int>>(container.data.fd) == static_cast<const uvw::details::uv_type_wrapper<int>>(actual);
|
||||
});
|
||||
|
||||
if(it == po_fd_stdio.cend()) {
|
||||
uv_stdio_container_t container;
|
||||
container.flags = fgs;
|
||||
container.data.fd = actual;
|
||||
po_fd_stdio.push_back(container);
|
||||
} else {
|
||||
it->flags = fgs;
|
||||
it->data.fd = actual;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
UVW_INLINE process_handle &process_handle::uid(uid_type id) {
|
||||
po_uid = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UVW_INLINE process_handle &process_handle::gid(gid_type id) {
|
||||
po_gid = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
@ -1,76 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef UVW_REQUEST_INCLUDE_H
|
||||
#define UVW_REQUEST_INCLUDE_H
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "resource.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
template<typename T, typename U>
|
||||
class Request: public Resource<T, U> {
|
||||
/**
|
||||
* @brief Request base class.
|
||||
*
|
||||
* Base type for all `uvw` request types.
|
||||
*/
|
||||
template<typename T, typename U, typename... E>
|
||||
class request: public resource<T, U, E...> {
|
||||
protected:
|
||||
static auto reserve(U *req) {
|
||||
auto ptr = static_cast<T*>(req->data)->shared_from_this();
|
||||
ptr->reset();
|
||||
[[nodiscard]] static auto reserve(U *req) {
|
||||
auto ptr = static_cast<T *>(req->data)->shared_from_this();
|
||||
ptr->self_reset();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
static void defaultCallback(U *req, int status) {
|
||||
auto ptr = reserve(req);
|
||||
if(status) { ptr->publish(ErrorEvent{status}); }
|
||||
else { ptr->publish(E{}); }
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
auto invoke(F &&f, Args&&... args)
|
||||
-> std::enable_if_t<not std::is_void<std::result_of_t<F(Args...)>>::value, int> {
|
||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
||||
else { this->leak(); }
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
auto invoke(F &&f, Args&&... args)
|
||||
-> std::enable_if_t<std::is_void<std::result_of_t<F(Args...)>>::value> {
|
||||
std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
this->leak();
|
||||
}
|
||||
|
||||
public:
|
||||
using Resource<T, U>::Resource;
|
||||
using resource<T, U, E...>::resource;
|
||||
|
||||
/**
|
||||
* @brief Cancels a pending request.
|
||||
*
|
||||
* This method fails if the request is executing or has finished
|
||||
* executing.<br/>
|
||||
* It can emit an ErrorEvent event in case of errors.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
|
||||
* for further details.
|
||||
*
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool cancel() {
|
||||
return (0 == uv_cancel(this->template get<uv_req_t>()));
|
||||
* @brief Cancels a pending request.
|
||||
*
|
||||
* This method fails if the request is executing or has finished
|
||||
* executing.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel)
|
||||
* for further details.
|
||||
*
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int cancel() {
|
||||
return uv_cancel(reinterpret_cast<uv_req_t *>(this->raw()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the underlying request type.
|
||||
* @return The size of the underlying request type.
|
||||
*/
|
||||
std::size_t size() const noexcept {
|
||||
return uv_req_size(this->template get<uv_req_t>()->type);
|
||||
* @brief Returns the size of the underlying request type.
|
||||
* @return The size of the underlying request type.
|
||||
*/
|
||||
[[nodiscard]] std::size_t size() const noexcept {
|
||||
return uv_req_size(reinterpret_cast<const uv_req_t *>(this->raw())->type);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
}
|
||||
#endif // UVW_REQUEST_INCLUDE_H
|
||||
|
||||
@ -1,135 +1,66 @@
|
||||
#pragma once
|
||||
#ifndef UVW_RESOURCE_INCLUDE_H
|
||||
#define UVW_RESOURCE_INCLUDE_H
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "emitter.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include "config.h"
|
||||
#include "emitter.h"
|
||||
#include "uv_type.hpp"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Common class for almost all the resources available in `uvw`.
|
||||
*
|
||||
* This is the base class for handles and requests.<br/>
|
||||
* It mainly acts as a wrapper around a data structure of `libuv`.
|
||||
* This is the base class for handles and requests.
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
class Resource: public Emitter<T>, public std::enable_shared_from_this<T> {
|
||||
template<typename, typename>
|
||||
friend class Resource;
|
||||
|
||||
template<typename T, typename U, typename... E>
|
||||
class resource: public uv_type<U>, public emitter<T, E...>, public std::enable_shared_from_this<T> {
|
||||
protected:
|
||||
struct ConstructorAccess { explicit ConstructorAccess(int) {} };
|
||||
[[nodiscard]] int leak_if(int err) noexcept {
|
||||
if(err == 0) {
|
||||
self_ptr = this->shared_from_this();
|
||||
}
|
||||
|
||||
auto parent() const noexcept {
|
||||
return pLoop->loop.get();
|
||||
return err;
|
||||
}
|
||||
|
||||
auto get() noexcept {
|
||||
return &resource;
|
||||
void self_reset() noexcept {
|
||||
self_ptr.reset();
|
||||
}
|
||||
|
||||
auto get() const noexcept {
|
||||
return const_cast<const U *>(&resource);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
auto get() noexcept {
|
||||
static_assert(not std::is_same<R, U>::value, "!");
|
||||
return reinterpret_cast<R *>(&resource);
|
||||
}
|
||||
|
||||
template<typename R, typename... P>
|
||||
auto get(Resource<P...> &res) noexcept {
|
||||
return reinterpret_cast<R *>(&res.resource);
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
auto get() const noexcept {
|
||||
static_assert(not std::is_same<R, U>::value, "!");
|
||||
return reinterpret_cast<const R *>(&resource);
|
||||
}
|
||||
|
||||
template<typename R, typename... P>
|
||||
auto get(const Resource<P...> &res) const noexcept {
|
||||
return reinterpret_cast<const R *>(&res.resource);
|
||||
}
|
||||
|
||||
void leak() noexcept {
|
||||
sPtr = this->shared_from_this();
|
||||
}
|
||||
|
||||
void reset() noexcept {
|
||||
sPtr.reset();
|
||||
}
|
||||
|
||||
bool self() const noexcept {
|
||||
return static_cast<bool>(sPtr);
|
||||
[[nodiscard]] bool has_self() const noexcept {
|
||||
return static_cast<bool>(self_ptr);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Resource(ConstructorAccess, std::shared_ptr<Loop> ref)
|
||||
: Emitter<T>{},
|
||||
std::enable_shared_from_this<T>{},
|
||||
pLoop{std::move(ref)},
|
||||
resource{}
|
||||
{
|
||||
resource.data = static_cast<T*>(this);
|
||||
explicit resource(loop::token token, std::shared_ptr<loop> ref)
|
||||
: uv_type<U>{token, std::move(ref)} {
|
||||
this->raw()->data = this;
|
||||
}
|
||||
|
||||
Resource(const Resource &) = delete;
|
||||
Resource(Resource &&) = delete;
|
||||
|
||||
virtual ~Resource() {
|
||||
static_assert(std::is_base_of<Resource<T, U>, T>::value, "!");
|
||||
}
|
||||
|
||||
Resource& operator=(const Resource &) = delete;
|
||||
Resource& operator=(Resource &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Creates a new resource of the given type.
|
||||
* @param args Arguments to be forwarded to the actual constructor (if any).
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename... Args>
|
||||
static std::shared_ptr<T> create(Args&&... args) {
|
||||
return std::make_shared<T>(ConstructorAccess{0}, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the loop from which the resource was originated.
|
||||
* @return A reference to a loop instance.
|
||||
*/
|
||||
Loop& loop() const noexcept { return *pLoop; }
|
||||
|
||||
/**
|
||||
* @brief Gets user-defined data. `uvw` won't use this field in any case.
|
||||
* @return User-defined data if any, an invalid pointer otherwise.
|
||||
*/
|
||||
template<typename R = void>
|
||||
std::shared_ptr<R> data() const {
|
||||
return std::static_pointer_cast<R>(userData);
|
||||
[[nodiscard]] std::shared_ptr<R> data() const {
|
||||
return std::static_pointer_cast<R>(user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets arbitrary data. `uvw` won't use this field in any case.
|
||||
* @param uData User-defined arbitrary data.
|
||||
* @param udata User-defined arbitrary data.
|
||||
*/
|
||||
void data(std::shared_ptr<void> uData) {
|
||||
userData = std::move(uData);
|
||||
void data(std::shared_ptr<void> udata) {
|
||||
user_data = std::move(udata);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<void> userData{nullptr};
|
||||
std::shared_ptr<void> sPtr{nullptr};
|
||||
std::shared_ptr<Loop> pLoop;
|
||||
U resource;
|
||||
std::shared_ptr<void> user_data{nullptr};
|
||||
std::shared_ptr<void> self_ptr{nullptr};
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
}
|
||||
#endif // UVW_RESOURCE_INCLUDE_H
|
||||
|
||||
2
src/uvw/signal.cpp
Normal file
2
src/uvw/signal.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "signal.h"
|
||||
#include "signal.ipp"
|
||||
83
src/uvw/signal.h
Normal file
83
src/uvw/signal.h
Normal file
@ -0,0 +1,83 @@
|
||||
#ifndef UVW_SIGNAL_INCLUDE_H
|
||||
#define UVW_SIGNAL_INCLUDE_H
|
||||
|
||||
#include <uv.h>
|
||||
#include "config.h"
|
||||
#include "handle.hpp"
|
||||
#include "loop.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
/*! @brief Signal event. */
|
||||
struct signal_event {
|
||||
explicit signal_event(int sig) noexcept;
|
||||
|
||||
int signum; /*!< The signal being monitored by this handle. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The signal handle.
|
||||
*
|
||||
* Signal handles implement Unix style signal handling on a per-event loop
|
||||
* bases.<br/>
|
||||
* Reception of some signals is emulated on Windows.
|
||||
*
|
||||
* To create a `signal_handle` through a `loop`, no arguments are required.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/signal.html)
|
||||
* for further details.
|
||||
*/
|
||||
class signal_handle final: public handle<signal_handle, uv_signal_t, signal_event> {
|
||||
static void start_callback(uv_signal_t *hndl, int signum);
|
||||
|
||||
public:
|
||||
using handle::handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int init();
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* The handle will start emitting signal events when needed.
|
||||
*
|
||||
* @param signum The signal to be monitored.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int start(int signum);
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* Same functionality as signal_handle::start but the signal handler is
|
||||
* reset the moment the signal is received.
|
||||
*
|
||||
* @param signum The signal to be monitored.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int one_shot(int signum);
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
* @return Underlying return value.
|
||||
*/
|
||||
int stop();
|
||||
|
||||
/**
|
||||
* @brief Gets the signal being monitored.
|
||||
* @return The signal being monitored.
|
||||
*/
|
||||
int signal() const noexcept;
|
||||
};
|
||||
|
||||
} // namespace uvw
|
||||
|
||||
#ifndef UVW_AS_LIB
|
||||
# include "signal.ipp"
|
||||
#endif
|
||||
|
||||
#endif // UVW_SIGNAL_INCLUDE_H
|
||||
@ -1,96 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "handle.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief SignalEvent event.
|
||||
*
|
||||
* It will be emitted by SignalHandle according with its functionalities.
|
||||
*/
|
||||
struct SignalEvent {
|
||||
explicit SignalEvent(int sig) noexcept: signum{sig} {}
|
||||
|
||||
int signum; /*!< The signal being monitored by this handle. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The SignalHandle handle.
|
||||
*
|
||||
* Signal handles implement Unix style signal handling on a per-event loop
|
||||
* bases.<br/>
|
||||
* Reception of some signals is emulated on Windows.
|
||||
*
|
||||
* To create a `SignalHandle` through a `Loop`, no arguments are required.
|
||||
*
|
||||
* See the official
|
||||
* [documentation](http://docs.libuv.org/en/v1.x/signal.html)
|
||||
* for further details.
|
||||
*/
|
||||
class SignalHandle final: public Handle<SignalHandle, uv_signal_t> {
|
||||
static void startCallback(uv_signal_t *handle, int signum) {
|
||||
SignalHandle &signal = *(static_cast<SignalHandle*>(handle->data));
|
||||
signal.publish(SignalEvent{signum});
|
||||
}
|
||||
|
||||
public:
|
||||
using Handle::Handle;
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize(&uv_signal_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* The handle will start emitting SignalEvent when needed.
|
||||
*
|
||||
* @param signum The signal to be monitored.
|
||||
*/
|
||||
void start(int signum) {
|
||||
invoke(&uv_signal_start, get(), &startCallback, signum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the handle.
|
||||
*
|
||||
* Same functionality as SignalHandle::start but the signal handler is reset
|
||||
* the moment the signal is received.
|
||||
*
|
||||
* @param signum
|
||||
*/
|
||||
void oneShot(int signum) {
|
||||
invoke(&uv_signal_start_oneshot, get(), &startCallback, signum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_signal_stop, get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the signal being monitored.
|
||||
* @return The signal being monitored.
|
||||
*/
|
||||
int signal() const noexcept {
|
||||
return get()->signum;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
33
src/uvw/signal.ipp
Normal file
33
src/uvw/signal.ipp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace uvw {
|
||||
|
||||
UVW_INLINE signal_event::signal_event(int sig) noexcept
|
||||
: signum{sig} {}
|
||||
|
||||
UVW_INLINE void signal_handle::start_callback(uv_signal_t *hndl, int signum) {
|
||||
signal_handle &signal = *(static_cast<signal_handle *>(hndl->data));
|
||||
signal.publish(signal_event{signum});
|
||||
}
|
||||
|
||||
UVW_INLINE int signal_handle::init() {
|
||||
return leak_if(uv_signal_init(parent().raw(), raw()));
|
||||
}
|
||||
|
||||
UVW_INLINE int signal_handle::start(int signum) {
|
||||
return uv_signal_start(raw(), &start_callback, signum);
|
||||
}
|
||||
|
||||
UVW_INLINE int signal_handle::one_shot(int signum) {
|
||||
return uv_signal_start_oneshot(raw(), &start_callback, signum);
|
||||
}
|
||||
|
||||
UVW_INLINE int signal_handle::stop() {
|
||||
return uv_signal_stop(raw());
|
||||
}
|
||||
|
||||
UVW_INLINE int signal_handle::signal() const noexcept {
|
||||
return raw()->signum;
|
||||
}
|
||||
|
||||
} // namespace uvw
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user