aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-12-11 14:53:30 +0100
committerEelco Dolstra <edolstra@gmail.com>2019-12-11 14:53:30 +0100
commitecb3a1afa2395c46c4ba2ec9da550f45414dbe6d (patch)
tree6d1038ee909bd1ba69948a0bc326cd5ba6824e01 /src/libutil
parentab88f4bbd4117db458a79f0a02a4de7bf7931f4c (diff)
parentf800d450b78091835ab7ca67847d76e75d877a24 (diff)
Merge remote-tracking branch 'origin/master' into flakes
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/rust-ffi.cc12
-rw-r--r--src/libutil/rust-ffi.hh133
-rw-r--r--src/libutil/tarfile.cc2
-rw-r--r--src/libutil/util.cc13
-rw-r--r--src/libutil/util.hh8
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 1e5e4851e..085c1e695 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -189,22 +189,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);
}
@@ -1307,9 +1307,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 c18d1b5a4..cc045016b 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);
@@ -431,7 +431,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. */
@@ -474,10 +474,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;
}