Merge pull request #30 from cynnyx/master

WIP: Fs
This commit is contained in:
Michele Caini 2016-07-27 20:14:32 +02:00 committed by GitHub
commit c6419e186f
9 changed files with 344 additions and 225 deletions

View File

@ -34,6 +34,9 @@ struct Event: BaseEvent {
struct ErrorEvent: Event<ErrorEvent> { struct ErrorEvent: Event<ErrorEvent> {
explicit ErrorEvent(int code = 0) noexcept: ec(code) { } explicit ErrorEvent(int code = 0) noexcept: ec(code) { }
template<typename U, typename = std::enable_if_t<std::is_convertible<U, int>::value>>
explicit ErrorEvent(U val) noexcept: ec{static_cast<int>(val)} { }
const char * what() const noexcept { return uv_strerror(ec); } const char * what() const noexcept { return uv_strerror(ec); }
int code() const noexcept { return ec; } int code() const noexcept { return ec; }

View File

@ -70,8 +70,48 @@ template<details::UVFsType e>
struct TypedEvent<details::UVFsType, e> struct TypedEvent<details::UVFsType, e>
: Event<TypedEvent<details::UVFsType, e>> : Event<TypedEvent<details::UVFsType, e>>
{ {
using Type = details::UVFsType; TypedEvent(const char *p) noexcept
static constexpr details::UVFsType value = e; : rPath{p}
{ }
const char * path() const noexcept { return rPath; }
private:
const char *rPath;
};
template<>
struct TypedEvent<details::UVFsType, details::UVFsType::WRITE>
: Event<TypedEvent<details::UVFsType, details::UVFsType::WRITE>>
{
TypedEvent(const char *p, ssize_t s) noexcept
: rPath{p}, sz{s}
{ }
const char * path() const noexcept { return rPath; }
ssize_t amount() const noexcept { return sz; }
private:
const char *rPath;
const ssize_t sz;
};
template<>
struct TypedEvent<details::UVFsType, details::UVFsType::SENDFILE>
: Event<TypedEvent<details::UVFsType, details::UVFsType::SENDFILE>>
{
TypedEvent(const char *p, ssize_t s) noexcept
: rPath{p}, sz{s}
{ }
const char * path() const noexcept { return rPath; }
ssize_t amount() const noexcept { return sz; }
private:
const char *rPath;
const ssize_t sz;
}; };
@ -79,14 +119,15 @@ template<>
struct TypedEvent<details::UVFsType, details::UVFsType::STAT> struct TypedEvent<details::UVFsType, details::UVFsType::STAT>
: Event<TypedEvent<details::UVFsType, details::UVFsType::STAT>> : Event<TypedEvent<details::UVFsType, details::UVFsType::STAT>>
{ {
using Type = details::UVFsType; TypedEvent(const char *p, const Stat &s) noexcept
static constexpr details::UVFsType value = details::UVFsType::STAT; : rPath{p}, fsStat{s}
{ }
TypedEvent(const Stat &s): fsStat{s} { }
const char * path() const noexcept { return rPath; }
const Stat & stat() const noexcept { return fsStat; } const Stat & stat() const noexcept { return fsStat; }
private: private:
const char *rPath;
Stat fsStat; Stat fsStat;
}; };
@ -95,14 +136,15 @@ template<>
struct TypedEvent<details::UVFsType, details::UVFsType::FSTAT> struct TypedEvent<details::UVFsType, details::UVFsType::FSTAT>
: Event<TypedEvent<details::UVFsType, details::UVFsType::FSTAT>> : Event<TypedEvent<details::UVFsType, details::UVFsType::FSTAT>>
{ {
using Type = details::UVFsType; TypedEvent(const char *p, const Stat &s) noexcept
static constexpr details::UVFsType value = details::UVFsType::FSTAT; : rPath{p}, fsStat{s}
{ }
TypedEvent(const Stat &s): fsStat{s} { }
const char * path() const noexcept { return rPath; }
const Stat & stat() const noexcept { return fsStat; } const Stat & stat() const noexcept { return fsStat; }
private: private:
const char *rPath;
Stat fsStat; Stat fsStat;
}; };
@ -111,71 +153,129 @@ template<>
struct TypedEvent<details::UVFsType, details::UVFsType::LSTAT> struct TypedEvent<details::UVFsType, details::UVFsType::LSTAT>
: Event<TypedEvent<details::UVFsType, details::UVFsType::LSTAT>> : Event<TypedEvent<details::UVFsType, details::UVFsType::LSTAT>>
{ {
using Type = details::UVFsType; TypedEvent(const char *p, const Stat &s) noexcept
static constexpr details::UVFsType value = details::UVFsType::LSTAT; : rPath{p}, fsStat{s}
{ }
TypedEvent(const Stat &s): fsStat{s} { }
const char * path() const noexcept { return rPath; }
const Stat & stat() const noexcept { return fsStat; } const Stat & stat() const noexcept { return fsStat; }
private: private:
const char *rPath;
Stat fsStat; Stat fsStat;
}; };
template<>
struct TypedEvent<details::UVFsType, details::UVFsType::SCANDIR>
: Event<TypedEvent<details::UVFsType, details::UVFsType::SCANDIR>>
{
TypedEvent(const char *p, ssize_t s) noexcept
: rPath{p}, sz{s}
{ }
const char * path() const noexcept { return rPath; }
ssize_t amount() const noexcept { return sz; }
private:
const char *rPath;
const ssize_t sz;
};
template<>
struct TypedEvent<details::UVFsType, details::UVFsType::READLINK>
: Event<TypedEvent<details::UVFsType, details::UVFsType::READLINK>>
{
explicit TypedEvent(const char *p, const char *d, ssize_t l) noexcept
: rPath{p}, dt{d}, len{l}
{ }
const char * path() const noexcept { return rPath; }
const char * data() const noexcept { return dt; }
ssize_t length() const noexcept { return len; }
private:
const char *rPath;
const char *dt;
const ssize_t len;
};
template<details::UVFsType e> template<details::UVFsType e>
using FsEvent = TypedEvent<details::UVFsType, e>; using FsEvent = TypedEvent<details::UVFsType, e>;
class Fs final: public Request<Fs, uv_fs_t> { class Fs final: public Request<Fs, uv_fs_t> {
template<details::UVFsType e> static constexpr int BAD_FD = -1;
static void fsGenericCallback(uv_fs_t *req) {
Fs &fs = *(static_cast<Fs*>(req->data));
auto ptr = fs.shared_from_this(); static void fsCloseCallback(uv_fs_t *req) {
(void)ptr; auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
fs.reset();
if(req->result) { if(req->result) {
int err = req->result; ptr->publish(ErrorEvent{req->result});
fs.publish(ErrorEvent{err});
} else { } else {
fs.publish(FsEvent<e>{}); ptr->file = BAD_FD;
ptr->publish(FsEvent<Type::CLOSE>{req->path});
} }
} }
static void fsOpenCallback(uv_fs_t *req) {
auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
if(req->result < 0) {
ptr->publish(ErrorEvent{req->result});
} else {
ptr->file = req->result;
ptr->publish(FsEvent<Type::OPEN>{req->path});
}
}
template<details::UVFsType e>
static void fsGenericCallback(uv_fs_t *req) {
auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
if(req->result) { ptr->publish(ErrorEvent{req->result}); }
else { ptr->publish(FsEvent<e>{req->path}); }
}
static void fsReadCallback(uv_fs_t *req) { static void fsReadCallback(uv_fs_t *req) {
// TODO - uv_fs_read callback // TODO - uv_fs_read callback
} }
static void fsWriteCallback(uv_fs_t *req) { template<details::UVFsType e>
// TODO - uv_fs_write callback static void fsResultCallback(uv_fs_t *req) {
auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
else { ptr->publish(FsEvent<e>{req->path, req->result}); }
} }
template<details::UVFsType e> template<details::UVFsType e>
static void fsStatCallback(uv_fs_t *req) { static void fsStatCallback(uv_fs_t *req) {
Fs &fs = *(static_cast<Fs*>(req->data)); auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
if(req->result) { ptr->publish(ErrorEvent{req->result}); }
auto ptr = fs.shared_from_this(); else { ptr->publish(FsEvent<e>{req->path, req->statbuf}); }
(void)ptr;
fs.reset();
if(req->result) {
int err = req->result;
fs.publish(ErrorEvent{err});
} else {
fs.publish(FsEvent<e>{req->statbuf});
}
} }
static void fsReadlinkCallback(uv_fs_t *req) { static void fsReadlinkCallback(uv_fs_t *req) {
// TODO - uv_fs_readlink callback auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
else { ptr->publish(FsEvent<Type::READLINK>{req->path, static_cast<char *>(req->ptr), req->result}); }
} }
using Request::Request; using Request::Request;
template<typename... Args>
void cleanupAndInvoke(Args&&... args) {
uv_fs_req_cleanup(get<uv_fs_t>());
invoke(std::forward<Args>(args)...);
}
template<typename F, typename... Args>
void cleanupAndInvokeSync(F &&f, Args&&... args) {
uv_fs_req_cleanup(get<uv_fs_t>());
std::forward<F>(f)(std::forward<Args>(args)...);
}
public: public:
using Time = std::chrono::seconds; using Time = std::chrono::seconds;
using Type = details::UVFsType; using Type = details::UVFsType;
@ -191,86 +291,99 @@ public:
uv_fs_req_cleanup(get<uv_fs_t>()); uv_fs_req_cleanup(get<uv_fs_t>());
} }
void close(FileHandle file) { void close() {
invoke(&uv_fs_close, parent(), get<uv_fs_t>(), file, &fsGenericCallback<Type::CLOSE>); cleanupAndInvoke(&uv_fs_close, parent(), get<uv_fs_t>(), file, &fsCloseCallback);
} }
auto closeSync(FileHandle file) { auto closeSync() {
auto err = uv_fs_close(parent(), get<uv_fs_t>(), file, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::CLOSE>{}); cleanupAndInvokeSync(&uv_fs_close, parent(), req, file, nullptr);
if(!req->result) { file = BAD_FD; }
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::CLOSE>{req->path});
} }
void open(std::string path, int flags, int mode) { void open(std::string path, int flags, int mode) {
invoke(&uv_fs_open, parent(), get<uv_fs_t>(), path.data(), flags, mode, &fsGenericCallback<Type::OPEN>); cleanupAndInvoke(&uv_fs_open, parent(), get<uv_fs_t>(), path.data(), flags, mode, &fsOpenCallback);
} }
auto openSync(std::string path, int flags, int mode) { auto openSync(std::string path, int flags, int mode) {
auto err = uv_fs_open(parent(), get<uv_fs_t>(), path.data(), flags, mode, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::OPEN>{}); cleanupAndInvokeSync(&uv_fs_open, parent(), req, path.data(), flags, mode, nullptr);
auto fd = req->result;
if(fd >= 0) { file = fd; }
return std::make_pair(ErrorEvent{fd < 0 ? fd : 0}, FsEvent<Type::OPEN>{req->path});
} }
// TODO uv_fs_read (sync (cb null)/async) void read(int64_t offset, unsigned int len) {
// TODO uv_fs_read (async)
}
auto readSync(int64_t offset, unsigned int len) {
// TODO uv_fs_read (sync (cb null))
}
void unlink(std::string path) { void unlink(std::string path) {
invoke(&uv_fs_unlink, parent(), get<uv_fs_t>(), path.data(), &fsGenericCallback<Type::UNLINK>); cleanupAndInvoke(&uv_fs_unlink, parent(), get<uv_fs_t>(), path.data(), &fsGenericCallback<Type::UNLINK>);
} }
auto unlinkSync(std::string path) { auto unlinkSync(std::string path) {
auto err = uv_fs_unlink(parent(), get<uv_fs_t>(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::UNLINK>{}); cleanupAndInvokeSync(&uv_fs_unlink, parent(), req, path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::UNLINK>{req->path});
} }
void write(FileHandle file, char *data, ssize_t len, int64_t offset) { void write(std::unique_ptr<char[]> data, ssize_t len, int64_t offset) {
uv_buf_t bufs[] = { uv_buf_init(data, len) }; uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
invoke(&uv_fs_write, parent(), get<uv_fs_t>(), file, bufs, 1, offset, &fsWriteCallback); cleanupAndInvoke(&uv_fs_write, parent(), get<uv_fs_t>(), file, bufs, 1, offset, &fsResultCallback<Type::WRITE>);
} }
void write(FileHandle file, std::unique_ptr<char[]> data, ssize_t len, int64_t offset) { auto writeSync(std::unique_ptr<char[]> data, ssize_t len, int64_t offset) {
write(file, data.get(), len, offset); uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
} auto req = get<uv_fs_t>();
cleanupAndInvokeSync(&uv_fs_write, parent(), get<uv_fs_t>(), file, bufs, 1, offset, nullptr);
auto writeSync(FileHandle file, char *data, ssize_t len, int64_t offset) { auto bw = req->result;
// TODO uv_fs_write (sync (cb null)) return std::make_pair(ErrorEvent{bw < 0 ? bw : 0}, FsEvent<Type::WRITE>{req->path, bw});
}
auto writeSync(FileHandle file, std::unique_ptr<char[]> data, ssize_t len, int64_t offset) {
// TODO uv_fs_write (sync (cb null))
} }
void mkdir(std::string path, int mode) { void mkdir(std::string path, int mode) {
invoke(&uv_fs_mkdir, parent(), get<uv_fs_t>(), path.data(), mode, &fsGenericCallback<Type::MKDIR>); cleanupAndInvoke(&uv_fs_mkdir, parent(), get<uv_fs_t>(), path.data(), mode, &fsGenericCallback<Type::MKDIR>);
} }
auto mkdirSync(std::string path, int mode) { auto mkdirSync(std::string path, int mode) {
auto err = uv_fs_mkdir(parent(), get<uv_fs_t>(), path.data(), mode, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::MKDIR>{}); cleanupAndInvokeSync(&uv_fs_mkdir, parent(), req, path.data(), mode, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::MKDIR>{req->path});
} }
void mkdtemp(std::string tpl) { void mkdtemp(std::string tpl) {
invoke(&uv_fs_mkdtemp, parent(), get<uv_fs_t>(), tpl.data(), &fsGenericCallback<Type::MKDTEMP>); cleanupAndInvoke(&uv_fs_mkdtemp, parent(), get<uv_fs_t>(), tpl.data(), &fsGenericCallback<Type::MKDTEMP>);
} }
auto mkdtempSync(std::string tpl) { auto mkdtempSync(std::string tpl) {
auto err = uv_fs_mkdtemp(parent(), get<uv_fs_t>(), tpl.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::MKDTEMP>{}); cleanupAndInvokeSync(&uv_fs_mkdtemp, parent(), req, tpl.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::MKDTEMP>{req->path});
} }
void rmdir(std::string path) { void rmdir(std::string path) {
invoke(&uv_fs_rmdir, parent(), get<uv_fs_t>(), path.data(), &fsGenericCallback<Type::RMDIR>); cleanupAndInvoke(&uv_fs_rmdir, parent(), get<uv_fs_t>(), path.data(), &fsGenericCallback<Type::RMDIR>);
} }
auto rmdirSync(std::string path) { auto rmdirSync(std::string path) {
auto err = uv_fs_rmdir(parent(), get<uv_fs_t>(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::RMDIR>{}); cleanupAndInvokeSync(&uv_fs_rmdir, parent(), req, path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::RMDIR>{req->path});
} }
void scandir(std::string path, int flags) { void scandir(std::string path, int flags) {
invoke(&uv_fs_scandir, parent(), get<uv_fs_t>(), path.data(), flags, &fsGenericCallback<Type::SCANDIR>); cleanupAndInvoke(&uv_fs_scandir, parent(), get<uv_fs_t>(), path.data(), flags, &fsResultCallback<Type::SCANDIR>);
} }
auto scandirSync(std::string path, int flags) { auto scandirSync(std::string path, int flags) {
auto err = uv_fs_scandir(parent(), get<uv_fs_t>(), path.data(), flags, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::SCANDIR>{}); cleanupAndInvokeSync(&uv_fs_scandir, parent(), req, path.data(), flags, nullptr);
auto sz = req->result;
return std::make_pair(ErrorEvent{sz < 0 ? sz : 0}, FsEvent<Type::SCANDIR>{req->path, sz});
} }
std::pair<bool, Entry> scandirNext() { std::pair<bool, Entry> scandirNext() {
@ -288,172 +401,201 @@ public:
} }
void stat(std::string path) { void stat(std::string path) {
invoke(&uv_fs_stat, parent(), get<uv_fs_t>(), path.data(), &fsStatCallback<Type::STAT>); cleanupAndInvoke(&uv_fs_stat, parent(), get<uv_fs_t>(), path.data(), &fsStatCallback<Type::STAT>);
} }
auto statSync(std::string path) { auto statSync(std::string path) {
auto err = uv_fs_stat(parent(), get<uv_fs_t>(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::STAT>{get<uv_fs_t>()->statbuf}); cleanupAndInvokeSync(&uv_fs_stat, parent(), req, path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::STAT>{req->path, req->statbuf});
} }
void fstat(FileHandle file) { void fstat() {
invoke(&uv_fs_fstat, parent(), get<uv_fs_t>(), file, &fsStatCallback<Type::FSTAT>); cleanupAndInvoke(&uv_fs_fstat, parent(), get<uv_fs_t>(), file, &fsStatCallback<Type::FSTAT>);
} }
auto fstatSync(FileHandle file) { auto fstatSync() {
auto err = uv_fs_fstat(parent(), get<uv_fs_t>(), file, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FSTAT>{get<uv_fs_t>()->statbuf}); cleanupAndInvokeSync(&uv_fs_fstat, parent(), req, file, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FSTAT>{req->path, req->statbuf});
} }
void lstat(std::string path) { void lstat(std::string path) {
invoke(&uv_fs_lstat, parent(), get<uv_fs_t>(), path.data(), &fsStatCallback<Type::LSTAT>); cleanupAndInvoke(&uv_fs_lstat, parent(), get<uv_fs_t>(), path.data(), &fsStatCallback<Type::LSTAT>);
} }
auto lstatSync(std::string path) { auto lstatSync(std::string path) {
auto err = uv_fs_lstat(parent(), get<uv_fs_t>(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::LSTAT>{get<uv_fs_t>()->statbuf}); cleanupAndInvokeSync(&uv_fs_lstat, parent(), req, path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::LSTAT>{req->path, req->statbuf});
} }
void rename(std::string old, std::string path) { void rename(std::string old, std::string path) {
invoke(&uv_fs_rename, parent(), get<uv_fs_t>(), old.data(), path.data(), &fsGenericCallback<Type::RENAME>); cleanupAndInvoke(&uv_fs_rename, parent(), get<uv_fs_t>(), old.data(), path.data(), &fsGenericCallback<Type::RENAME>);
} }
auto renameSync(std::string old, std::string path) { auto renameSync(std::string old, std::string path) {
auto err = uv_fs_rename(parent(), get<uv_fs_t>(), old.data(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::RENAME>{}); cleanupAndInvokeSync(&uv_fs_rename, parent(), req, old.data(), path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::RENAME>{req->path});
} }
void fsync(FileHandle file) { void fsync() {
invoke(&uv_fs_fsync, parent(), get<uv_fs_t>(), file, &fsGenericCallback<Type::FSYNC>); cleanupAndInvoke(&uv_fs_fsync, parent(), get<uv_fs_t>(), file, &fsGenericCallback<Type::FSYNC>);
} }
auto fsyncSync(FileHandle file) { auto fsyncSync() {
auto err = uv_fs_fsync(parent(), get<uv_fs_t>(), file, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FSYNC>{}); cleanupAndInvokeSync(&uv_fs_fsync, parent(), req, file, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FSYNC>{req->path});
} }
void fdatasync(FileHandle file) { void fdatasync() {
invoke(&uv_fs_fdatasync, parent(), get<uv_fs_t>(), file, &fsGenericCallback<Type::FDATASYNC>); cleanupAndInvoke(&uv_fs_fdatasync, parent(), get<uv_fs_t>(), file, &fsGenericCallback<Type::FDATASYNC>);
} }
auto fdatasyncSync(FileHandle file) { auto fdatasyncSync() {
auto err = uv_fs_fdatasync(parent(), get<uv_fs_t>(), file, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FDATASYNC>{}); cleanupAndInvokeSync(&uv_fs_fdatasync, parent(), req, file, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FDATASYNC>{req->path});
} }
void ftruncate(FileHandle file, int64_t offset) { void ftruncate(int64_t offset) {
invoke(&uv_fs_ftruncate, parent(), get<uv_fs_t>(), file, offset, &fsGenericCallback<Type::FTRUNCATE>); cleanupAndInvoke(&uv_fs_ftruncate, parent(), get<uv_fs_t>(), file, offset, &fsGenericCallback<Type::FTRUNCATE>);
} }
auto ftruncateSync(FileHandle file, int64_t offset) { auto ftruncateSync(int64_t offset) {
auto err = uv_fs_ftruncate(parent(), get<uv_fs_t>(), file, offset, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FTRUNCATE>{}); cleanupAndInvokeSync(&uv_fs_ftruncate, parent(), req, file, offset, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FTRUNCATE>{req->path});
} }
void sendfile(FileHandle out, FileHandle in, int64_t offset, size_t length) { void sendfile(FileHandle out, int64_t offset, size_t length) {
invoke(&uv_fs_sendfile, parent(), get<uv_fs_t>(), out, in, offset, length, &fsGenericCallback<Type::SENDFILE>); cleanupAndInvoke(&uv_fs_sendfile, parent(), get<uv_fs_t>(), out, file, offset, length, &fsResultCallback<Type::SENDFILE>);
} }
auto sendfileSync(FileHandle out, FileHandle in, int64_t offset, size_t length) { auto sendfileSync(FileHandle out, int64_t offset, size_t length) {
auto err = uv_fs_sendfile(parent(), get<uv_fs_t>(), out, in, offset, length, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::SENDFILE>{}); cleanupAndInvokeSync(&uv_fs_sendfile, parent(), req, out, file, offset, length, nullptr);
auto bw = req->result;
return std::make_pair(ErrorEvent{bw < 0 ? bw : 0}, FsEvent<Type::SENDFILE>{req->path, bw});
} }
void access(std::string path, int mode) { void access(std::string path, int mode) {
invoke(&uv_fs_access, parent(), get<uv_fs_t>(), path.data(), mode, &fsGenericCallback<Type::ACCESS>); cleanupAndInvoke(&uv_fs_access, parent(), get<uv_fs_t>(), path.data(), mode, &fsGenericCallback<Type::ACCESS>);
} }
auto accessSync(std::string path, int mode) { auto accessSync(std::string path, int mode) {
auto err = uv_fs_access(parent(), get<uv_fs_t>(), path.data(), mode, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::ACCESS>{}); cleanupAndInvokeSync(&uv_fs_access, parent(), req, path.data(), mode, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::ACCESS>{req->path});
} }
void chmod(std::string path, int mode) { void chmod(std::string path, int mode) {
invoke(&uv_fs_chmod, parent(), get<uv_fs_t>(), path.data(), mode, &fsGenericCallback<Type::CHMOD>); cleanupAndInvoke(&uv_fs_chmod, parent(), get<uv_fs_t>(), path.data(), mode, &fsGenericCallback<Type::CHMOD>);
} }
auto chmodSync(std::string path, int mode) { auto chmodSync(std::string path, int mode) {
auto err = uv_fs_chmod(parent(), get<uv_fs_t>(), path.data(), mode, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::CHMOD>{}); cleanupAndInvokeSync(&uv_fs_chmod, parent(), req, path.data(), mode, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::CHMOD>{req->path});
} }
void fchmod(FileHandle file, int mode) { void fchmod(int mode) {
invoke(&uv_fs_fchmod, parent(), get<uv_fs_t>(), file, mode, &fsGenericCallback<Type::FCHMOD>); cleanupAndInvoke(&uv_fs_fchmod, parent(), get<uv_fs_t>(), file, mode, &fsGenericCallback<Type::FCHMOD>);
} }
auto fchmodSync(FileHandle file, int mode) { auto fchmodSync(int mode) {
auto err = uv_fs_fchmod(parent(), get<uv_fs_t>(), file, mode, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FCHMOD>{}); cleanupAndInvokeSync(&uv_fs_fchmod, parent(), req, file, mode, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FCHMOD>{req->path});
} }
void utime(std::string path, Time atime, Time mtime) { void utime(std::string path, Time atime, Time mtime) {
invoke(&uv_fs_utime, parent(), get<uv_fs_t>(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::UTIME>); cleanupAndInvoke(&uv_fs_utime, parent(), get<uv_fs_t>(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::UTIME>);
} }
auto utimeSync(std::string path, Time atime, Time mtime) { auto utimeSync(std::string path, Time atime, Time mtime) {
auto err = uv_fs_utime(parent(), get<uv_fs_t>(), path.data(), atime.count(), mtime.count(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::UTIME>{}); cleanupAndInvokeSync(&uv_fs_utime, parent(), req, path.data(), atime.count(), mtime.count(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::UTIME>{req->path});
} }
void futime(FileHandle file, Time atime, Time mtime) { void futime(Time atime, Time mtime) {
invoke(&uv_fs_futime, parent(), get<uv_fs_t>(), file, atime.count(), mtime.count(), &fsGenericCallback<Type::FUTIME>); cleanupAndInvoke(&uv_fs_futime, parent(), get<uv_fs_t>(), file, atime.count(), mtime.count(), &fsGenericCallback<Type::FUTIME>);
} }
auto futimeSync(FileHandle file, Time atime, Time mtime) { auto futimeSync(Time atime, Time mtime) {
auto err = uv_fs_futime(parent(), get<uv_fs_t>(), file, atime.count(), mtime.count(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FUTIME>{}); cleanupAndInvokeSync(&uv_fs_futime, parent(), req, file, atime.count(), mtime.count(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FUTIME>{req->path});
} }
void link(std::string old, std::string path) { void link(std::string old, std::string path) {
invoke(&uv_fs_link, parent(), get<uv_fs_t>(), old.data(), path.data(), &fsGenericCallback<Type::LINK>); cleanupAndInvoke(&uv_fs_link, parent(), get<uv_fs_t>(), old.data(), path.data(), &fsGenericCallback<Type::LINK>);
} }
auto linkSync(std::string old, std::string path) { auto linkSync(std::string old, std::string path) {
auto err = uv_fs_link(parent(), get<uv_fs_t>(), old.data(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::LINK>{}); cleanupAndInvokeSync(&uv_fs_link, parent(), req, old.data(), path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::LINK>{req->path});
} }
void symlink(std::string old, std::string path, int flags) { void symlink(std::string old, std::string path, int flags) {
invoke(&uv_fs_symlink, parent(), get<uv_fs_t>(), old.data(), path.data(), flags, &fsGenericCallback<Type::SYMLINK>); cleanupAndInvoke(&uv_fs_symlink, parent(), get<uv_fs_t>(), old.data(), path.data(), flags, &fsGenericCallback<Type::SYMLINK>);
} }
auto symlinkSync(std::string old, std::string path, int flags) { auto symlinkSync(std::string old, std::string path, int flags) {
auto err = uv_fs_symlink(parent(), get<uv_fs_t>(), old.data(), path.data(), flags, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::SYMLINK>{}); cleanupAndInvokeSync(&uv_fs_symlink, parent(), req, old.data(), path.data(), flags, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::SYMLINK>{req->path});
} }
void readlink(std::string path) { void readlink(std::string path) {
invoke(&uv_fs_readlink, parent(), get<uv_fs_t>(), path.data(), &fsReadlinkCallback); cleanupAndInvoke(&uv_fs_readlink, parent(), get<uv_fs_t>(), path.data(), &fsReadlinkCallback);
} }
// TODO uv_fs_readlink (sync (cb null)) auto readlinkSync(std::string path) {
auto req = get<uv_fs_t>();
cleanupAndInvokeSync(&uv_fs_readlink, parent(), req, path.data(), nullptr);
auto bw = req->result;
return std::make_pair(ErrorEvent{bw < 0 ? bw : 0}, FsEvent<Type::READLINK>{req->path, static_cast<char *>(req->ptr), bw});
}
void realpath(std::string path) { void realpath(std::string path) {
invoke(&uv_fs_realpath, parent(), get<uv_fs_t>(), path.data(), &fsGenericCallback<Type::REALPATH>); cleanupAndInvoke(&uv_fs_realpath, parent(), get<uv_fs_t>(), path.data(), &fsGenericCallback<Type::REALPATH>);
} }
auto realpathSync(std::string path) { auto realpathSync(std::string path) {
auto err = uv_fs_realpath(parent(), get<uv_fs_t>(), path.data(), nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::REALPATH>{}); cleanupAndInvokeSync(&uv_fs_realpath, parent(), req, path.data(), nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::REALPATH>{req->path});
} }
void chown(std::string path, Uid uid, Gid gid) { void chown(std::string path, Uid uid, Gid gid) {
invoke(&uv_fs_chown, parent(), get<uv_fs_t>(), path.data(), uid, gid, &fsGenericCallback<Type::CHOWN>); cleanupAndInvoke(&uv_fs_chown, parent(), get<uv_fs_t>(), path.data(), uid, gid, &fsGenericCallback<Type::CHOWN>);
} }
auto chownSync(std::string path, Uid uid, Gid gid) { auto chownSync(std::string path, Uid uid, Gid gid) {
auto err = uv_fs_chown(parent(), get<uv_fs_t>(), path.data(), uid, gid, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::CHOWN>{}); cleanupAndInvokeSync(&uv_fs_chown, parent(), req, path.data(), uid, gid, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::CHOWN>{req->path});
} }
void fchown(FileHandle file, Uid uid, Gid gid) { void fchown(Uid uid, Gid gid) {
invoke(&uv_fs_fchown, parent(), get<uv_fs_t>(), file, uid, gid, &fsGenericCallback<Type::FCHOWN>); cleanupAndInvoke(&uv_fs_fchown, parent(), get<uv_fs_t>(), file, uid, gid, &fsGenericCallback<Type::FCHOWN>);
} }
auto fchownSync(FileHandle file, Uid uid, Gid gid) { auto fchownSync(Uid uid, Gid gid) {
auto err = uv_fs_fchown(parent(), get<uv_fs_t>(), file, uid, gid, nullptr); auto req = get<uv_fs_t>();
return std::make_pair(ErrorEvent{err}, FsEvent<Type::FCHOWN>{}); cleanupAndInvokeSync(&uv_fs_fchown, parent(), req, file, uid, gid, nullptr);
return std::make_pair(ErrorEvent{req->result}, FsEvent<Type::FCHOWN>{req->path});
} }
operator FileHandle() const noexcept { return file; }
private:
uv_file file{BAD_FD};
}; };

View File

@ -63,6 +63,13 @@ protected:
return this->self(); return this->self();
} }
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;
}
public: public:
bool active() const noexcept override { bool active() const noexcept override {
return !(uv_is_active(this->template get<uv_handle_t>()) == 0); return !(uv_is_active(this->template get<uv_handle_t>()) == 0);

View File

@ -13,43 +13,42 @@ namespace uvw {
template<typename T, typename U> template<typename T, typename U>
class Request: public Resource<T, U> { class Request: public Resource<T, U> {
template<typename R, typename E>
static void execCallback(R *req, int status) {
T &res = *(static_cast<T*>(req->data));
auto ptr = res.shared_from_this();
(void)ptr;
res.reset();
if(status) {
res.publish(ErrorEvent{status});
} else {
res.publish(E{});
}
}
protected: protected:
using Resource<T, U>::Resource; using Resource<T, U>::Resource;
template<typename R, typename E, typename F, typename... Args> static auto reserve(uv_req_t *req) {
auto exec(F &&f, Args&&... args) auto ptr = static_cast<T*>(req->data)->shared_from_this();
-> std::enable_if_t<not std::is_void<std::result_of_t<F(Args..., decltype(&execCallback<R, E>))>>::value, int> { ptr->reset();
auto ret = this->invoke(std::forward<F>(f), std::forward<Args>(args)..., &execCallback<R, E>); return ptr;
if(0 == ret) { this->leak(); }
return ret;
} }
template<typename R, typename E, typename F, typename... Args> template<typename R, typename E>
auto exec(F &&f, Args&&... args) static void defaultCallback(R *req, int status) {
-> std::enable_if_t<std::is_void<std::result_of_t<F(Args..., decltype(&execCallback<R, E>))>>::value> { auto ptr = reserve(reinterpret_cast<uv_req_t*>(req));
std::forward<F>(f)(std::forward<Args>(args)..., &execCallback<R, E>); 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(); this->leak();
} }
public: public:
void cancel() { void cancel() {
this->invoke(&uv_cancel, this->template get<uv_req_t>()); auto err = uv_cancel(this->template get<uv_req_t>());
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
} }
std::size_t size() const noexcept { std::size_t size() const noexcept {

View File

@ -35,13 +35,6 @@ protected:
template<typename R> template<typename R>
auto get() const noexcept { return reinterpret_cast<const R*>(&resource); } auto get() const noexcept { return reinterpret_cast<const R*>(&resource); }
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;
}
public: public:
Resource(const Resource &) = delete; Resource(const Resource &) = delete;
Resource(Resource &&) = delete; Resource(Resource &&) = delete;

View File

@ -50,7 +50,7 @@ public:
template<typename F, typename... Args> template<typename F, typename... Args>
void connect(F &&f, Args... args) { void connect(F &&f, Args... args) {
exec<uv_connect_t, ConnectEvent>(std::forward<F>(f), get<uv_connect_t>(), std::forward<Args>(args)...); invoke(std::forward<F>(f), get<uv_connect_t>(), std::forward<Args>(args)..., &defaultCallback<uv_connect_t, ConnectEvent>);
} }
}; };
@ -65,7 +65,7 @@ public:
} }
void shutdown(uv_stream_t *handle) { void shutdown(uv_stream_t *handle) {
exec<uv_shutdown_t, ShutdownEvent>(&uv_shutdown, get<uv_shutdown_t>(), handle); invoke(&uv_shutdown, get<uv_shutdown_t>(), handle, &defaultCallback<uv_shutdown_t, ShutdownEvent>);
} }
}; };
@ -80,11 +80,11 @@ public:
} }
void write(uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs) { void write(uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs) {
exec<uv_write_t, WriteEvent>(&uv_write, get<uv_write_t>(), handle, bufs, nbufs); invoke(&uv_write, get<uv_write_t>(), handle, bufs, nbufs, &defaultCallback<uv_write_t, WriteEvent>);
} }
void write(uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t *send) { void write(uv_stream_t *handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t *send) {
exec<uv_write_t, WriteEvent>(&uv_write2, get<uv_write_t>(), handle, bufs, nbufs, send); invoke(&uv_write2, get<uv_write_t>(), handle, bufs, nbufs, send, &defaultCallback<uv_write_t, WriteEvent>);
} }
}; };
@ -155,8 +155,8 @@ public:
this->invoke(&uv_read_stop, this->template get<uv_stream_t>()); this->invoke(&uv_read_stop, this->template get<uv_stream_t>());
} }
void write(char *data, ssize_t len) { void write(std::unique_ptr<char[]> data, ssize_t len) {
uv_buf_t bufs[] = { uv_buf_init(data, len) }; uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
auto listener = [ptr = this->shared_from_this()](const auto &event, details::Write &) { auto listener = [ptr = this->shared_from_this()](const auto &event, details::Write &) {
ptr->publish(event); ptr->publish(event);
@ -168,13 +168,9 @@ public:
write->write(this->template get<uv_stream_t>(), bufs, 1); write->write(this->template get<uv_stream_t>(), bufs, 1);
} }
void write(std::unique_ptr<char[]> data, ssize_t len) {
write(data.get(), len);
}
template<typename S> template<typename S>
void write(S &send, char *data, ssize_t len) { void write(S &send, std::unique_ptr<char[]> data, ssize_t len) {
uv_buf_t bufs[] = { uv_buf_init(data, len) }; uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
auto listener = [ptr = this->shared_from_this()](const auto &event, details::Write &) { auto listener = [ptr = this->shared_from_this()](const auto &event, details::Write &) {
ptr->publish(event); ptr->publish(event);
@ -186,13 +182,8 @@ public:
write->write(this->template get<uv_stream_t>(), bufs, 1, send.template get<uv_stream_t>()); write->write(this->template get<uv_stream_t>(), bufs, 1, send.template get<uv_stream_t>());
} }
template<typename S> int tryWrite(std::unique_ptr<char[]> data, ssize_t len) {
void write(S &send, std::unique_ptr<char[]> data, ssize_t len) { uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
write(send, data.get(), len);
}
int tryWrite(char *data, ssize_t len) {
uv_buf_t bufs[] = { uv_buf_init(data, len) };
auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1); auto bw = uv_try_write(this->template get<uv_stream_t>(), bufs, 1);
if(bw < 0) { if(bw < 0) {
@ -203,10 +194,6 @@ public:
return bw; return bw;
} }
int tryWrite(std::unique_ptr<char[]> data, ssize_t len) {
return tryWrite(data.get(), len);
}
bool readable() const noexcept { bool readable() const noexcept {
return (uv_is_readable(this->template get<uv_stream_t>()) == 1); return (uv_is_readable(this->template get<uv_stream_t>()) == 1);
} }

View File

@ -30,9 +30,7 @@ class TTY final: public Stream<TTY, uv_tty_t> {
explicit TTY(std::shared_ptr<Loop> ref, explicit TTY(std::shared_ptr<Loop> ref,
FileHandle desc, FileHandle desc,
bool readable) bool readable)
: Stream{std::move(ref)}, : Stream{std::move(ref)}, fd{desc}, rw{readable}
fd{static_cast<FileHandle::Type>(desc)},
rw{readable}
{ } { }
public: public:

View File

@ -61,7 +61,7 @@ public:
} }
void send(uv_udp_t *handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr) { void send(uv_udp_t *handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr) {
exec<uv_udp_send_t, SendEvent>(&uv_udp_send, get<uv_udp_send_t>(), handle, bufs, nbufs, addr); invoke(&uv_udp_send, get<uv_udp_send_t>(), handle, bufs, nbufs, addr, &defaultCallback<uv_udp_send_t, SendEvent>);
} }
}; };
@ -156,11 +156,11 @@ public:
void ttl(int val) { invoke(&uv_udp_set_ttl, get<uv_udp_t>(), val > 255 ? 255 : val); } void ttl(int val) { invoke(&uv_udp_set_ttl, get<uv_udp_t>(), val > 255 ? 255 : val); }
template<typename I = IPv4> template<typename I = IPv4>
void send(std::string ip, unsigned int port, char *data, ssize_t len) { void send(std::string ip, unsigned int port, std::unique_ptr<char[]> data, ssize_t len) {
typename details::IpTraits<I>::Type addr; typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::AddrFunc(ip.data(), port, &addr); details::IpTraits<I>::AddrFunc(ip.data(), port, &addr);
uv_buf_t bufs[] = { uv_buf_init(data, len) }; uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
auto listener = [ptr = shared_from_this()](const auto &event, details::Send &) { auto listener = [ptr = shared_from_this()](const auto &event, details::Send &) {
ptr->publish(event); ptr->publish(event);
@ -173,16 +173,11 @@ public:
} }
template<typename I = IPv4> template<typename I = IPv4>
void send(std::string ip, unsigned int port, std::unique_ptr<char[]> data, ssize_t len) { int trySend(std::string ip, unsigned int port, std::unique_ptr<char[]> data, ssize_t len) {
send<I>(ip, port, data.get(), len);
}
template<typename I = IPv4>
int trySend(std::string ip, unsigned int port, char *data, ssize_t len) {
typename details::IpTraits<I>::Type addr; typename details::IpTraits<I>::Type addr;
details::IpTraits<I>::AddrFunc(ip.data(), port, &addr); details::IpTraits<I>::AddrFunc(ip.data(), port, &addr);
uv_buf_t bufs[] = { uv_buf_init(data, len) }; uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
auto bw = uv_udp_try_send(get<uv_udp_t>(), bufs, 1, reinterpret_cast<const sockaddr *>(&addr)); auto bw = uv_udp_try_send(get<uv_udp_t>(), bufs, 1, reinterpret_cast<const sockaddr *>(&addr));
if(bw < 0) { if(bw < 0) {
@ -193,11 +188,6 @@ public:
return bw; return bw;
} }
template<typename I = IPv4>
int trySend(std::string ip, unsigned int port, std::unique_ptr<char[]> data, ssize_t len) {
return trySend<I>(ip, port, data.get(), len);
}
template<typename I = IPv4> template<typename I = IPv4>
void recv() { void recv() {
invoke(&uv_udp_recv_start, get<uv_udp_t>(), &allocCallback, &recvCallback<I>); invoke(&uv_udp_recv_start, get<uv_udp_t>(), &allocCallback, &recvCallback<I>);

View File

@ -32,7 +32,7 @@ public:
} }
void queue(Task t) { void queue(Task t) {
if(0 == exec<uv_work_t, WorkEvent>(&uv_queue_work, parent(), get<uv_work_t>(), &workCallback)) { if(0 == invoke(&uv_queue_work, parent(), get<uv_work_t>(), &workCallback, &defaultCallback<uv_work_t, WorkEvent>)) {
task = std::move(t); task = std::move(t);
} }
} }