diff options
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/rust-ffi.cc | 12 | ||||
-rw-r--r-- | src/libutil/rust-ffi.hh | 133 | ||||
-rw-r--r-- | src/libutil/tarfile.cc | 2 | ||||
-rw-r--r-- | src/libutil/util.cc | 13 | ||||
-rw-r--r-- | src/libutil/util.hh | 8 |
5 files changed, 147 insertions, 21 deletions
diff --git a/src/libutil/rust-ffi.cc b/src/libutil/rust-ffi.cc index 931d29542..accc5e22b 100644 --- a/src/libutil/rust-ffi.cc +++ b/src/libutil/rust-ffi.cc @@ -1,12 +1,18 @@ #include "logging.hh" #include "rust-ffi.hh" -namespace nix { - extern "C" std::exception_ptr * make_error(rust::StringSlice s) { // FIXME: leak - return new std::exception_ptr(std::make_exception_ptr(Error(std::string(s.ptr, s.size)))); + return new std::exception_ptr(std::make_exception_ptr(nix::Error(std::string(s.ptr, s.size)))); +} + +namespace rust { + +std::ostream & operator << (std::ostream & str, const String & s) +{ + str << (std::string_view) s; + return str; } } diff --git a/src/libutil/rust-ffi.hh b/src/libutil/rust-ffi.hh index 663758bfc..a77f83ac5 100644 --- a/src/libutil/rust-ffi.hh +++ b/src/libutil/rust-ffi.hh @@ -1,16 +1,91 @@ +#pragma once + #include "serialise.hh" +#include <string_view> +#include <cstring> +#include <array> + namespace rust { -// Depending on the internal representation of Rust slices is slightly -// evil... +typedef void (*DropFun)(void *); + +/* A Rust value of N bytes. It can be moved but not copied. When it + goes out of scope, the C++ destructor will run the drop + function. */ +template<std::size_t N, DropFun drop> +struct Value +{ +protected: + + std::array<char, N> raw; + + ~Value() + { + if (!isEvacuated()) { + drop(this); + evacuate(); + } + } + + // Must not be called directly. + Value() + { } + + Value(Value && other) + : raw(other.raw) + { + other.evacuate(); + } + + void operator =(Value && other) + { + if (!isEvacuated()) + drop(this); + raw = other.raw; + other.evacuate(); + } + +private: + + /* FIXME: optimize these (ideally in such a way that the compiler + can elide most calls to evacuate() / isEvacuated(). */ + inline void evacuate() + { + for (auto & i : raw) i = 0; + } + + inline bool isEvacuated() + { + for (auto & i : raw) + if (i != 0) return false; + return true; + } +}; + +/* A Rust vector. */ +template<typename T, DropFun drop> +struct Vec : Value<3 * sizeof(void *), drop> +{ + inline size_t size() const + { + return ((const size_t *) &this->raw)[2]; + } + + const T * data() const + { + return ((const T * *) &this->raw)[0]; + } +}; + +/* A Rust slice. */ template<typename T> struct Slice { - T * ptr; + const T * ptr; size_t size; - Slice(T * ptr, size_t size) : ptr(ptr), size(size) + Slice(const T * ptr, size_t size) : ptr(ptr), size(size) { assert(ptr); } @@ -18,9 +93,44 @@ struct Slice struct StringSlice : Slice<char> { - StringSlice(const std::string & s): Slice((char *) s.data(), s.size()) {} + StringSlice(const std::string & s): Slice(s.data(), s.size()) {} + explicit StringSlice(std::string_view s): Slice(s.data(), s.size()) {} + StringSlice(const char * s): Slice(s, strlen(s)) {} + + operator std::string_view() const + { + return std::string_view(ptr, size); + } +}; + +/* A Rust string. */ +struct String; + +extern "C" { + void ffi_String_new(StringSlice s, String * out); + void ffi_String_drop(void * s); +} + +struct String : Vec<char, ffi_String_drop> +{ + String(std::string_view s) + { + ffi_String_new(StringSlice(s), this); + } + + String(const char * s) + : String({s, std::strlen(s)}) + { + } + + operator std::string_view() const + { + return std::string_view(data(), size()); + } }; +std::ostream & operator << (std::ostream & str, const String & s); + struct Source { size_t (*fun)(void * source_this, rust::Slice<uint8_t> data); @@ -33,7 +143,7 @@ struct Source // FIXME: how to propagate exceptions? static size_t sourceWrapper(void * _this, rust::Slice<uint8_t> data) { - auto n = ((nix::Source *) _this)->read(data.ptr, data.size); + auto n = ((nix::Source *) _this)->read((unsigned char *) data.ptr, data.size); return n; } }; @@ -49,11 +159,20 @@ struct Result std::exception_ptr * exc; }; + ~Result() + { + if (tag == 0) + data.~T(); + else if (tag == 1) + // FIXME: don't leak exc + ; + } + /* Rethrow the wrapped exception or return the wrapped value. */ T unwrap() { if (tag == 0) - return data; + return std::move(data); else if (tag == 1) std::rethrow_exception(*exc); else diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc index 2cc7793fd..262bc655f 100644 --- a/src/libutil/tarfile.cc +++ b/src/libutil/tarfile.cc @@ -17,7 +17,7 @@ void unpackTarfile(Source & source, const Path & destDir) void unpackTarfile(const Path & tarFile, const Path & destDir, std::optional<std::string> baseName) { - if (!baseName) baseName = baseNameOf(tarFile); + if (!baseName) baseName = std::string(baseNameOf(tarFile)); auto source = sinkToSource([&](Sink & sink) { // FIXME: look at first few bytes to determine compression type. diff --git a/src/libutil/util.cc b/src/libutil/util.cc index b4d444a67..e67bdcdeb 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -188,22 +188,22 @@ Path dirOf(const Path & path) } -string baseNameOf(const Path & path) +std::string_view baseNameOf(std::string_view path) { if (path.empty()) return ""; - Path::size_type last = path.length() - 1; + auto last = path.size() - 1; if (path[last] == '/' && last > 0) last -= 1; - Path::size_type pos = path.rfind('/', last); + auto pos = path.rfind('/', last); if (pos == string::npos) pos = 0; else pos += 1; - return string(path, pos, last - pos + 1); + return path.substr(pos, last - pos + 1); } @@ -1302,9 +1302,10 @@ bool hasPrefix(const string & s, const string & prefix) } -bool hasSuffix(const string & s, const string & suffix) +bool hasSuffix(std::string_view s, std::string_view suffix) { - return s.size() >= suffix.size() && string(s, s.size() - suffix.size()) == suffix; + return s.size() >= suffix.size() + && s.substr(s.size() - suffix.size()) == suffix; } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index a1acb49b5..abd91b81c 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -62,7 +62,7 @@ Path dirOf(const Path & path); /* Return the base name of the given canonical path, i.e., everything following the final `/'. */ -string baseNameOf(const Path & path); +std::string_view baseNameOf(std::string_view path); /* Check whether 'path' is a descendant of 'dir'. */ bool isInDir(const Path & path, const Path & dir); @@ -407,7 +407,7 @@ bool hasPrefix(const string & s, const string & prefix); /* Return true iff `s' ends in `suffix'. */ -bool hasSuffix(const string & s, const string & suffix); +bool hasSuffix(std::string_view s, std::string_view suffix); /* Convert a string to lower case. */ @@ -450,10 +450,10 @@ string base64Decode(const string & s); /* Get a value for the specified key from an associate container, or a default value if the key doesn't exist. */ template <class T> -string get(const T & map, const string & key, const string & def = "") +std::optional<std::string> get(const T & map, const std::string & key) { auto i = map.find(key); - return i == map.end() ? def : i->second; + return i == map.end() ? std::optional<std::string>() : i->second; } |