Extend internal API docs, part 2

Picking up from #8111.

Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
This commit is contained in:
John Ericson 2023-03-26 21:12:25 -04:00
parent 8ae9d66940
commit abd5e7dec0
32 changed files with 640 additions and 359 deletions

View file

@ -3,8 +3,15 @@
namespace nix { namespace nix {
/**
* An InstallableCommand where the single positional argument must be an
* InstallableValue in particular.
*/
struct InstallableValueCommand : InstallableCommand struct InstallableValueCommand : InstallableCommand
{ {
/**
* Entry point to this command
*/
virtual void run(ref<Store> store, ref<InstallableValue> installable) = 0; virtual void run(ref<Store> store, ref<InstallableValue> installable) = 0;
void run(ref<Store> store, ref<Installable> installable) override; void run(ref<Store> store, ref<Installable> installable) override;

View file

@ -87,39 +87,56 @@ struct FileTransfer
{ {
virtual ~FileTransfer() { } virtual ~FileTransfer() { }
/* Enqueue a data transfer request, returning a future to the result of /**
the download. The future may throw a FileTransferError * Enqueue a data transfer request, returning a future to the result of
exception. */ * the download. The future may throw a FileTransferError
* exception.
*/
virtual void enqueueFileTransfer(const FileTransferRequest & request, virtual void enqueueFileTransfer(const FileTransferRequest & request,
Callback<FileTransferResult> callback) = 0; Callback<FileTransferResult> callback) = 0;
std::future<FileTransferResult> enqueueFileTransfer(const FileTransferRequest & request); std::future<FileTransferResult> enqueueFileTransfer(const FileTransferRequest & request);
/* Synchronously download a file. */ /**
* Synchronously download a file.
*/
FileTransferResult download(const FileTransferRequest & request); FileTransferResult download(const FileTransferRequest & request);
/* Synchronously upload a file. */ /**
* Synchronously upload a file.
*/
FileTransferResult upload(const FileTransferRequest & request); FileTransferResult upload(const FileTransferRequest & request);
/* Download a file, writing its data to a sink. The sink will be /**
invoked on the thread of the caller. */ * Download a file, writing its data to a sink. The sink will be
* invoked on the thread of the caller.
*/
void download(FileTransferRequest && request, Sink & sink); void download(FileTransferRequest && request, Sink & sink);
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted }; enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
}; };
/* Return a shared FileTransfer object. Using this object is preferred /**
because it enables connection reuse and HTTP/2 multiplexing. */ * @return a shared FileTransfer object.
*
* Using this object is preferred because it enables connection reuse
* and HTTP/2 multiplexing.
*/
ref<FileTransfer> getFileTransfer(); ref<FileTransfer> getFileTransfer();
/* Return a new FileTransfer object. */ /**
* @return a new FileTransfer object
*
* Prefer getFileTransfer() to this; see its docs for why.
*/
ref<FileTransfer> makeFileTransfer(); ref<FileTransfer> makeFileTransfer();
class FileTransferError : public Error class FileTransferError : public Error
{ {
public: public:
FileTransfer::Error error; FileTransfer::Error error;
std::optional<std::string> response; // intentionally optional /// intentionally optional
std::optional<std::string> response;
template<typename... Args> template<typename... Args>
FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args); FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);

View file

@ -4,6 +4,13 @@
namespace nix { namespace nix {
/**
* Helper to try downcasting a Store with a nice method if it fails.
*
* This is basically an alternative to the user-facing part of
* Store::unsupported that allows us to still have a nice message but
* better interface design.
*/
template<typename T> template<typename T>
T & require(Store & store) T & require(Store & store)
{ {

View file

@ -14,6 +14,10 @@ namespace nix {
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff) #define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
/**
* Enumeration of all the request types for the "worker protocol", used
* by unix:// and ssh-ng:// stores.
*/
typedef enum { typedef enum {
wopIsValidPath = 1, wopIsValidPath = 1,
wopHasSubstitutes = 3, wopHasSubstitutes = 3,
@ -74,7 +78,12 @@ typedef enum {
class Store; class Store;
struct Source; struct Source;
/* To guide overloading */ /**
* Used to guide overloading
*
* See https://en.cppreference.com/w/cpp/language/adl for the broader
* concept of what is going on here.
*/
template<typename T> template<typename T>
struct Phantom {}; struct Phantom {};
@ -103,18 +112,19 @@ MAKE_WORKER_PROTO(X_, Y_);
#undef X_ #undef X_
#undef Y_ #undef Y_
/* These use the empty string for the null case, relying on the fact /**
that the underlying types never serialize to the empty string. * These use the empty string for the null case, relying on the fact
* that the underlying types never serialize to the empty string.
We do this instead of a generic std::optional<T> instance because *
ordinal tags (0 or 1, here) are a bit of a compatability hazard. For * We do this instead of a generic std::optional<T> instance because
the same reason, we don't have a std::variant<T..> instances (ordinal * ordinal tags (0 or 1, here) are a bit of a compatability hazard. For
tags 0...n). * the same reason, we don't have a std::variant<T..> instances (ordinal
* tags 0...n).
We could the generic instances and then these as specializations for *
compatability, but that's proven a bit finnicky, and also makes the * We could the generic instances and then these as specializations for
worker protocol harder to implement in other languages where such * compatability, but that's proven a bit finnicky, and also makes the
specializations may not be allowed. * worker protocol harder to implement in other languages where such
* specializations may not be allowed.
*/ */
MAKE_WORKER_PROTO(, std::optional<StorePath>); MAKE_WORKER_PROTO(, std::optional<StorePath>);
MAKE_WORKER_PROTO(, std::optional<ContentAddress>); MAKE_WORKER_PROTO(, std::optional<ContentAddress>);

View file

@ -7,54 +7,71 @@
namespace nix { namespace nix {
/* dumpPath creates a Nix archive of the specified path. The format /**
is as follows: * dumpPath creates a Nix archive of the specified path.
*
IF path points to a REGULAR FILE: * @param path the file system data to dump. Dumping is recursive so if
dump(path) = attrs( * this is a directory we dump it and all its children.
[ ("type", "regular") *
, ("contents", contents(path)) * @param [out] sink The serialised archive is fed into this sink.
]) *
* @param filter Can be used to skip certain files.
IF path points to a DIRECTORY: *
dump(path) = attrs( * The format is as follows:
[ ("type", "directory") *
, ("entries", concat(map(f, sort(entries(path))))) * IF path points to a REGULAR FILE:
]) * dump(path) = attrs(
where f(fn) = attrs( * [ ("type", "regular")
[ ("name", fn) * , ("contents", contents(path))
, ("file", dump(path + "/" + fn)) * ])
]) *
* IF path points to a DIRECTORY:
where: * dump(path) = attrs(
* [ ("type", "directory")
attrs(as) = concat(map(attr, as)) + encN(0) * , ("entries", concat(map(f, sort(entries(path)))))
attrs((a, b)) = encS(a) + encS(b) * ])
* where f(fn) = attrs(
encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary) * [ ("name", fn)
* , ("file", dump(path + "/" + fn))
encN(n) = 64-bit little-endian encoding of n. * ])
*
contents(path) = the contents of a regular file. * where:
*
sort(strings) = lexicographic sort by 8-bit value (strcmp). * attrs(as) = concat(map(attr, as)) + encN(0)
* attrs((a, b)) = encS(a) + encS(b)
entries(path) = the entries of a directory, without `.' and *
`..'. * encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)
*
`+' denotes string concatenation. */ * encN(n) = 64-bit little-endian encoding of n.
*
* contents(path) = the contents of a regular file.
*
* sort(strings) = lexicographic sort by 8-bit value (strcmp).
*
* entries(path) = the entries of a directory, without `.' and
* `..'.
*
* `+' denotes string concatenation.
*/
void dumpPath(const Path & path, Sink & sink, void dumpPath(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter); PathFilter & filter = defaultPathFilter);
/* Same as `void dumpPath()`, but returns the last modified date of the path */ /**
* Same as dumpPath(), but returns the last modified date of the path.
*/
time_t dumpPathAndGetMtime(const Path & path, Sink & sink, time_t dumpPathAndGetMtime(const Path & path, Sink & sink,
PathFilter & filter = defaultPathFilter); PathFilter & filter = defaultPathFilter);
/**
* Dump an archive with a single file with these contents.
*
* @param s Contents of the file.
*/
void dumpString(std::string_view s, Sink & sink); void dumpString(std::string_view s, Sink & sink);
/* FIXME: fix this API, it sucks. */ /**
* \todo Fix this API, it sucks.
*/
struct ParseSink struct ParseSink
{ {
virtual void createDirectory(const Path & path) { }; virtual void createDirectory(const Path & path) { };
@ -68,8 +85,10 @@ struct ParseSink
virtual void createSymlink(const Path & path, const std::string & target) { }; virtual void createSymlink(const Path & path, const std::string & target) { };
}; };
/* If the NAR archive contains a single file at top-level, then save /**
the contents of the file to `s'. Otherwise barf. */ * If the NAR archive contains a single file at top-level, then save
* the contents of the file to `s'. Otherwise barf.
*/
struct RetrieveRegularNARSink : ParseSink struct RetrieveRegularNARSink : ParseSink
{ {
bool regular = true; bool regular = true;
@ -97,7 +116,9 @@ void parseDump(ParseSink & sink, Source & source);
void restorePath(const Path & path, Source & source); void restorePath(const Path & path, Source & source);
/* Read a NAR from 'source' and write it to 'sink'. */ /**
* Read a NAR from 'source' and write it to 'sink'.
*/
void copyNAR(Source & source, Sink & sink); void copyNAR(Source & source, Sink & sink);
void copyPath(const Path & from, const Path & to); void copyPath(const Path & from, const Path & to);

View file

@ -18,16 +18,22 @@ class Args
{ {
public: public:
/* Parse the command line, throwing a UsageError if something goes /**
wrong. */ * Parse the command line, throwing a UsageError if something goes
* wrong.
*/
void parseCmdline(const Strings & cmdline); void parseCmdline(const Strings & cmdline);
/* Return a short one-line description of the command. */ /**
* Return a short one-line description of the command.
*/
virtual std::string description() { return ""; } virtual std::string description() { return ""; }
virtual bool forceImpureByDefault() { return false; } virtual bool forceImpureByDefault() { return false; }
/* Return documentation about this command, in Markdown format. */ /**
* Return documentation about this command, in Markdown format.
*/
virtual std::string doc() { return ""; } virtual std::string doc() { return ""; }
protected: protected:
@ -146,13 +152,17 @@ protected:
std::set<std::string> hiddenCategories; std::set<std::string> hiddenCategories;
/* Called after all command line flags before the first non-flag /**
argument (if any) have been processed. */ * Called after all command line flags before the first non-flag
* argument (if any) have been processed.
*/
virtual void initialFlagsProcessed() {} virtual void initialFlagsProcessed() {}
/* Called after the command line has been processed if we need to generate /**
completions. Useful for commands that need to know the whole command line * Called after the command line has been processed if we need to generate
in order to know what completions to generate. */ * completions. Useful for commands that need to know the whole command line
* in order to know what completions to generate.
*/
virtual void completionHook() { } virtual void completionHook() { }
public: public:
@ -166,7 +176,9 @@ public:
expectedArgs.emplace_back(std::move(arg)); expectedArgs.emplace_back(std::move(arg));
} }
/* Expect a string argument. */ /**
* Expect a string argument.
*/
void expectArg(const std::string & label, std::string * dest, bool optional = false) void expectArg(const std::string & label, std::string * dest, bool optional = false)
{ {
expectArgs({ expectArgs({
@ -176,7 +188,9 @@ public:
}); });
} }
/* Expect 0 or more arguments. */ /**
* Expect 0 or more arguments.
*/
void expectArgs(const std::string & label, std::vector<std::string> * dest) void expectArgs(const std::string & label, std::vector<std::string> * dest)
{ {
expectArgs({ expectArgs({
@ -202,14 +216,19 @@ private:
std::set<ExperimentalFeature> flagExperimentalFeatures; std::set<ExperimentalFeature> flagExperimentalFeatures;
}; };
/* A command is an argument parser that can be executed by calling its /**
run() method. */ * A command is an argument parser that can be executed by calling its
* run() method.
*/
struct Command : virtual public Args struct Command : virtual public Args
{ {
friend class MultiCommand; friend class MultiCommand;
virtual ~Command() { } virtual ~Command() { }
/**
* Entry point to the command
*/
virtual void run() = 0; virtual void run() = 0;
typedef int Category; typedef int Category;
@ -221,8 +240,10 @@ struct Command : virtual public Args
typedef std::map<std::string, std::function<ref<Command>()>> Commands; typedef std::map<std::string, std::function<ref<Command>()>> Commands;
/* An argument parser that supports multiple subcommands, /**
i.e. <command> <subcommand>. */ * An argument parser that supports multiple subcommands,
* i.e. <command> <subcommand>.
*/
class MultiCommand : virtual public Args class MultiCommand : virtual public Args
{ {
public: public:
@ -230,7 +251,9 @@ public:
std::map<Command::Category, std::string> categories; std::map<Command::Category, std::string> categories;
// Selected command, if any. /**
* Selected command, if any.
*/
std::optional<std::pair<std::string, ref<Command>>> command; std::optional<std::pair<std::string, ref<Command>>> command;
MultiCommand(const Commands & commands); MultiCommand(const Commands & commands);

View file

@ -5,9 +5,11 @@
namespace nix { namespace nix {
/* A callback is a wrapper around a lambda that accepts a valid of /**
type T or an exception. (We abuse std::future<T> to pass the value or * A callback is a wrapper around a lambda that accepts a valid of
exception.) */ * type T or an exception. (We abuse std::future<T> to pass the value or
* exception.)
*/
template<typename T> template<typename T>
class Callback class Callback
{ {

View file

@ -8,19 +8,20 @@
namespace nix { namespace nix {
/* A canonical representation of a path. It ensures the following: /**
* A canonical representation of a path. It ensures the following:
- It always starts with a slash. *
* - It always starts with a slash.
- It never ends with a slash, except if the path is "/". *
* - It never ends with a slash, except if the path is "/".
- A slash is never followed by a slash (i.e. no empty components). *
* - A slash is never followed by a slash (i.e. no empty components).
- There are no components equal to '.' or '..'. *
* - There are no components equal to '.' or '..'.
Note that the path does not need to correspond to an actually *
existing path, and there is no guarantee that symlinks are * Note that the path does not need to correspond to an actually
resolved. * existing path, and there is no guarantee that symlinks are
* resolved.
*/ */
class CanonPath class CanonPath
{ {
@ -28,8 +29,10 @@ class CanonPath
public: public:
/* Construct a canon path from a non-canonical path. Any '.', '..' /**
or empty components are removed. */ * Construct a canon path from a non-canonical path. Any '.', '..'
* or empty components are removed.
*/
CanonPath(std::string_view raw); CanonPath(std::string_view raw);
explicit CanonPath(const char * raw) explicit CanonPath(const char * raw)
@ -44,9 +47,11 @@ public:
static CanonPath root; static CanonPath root;
/* If `raw` starts with a slash, return /**
`CanonPath(raw)`. Otherwise return a `CanonPath` representing * If `raw` starts with a slash, return
`root + "/" + raw`. */ * `CanonPath(raw)`. Otherwise return a `CanonPath` representing
* `root + "/" + raw`.
*/
CanonPath(std::string_view raw, const CanonPath & root); CanonPath(std::string_view raw, const CanonPath & root);
bool isRoot() const bool isRoot() const
@ -58,8 +63,10 @@ public:
const std::string & abs() const const std::string & abs() const
{ return path; } { return path; }
/* Like abs(), but return an empty string if this path is /**
'/'. Thus the returned string never ends in a slash. */ * Like abs(), but return an empty string if this path is
* '/'. Thus the returned string never ends in a slash.
*/
const std::string & absOrEmpty() const const std::string & absOrEmpty() const
{ {
const static std::string epsilon; const static std::string epsilon;
@ -107,7 +114,9 @@ public:
std::optional<CanonPath> parent() const; std::optional<CanonPath> parent() const;
/* Remove the last component. Panics if this path is the root. */ /**
* Remove the last component. Panics if this path is the root.
*/
void pop(); void pop();
std::optional<std::string_view> dirOf() const std::optional<std::string_view> dirOf() const
@ -128,10 +137,12 @@ public:
bool operator != (const CanonPath & x) const bool operator != (const CanonPath & x) const
{ return path != x.path; } { return path != x.path; }
/* Compare paths lexicographically except that path separators /**
are sorted before any other character. That is, in the sorted order * Compare paths lexicographically except that path separators
a directory is always followed directly by its children. For * are sorted before any other character. That is, in the sorted order
instance, 'foo' < 'foo/bar' < 'foo!'. */ * a directory is always followed directly by its children. For
* instance, 'foo' < 'foo/bar' < 'foo!'.
*/
bool operator < (const CanonPath & x) const bool operator < (const CanonPath & x) const
{ {
auto i = path.begin(); auto i = path.begin();
@ -147,27 +158,37 @@ public:
return i == path.end() && j != x.path.end(); return i == path.end() && j != x.path.end();
} }
/* Return true if `this` is equal to `parent` or a child of /**
`parent`. */ * Return true if `this` is equal to `parent` or a child of
* `parent`.
*/
bool isWithin(const CanonPath & parent) const; bool isWithin(const CanonPath & parent) const;
CanonPath removePrefix(const CanonPath & prefix) const; CanonPath removePrefix(const CanonPath & prefix) const;
/* Append another path to this one. */ /**
* Append another path to this one.
*/
void extend(const CanonPath & x); void extend(const CanonPath & x);
/* Concatenate two paths. */ /**
* Concatenate two paths.
*/
CanonPath operator + (const CanonPath & x) const; CanonPath operator + (const CanonPath & x) const;
/* Add a path component to this one. It must not contain any slashes. */ /**
* Add a path component to this one. It must not contain any slashes.
*/
void push(std::string_view c); void push(std::string_view c);
CanonPath operator + (std::string_view c) const; CanonPath operator + (std::string_view c) const;
/* Check whether access to this path is allowed, which is the case /**
if 1) `this` is within any of the `allowed` paths; or 2) any of * Check whether access to this path is allowed, which is the case
the `allowed` paths are within `this`. (The latter condition * if 1) `this` is within any of the `allowed` paths; or 2) any of
ensures access to the parents of allowed paths.) */ * the `allowed` paths are within `this`. (The latter condition
* ensures access to the parents of allowed paths.)
*/
bool isAllowed(const std::set<CanonPath> & allowed) const; bool isAllowed(const std::set<CanonPath> & allowed) const;
/* Return a representation `x` of `path` relative to `this`, i.e. /* Return a representation `x` of `path` relative to `this`, i.e.

View file

@ -18,10 +18,12 @@ struct CgroupStats
std::optional<std::chrono::microseconds> cpuUser, cpuSystem; std::optional<std::chrono::microseconds> cpuUser, cpuSystem;
}; };
/* Destroy the cgroup denoted by 'path'. The postcondition is that /**
'path' does not exist, and thus any processes in the cgroup have * Destroy the cgroup denoted by 'path'. The postcondition is that
been killed. Also return statistics from the cgroup just before * 'path' does not exist, and thus any processes in the cgroup have
destruction. */ * been killed. Also return statistics from the cgroup just before
* destruction.
*/
CgroupStats destroyCgroup(const Path & cgroup); CgroupStats destroyCgroup(const Path & cgroup);
} }

View file

@ -7,20 +7,24 @@
namespace nix { namespace nix {
/* Provides an indexable container like vector<> with memory overhead /**
guarantees like list<> by allocating storage in chunks of ChunkSize * Provides an indexable container like vector<> with memory overhead
elements instead of using a contiguous memory allocation like vector<> * guarantees like list<> by allocating storage in chunks of ChunkSize
does. Not using a single vector that is resized reduces memory overhead * elements instead of using a contiguous memory allocation like vector<>
on large data sets by on average (growth factor)/2, mostly * does. Not using a single vector that is resized reduces memory overhead
eliminates copies within the vector during resizing, and provides stable * on large data sets by on average (growth factor)/2, mostly
references to its elements. */ * eliminates copies within the vector during resizing, and provides stable
* references to its elements.
*/
template<typename T, size_t ChunkSize> template<typename T, size_t ChunkSize>
class ChunkedVector { class ChunkedVector {
private: private:
uint32_t size_ = 0; uint32_t size_ = 0;
std::vector<std::vector<T>> chunks; std::vector<std::vector<T>> chunks;
/* keep this out of the ::add hot path */ /**
* Keep this out of the ::add hot path
*/
[[gnu::noinline]] [[gnu::noinline]]
auto & addChunk() auto & addChunk()
{ {

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
/* Awfull hacky generation of the comparison operators by doing a lexicographic /**
* Awful hacky generation of the comparison operators by doing a lexicographic
* comparison between the choosen fields. * comparison between the choosen fields.
* *
* ``` * ```

View file

@ -124,21 +124,21 @@ public:
void reapplyUnknownSettings(); void reapplyUnknownSettings();
}; };
/* A class to simplify providing configuration settings. The typical /**
use is to inherit Config and add Setting<T> members: * A class to simplify providing configuration settings. The typical
* use is to inherit Config and add Setting<T> members:
class MyClass : private Config *
{ * class MyClass : private Config
Setting<int> foo{this, 123, "foo", "the number of foos to use"}; * {
Setting<std::string> bar{this, "blabla", "bar", "the name of the bar"}; * Setting<int> foo{this, 123, "foo", "the number of foos to use"};
* Setting<std::string> bar{this, "blabla", "bar", "the name of the bar"};
MyClass() : Config(readConfigFile("/etc/my-app.conf")) *
{ * MyClass() : Config(readConfigFile("/etc/my-app.conf"))
std::cout << foo << "\n"; // will print 123 unless overridden * {
} * std::cout << foo << "\n"; // will print 123 unless overridden
}; * }
* };
*/ */
class Config : public AbstractConfig class Config : public AbstractConfig
{ {
friend class AbstractSetting; friend class AbstractSetting;
@ -228,7 +228,9 @@ protected:
bool isOverridden() const { return overridden; } bool isOverridden() const { return overridden; }
}; };
/* A setting of type T. */ /**
* A setting of type T.
*/
template<typename T> template<typename T>
class BaseSetting : public AbstractSetting class BaseSetting : public AbstractSetting
{ {
@ -311,8 +313,10 @@ public:
void operator =(const T & v) { this->assign(v); } void operator =(const T & v) { this->assign(v); }
}; };
/* A special setting for Paths. These are automatically canonicalised /**
(e.g. "/foo//bar/" becomes "/foo/bar"). */ * A special setting for Paths. These are automatically canonicalised
* (e.g. "/foo//bar/" becomes "/foo/bar").
*/
class PathSetting : public BaseSetting<Path> class PathSetting : public BaseSetting<Path>
{ {
bool allowEmpty; bool allowEmpty;

View file

@ -54,20 +54,26 @@ typedef enum {
lvlVomit lvlVomit
} Verbosity; } Verbosity;
// the lines of code surrounding an error. /**
* The lines of code surrounding an error.
*/
struct LinesOfCode { struct LinesOfCode {
std::optional<std::string> prevLineOfCode; std::optional<std::string> prevLineOfCode;
std::optional<std::string> errLineOfCode; std::optional<std::string> errLineOfCode;
std::optional<std::string> nextLineOfCode; std::optional<std::string> nextLineOfCode;
}; };
/* An abstract type that represents a location in a source file. */ /**
* An abstract type that represents a location in a source file.
*/
struct AbstractPos struct AbstractPos
{ {
uint32_t line = 0; uint32_t line = 0;
uint32_t column = 0; uint32_t column = 0;
/* Return the contents of the source file. */ /**
* Return the contents of the source file.
*/
virtual std::optional<std::string> getSource() const virtual std::optional<std::string> getSource() const
{ return std::nullopt; }; { return std::nullopt; };
@ -104,8 +110,10 @@ struct ErrorInfo {
std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace); std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace);
/* BaseError should generally not be caught, as it has Interrupted as /**
a subclass. Catch Error instead. */ * BaseError should generally not be caught, as it has Interrupted as
* a subclass. Catch Error instead.
*/
class BaseError : public std::exception class BaseError : public std::exception
{ {
protected: protected:

View file

@ -12,7 +12,7 @@ namespace nix {
* *
* If you update this, dont forget to also change the map defining their * If you update this, dont forget to also change the map defining their
* string representation in the corresponding `.cc` file. * string representation in the corresponding `.cc` file.
**/ */
enum struct ExperimentalFeature enum struct ExperimentalFeature
{ {
CaDerivations, CaDerivations,

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
/* A trivial class to run a function at the end of a scope. */ /**
* A trivial class to run a function at the end of a scope.
*/
template<typename Fn> template<typename Fn>
class Finally class Finally
{ {

View file

@ -8,20 +8,25 @@
namespace nix { namespace nix {
/* Inherit some names from other namespaces for convenience. */ /**
* Inherit some names from other namespaces for convenience.
*/
using boost::format; using boost::format;
/* A variadic template that does nothing. Useful to call a function /**
for all variadic arguments but ignoring the result. */ * A variadic template that does nothing. Useful to call a function
* for all variadic arguments but ignoring the result.
*/
struct nop { template<typename... T> nop(T...) {} }; struct nop { template<typename... T> nop(T...) {} };
/* A helper for formatting strings. fmt(format, a_0, ..., a_n) is /**
equivalent to boost::format(format) % a_0 % ... % * A helper for formatting strings. fmt(format, a_0, ..., a_n) is
... a_n. However, fmt(s) is equivalent to s (so no %-expansion * equivalent to boost::format(format) % a_0 % ... %
takes place). */ * ... a_n. However, fmt(s) is equivalent to s (so no %-expansion
* takes place).
*/
template<class F> template<class F>
inline void formatHelper(F & f) inline void formatHelper(F & f)
{ {

View file

@ -8,21 +8,23 @@ namespace nix {
namespace git { namespace git {
// A line from the output of `git ls-remote --symref`. /**
// * A line from the output of `git ls-remote --symref`.
// These can be of two kinds: *
// * These can be of two kinds:
// - Symbolic references of the form *
// * - Symbolic references of the form
// ref: {target} {reference} *
// * ref: {target} {reference}
// where {target} is itself a reference and {reference} is optional *
// * where {target} is itself a reference and {reference} is optional
// - Object references of the form *
// * - Object references of the form
// {target} {reference} *
// * {target} {reference}
// where {target} is a commit id and {reference} is mandatory *
* where {target} is a commit id and {reference} is mandatory
*/
struct LsRemoteRefLine { struct LsRemoteRefLine {
enum struct Kind { enum struct Kind {
Symbolic, Symbolic,

View file

@ -33,62 +33,86 @@ struct Hash
HashType type; HashType type;
/* Create a zero-filled hash object. */ /**
* Create a zero-filled hash object.
*/
Hash(HashType type); Hash(HashType type);
/* Parse the hash from a string representation in the format /**
"[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a * Parse the hash from a string representation in the format
Subresource Integrity hash expression). If the 'type' argument * "[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a
is not present, then the hash type must be specified in the * Subresource Integrity hash expression). If the 'type' argument
string. */ * is not present, then the hash type must be specified in the
* string.
*/
static Hash parseAny(std::string_view s, std::optional<HashType> type); static Hash parseAny(std::string_view s, std::optional<HashType> type);
/* Parse a hash from a string representation like the above, except the /**
type prefix is mandatory is there is no separate arguement. */ * Parse a hash from a string representation like the above, except the
* type prefix is mandatory is there is no separate arguement.
*/
static Hash parseAnyPrefixed(std::string_view s); static Hash parseAnyPrefixed(std::string_view s);
/* Parse a plain hash that musst not have any prefix indicating the type. /**
The type is passed in to disambiguate. */ * Parse a plain hash that musst not have any prefix indicating the type.
* The type is passed in to disambiguate.
*/
static Hash parseNonSRIUnprefixed(std::string_view s, HashType type); static Hash parseNonSRIUnprefixed(std::string_view s, HashType type);
static Hash parseSRI(std::string_view original); static Hash parseSRI(std::string_view original);
private: private:
/* The type must be provided, the string view must not include <type> /**
prefix. `isSRI` helps disambigate the various base-* encodings. */ * The type must be provided, the string view must not include <type>
* prefix. `isSRI` helps disambigate the various base-* encodings.
*/
Hash(std::string_view s, HashType type, bool isSRI); Hash(std::string_view s, HashType type, bool isSRI);
public: public:
/* Check whether two hash are equal. */ /**
* Check whether two hash are equal.
*/
bool operator == (const Hash & h2) const; bool operator == (const Hash & h2) const;
/* Check whether two hash are not equal. */ /**
* Check whether two hash are not equal.
*/
bool operator != (const Hash & h2) const; bool operator != (const Hash & h2) const;
/* For sorting. */ /**
* For sorting.
*/
bool operator < (const Hash & h) const; bool operator < (const Hash & h) const;
/* Returns the length of a base-16 representation of this hash. */ /**
* Returns the length of a base-16 representation of this hash.
*/
size_t base16Len() const size_t base16Len() const
{ {
return hashSize * 2; return hashSize * 2;
} }
/* Returns the length of a base-32 representation of this hash. */ /**
* Returns the length of a base-32 representation of this hash.
*/
size_t base32Len() const size_t base32Len() const
{ {
return (hashSize * 8 - 1) / 5 + 1; return (hashSize * 8 - 1) / 5 + 1;
} }
/* Returns the length of a base-64 representation of this hash. */ /**
* Returns the length of a base-64 representation of this hash.
*/
size_t base64Len() const size_t base64Len() const
{ {
return ((4 * hashSize / 3) + 3) & ~3; return ((4 * hashSize / 3) + 3) & ~3;
} }
/* Return a string representation of the hash, in base-16, base-32 /**
or base-64. By default, this is prefixed by the hash type * Return a string representation of the hash, in base-16, base-32
(e.g. "sha256:"). */ * or base-64. By default, this is prefixed by the hash type
* (e.g. "sha256:").
*/
std::string to_string(Base base, bool includeType) const; std::string to_string(Base base, bool includeType) const;
std::string gitRev() const std::string gitRev() const
@ -104,35 +128,53 @@ public:
static Hash dummy; static Hash dummy;
}; };
/* Helper that defaults empty hashes to the 0 hash. */ /**
* Helper that defaults empty hashes to the 0 hash.
*/
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht); Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht);
/* Print a hash in base-16 if it's MD5, or base-32 otherwise. */ /**
* Print a hash in base-16 if it's MD5, or base-32 otherwise.
*/
std::string printHash16or32(const Hash & hash); std::string printHash16or32(const Hash & hash);
/* Compute the hash of the given string. */ /**
* Compute the hash of the given string.
*/
Hash hashString(HashType ht, std::string_view s); Hash hashString(HashType ht, std::string_view s);
/* Compute the hash of the given file. */ /**
* Compute the hash of the given file.
*/
Hash hashFile(HashType ht, const Path & path); Hash hashFile(HashType ht, const Path & path);
/* Compute the hash of the given path. The hash is defined as /**
(essentially) hashString(ht, dumpPath(path)). */ * Compute the hash of the given path. The hash is defined as
* (essentially) hashString(ht, dumpPath(path)).
*/
typedef std::pair<Hash, uint64_t> HashResult; typedef std::pair<Hash, uint64_t> HashResult;
HashResult hashPath(HashType ht, const Path & path, HashResult hashPath(HashType ht, const Path & path,
PathFilter & filter = defaultPathFilter); PathFilter & filter = defaultPathFilter);
/* Compress a hash to the specified number of bytes by cyclically /**
XORing bytes together. */ * Compress a hash to the specified number of bytes by cyclically
* XORing bytes together.
*/
Hash compressHash(const Hash & hash, unsigned int newSize); Hash compressHash(const Hash & hash, unsigned int newSize);
/* Parse a string representing a hash type. */ /**
* Parse a string representing a hash type.
*/
HashType parseHashType(std::string_view s); HashType parseHashType(std::string_view s);
/* Will return nothing on parse error */ /**
* Will return nothing on parse error
*/
std::optional<HashType> parseHashTypeOpt(std::string_view s); std::optional<HashType> parseHashTypeOpt(std::string_view s);
/* And the reverse. */ /**
* And the reverse.
*/
std::string_view printHashType(HashType ht); std::string_view printHashType(HashType ht);

View file

@ -6,11 +6,13 @@
namespace nix { namespace nix {
/* Highlight all the given matches in the given string `s` by wrapping /**
them between `prefix` and `postfix`. * Highlight all the given matches in the given string `s` by wrapping
* them between `prefix` and `postfix`.
If some matches overlap, then their union will be wrapped rather *
than the individual matches. */ * If some matches overlap, then their union will be wrapped rather
* than the individual matches.
*/
std::string hiliteMatches( std::string hiliteMatches(
std::string_view s, std::string_view s,
std::vector<std::smatch> matches, std::vector<std::smatch> matches,

View file

@ -217,7 +217,9 @@ extern Verbosity verbosity; /* suppress msgs > this */
#define debug(args...) printMsg(lvlDebug, args) #define debug(args...) printMsg(lvlDebug, args)
#define vomit(args...) printMsg(lvlVomit, args) #define vomit(args...) printMsg(lvlVomit, args)
/* if verbosity >= lvlWarn, print a message with a yellow 'warning:' prefix. */ /**
* if verbosity >= lvlWarn, print a message with a yellow 'warning:' prefix.
*/
template<typename... Args> template<typename... Args>
inline void warn(const std::string & fs, const Args & ... args) inline void warn(const std::string & fs, const Args & ... args)
{ {

View file

@ -7,7 +7,9 @@
namespace nix { namespace nix {
/* A simple least-recently used cache. Not thread-safe. */ /**
* A simple least-recently used cache. Not thread-safe.
*/
template<typename Key, typename Value> template<typename Key, typename Value>
class LRUCache class LRUCache
{ {
@ -31,7 +33,9 @@ public:
LRUCache(size_t capacity) : capacity(capacity) { } LRUCache(size_t capacity) : capacity(capacity) { }
/* Insert or upsert an item in the cache. */ /**
* Insert or upsert an item in the cache.
*/
void upsert(const Key & key, const Value & value) void upsert(const Key & key, const Value & value)
{ {
if (capacity == 0) return; if (capacity == 0) return;
@ -39,7 +43,9 @@ public:
erase(key); erase(key);
if (data.size() >= capacity) { if (data.size() >= capacity) {
/* Retire the oldest item. */ /**
* Retire the oldest item.
*/
auto oldest = lru.begin(); auto oldest = lru.begin();
data.erase(*oldest); data.erase(*oldest);
lru.erase(oldest); lru.erase(oldest);
@ -63,14 +69,18 @@ public:
return true; return true;
} }
/* Look up an item in the cache. If it exists, it becomes the most /**
recently used item. */ * Look up an item in the cache. If it exists, it becomes the most
* recently used item.
* */
std::optional<Value> get(const Key & key) std::optional<Value> get(const Key & key)
{ {
auto i = data.find(key); auto i = data.find(key);
if (i == data.end()) return {}; if (i == data.end()) return {};
/* Move this item to the back of the LRU list. */ /**
* Move this item to the back of the LRU list.
*/
lru.erase(i->second.first.it); lru.erase(i->second.first.it);
auto j = lru.insert(lru.end(), i); auto j = lru.insert(lru.end(), i);
i->second.first.it = j; i->second.first.it = j;

View file

@ -11,33 +11,37 @@
namespace nix { namespace nix {
/* This template class implements a simple pool manager of resources /**
of some type R, such as database connections. It is used as * This template class implements a simple pool manager of resources
follows: * of some type R, such as database connections. It is used as
* follows:
class Connection { ... }; *
* class Connection { ... };
Pool<Connection> pool; *
* Pool<Connection> pool;
{ *
auto conn(pool.get()); * {
conn->exec("select ..."); * auto conn(pool.get());
} * conn->exec("select ...");
* }
Here, the Connection object referenced by conn is automatically *
returned to the pool when conn goes out of scope. * Here, the Connection object referenced by conn is automatically
* returned to the pool when conn goes out of scope.
*/ */
template <class R> template <class R>
class Pool class Pool
{ {
public: public:
/* A function that produces new instances of R on demand. */ /**
* A function that produces new instances of R on demand.
*/
typedef std::function<ref<R>()> Factory; typedef std::function<ref<R>()> Factory;
/* A function that checks whether an instance of R is still /**
usable. Unusable instances are removed from the pool. */ * A function that checks whether an instance of R is still
* usable. Unusable instances are removed from the pool.
*/
typedef std::function<bool(const ref<R> &)> Validator; typedef std::function<bool(const ref<R> &)> Validator;
private: private:

View file

@ -6,8 +6,10 @@
namespace nix { namespace nix {
/* A simple non-nullable reference-counted pointer. Actually a wrapper /**
around std::shared_ptr that prevents null constructions. */ * A simple non-nullable reference-counted pointer. Actually a wrapper
* around std::shared_ptr that prevents null constructions.
*/
template<typename T> template<typename T>
class ref class ref
{ {

View file

@ -10,7 +10,9 @@ namespace boost::context { struct stack_context; }
namespace nix { namespace nix {
/* Abstract destination of binary data. */ /**
* Abstract destination of binary data.
*/
struct Sink struct Sink
{ {
virtual ~Sink() { } virtual ~Sink() { }
@ -18,7 +20,9 @@ struct Sink
virtual bool good() { return true; } virtual bool good() { return true; }
}; };
/* Just throws away data. */ /**
* Just throws away data.
*/
struct NullSink : Sink struct NullSink : Sink
{ {
void operator () (std::string_view data) override void operator () (std::string_view data) override
@ -32,8 +36,10 @@ struct FinishSink : virtual Sink
}; };
/* A buffered abstract sink. Warning: a BufferedSink should not be /**
used from multiple threads concurrently. */ * A buffered abstract sink. Warning: a BufferedSink should not be
* used from multiple threads concurrently.
*/
struct BufferedSink : virtual Sink struct BufferedSink : virtual Sink
{ {
size_t bufSize, bufPos; size_t bufSize, bufPos;
@ -50,19 +56,25 @@ struct BufferedSink : virtual Sink
}; };
/* Abstract source of binary data. */ /**
* Abstract source of binary data.
*/
struct Source struct Source
{ {
virtual ~Source() { } virtual ~Source() { }
/* Store exactly len bytes in the buffer pointed to by data. /**
It blocks until all the requested data is available, or throws * Store exactly len bytes in the buffer pointed to by data.
an error if it is not going to be available. */ * It blocks until all the requested data is available, or throws
* an error if it is not going to be available.
*/
void operator () (char * data, size_t len); void operator () (char * data, size_t len);
/* Store up to len in the buffer pointed to by data, and /**
return the number of bytes stored. It blocks until at least * Store up to len in the buffer pointed to by data, and
one byte is available. */ * return the number of bytes stored. It blocks until at least
* one byte is available.
*/
virtual size_t read(char * data, size_t len) = 0; virtual size_t read(char * data, size_t len) = 0;
virtual bool good() { return true; } virtual bool good() { return true; }
@ -73,8 +85,10 @@ struct Source
}; };
/* A buffered abstract source. Warning: a BufferedSource should not be /**
used from multiple threads concurrently. */ * A buffered abstract source. Warning: a BufferedSource should not be
* used from multiple threads concurrently.
*/
struct BufferedSource : Source struct BufferedSource : Source
{ {
size_t bufSize, bufPosIn, bufPosOut; size_t bufSize, bufPosIn, bufPosOut;
@ -88,12 +102,16 @@ struct BufferedSource : Source
bool hasData(); bool hasData();
protected: protected:
/* Underlying read call, to be overridden. */ /**
* Underlying read call, to be overridden.
*/
virtual size_t readUnbuffered(char * data, size_t len) = 0; virtual size_t readUnbuffered(char * data, size_t len) = 0;
}; };
/* A sink that writes data to a file descriptor. */ /**
* A sink that writes data to a file descriptor.
*/
struct FdSink : BufferedSink struct FdSink : BufferedSink
{ {
int fd; int fd;
@ -123,7 +141,9 @@ private:
}; };
/* A source that reads data from a file descriptor. */ /**
* A source that reads data from a file descriptor.
*/
struct FdSource : BufferedSource struct FdSource : BufferedSource
{ {
int fd; int fd;
@ -149,7 +169,9 @@ private:
}; };
/* A sink that writes data to a string. */ /**
* A sink that writes data to a string.
*/
struct StringSink : Sink struct StringSink : Sink
{ {
std::string s; std::string s;
@ -163,7 +185,9 @@ struct StringSink : Sink
}; };
/* A source that reads data from a string. */ /**
* A source that reads data from a string.
*/
struct StringSource : Source struct StringSource : Source
{ {
std::string_view s; std::string_view s;
@ -173,7 +197,9 @@ struct StringSource : Source
}; };
/* A sink that writes all incoming data to two other sinks. */ /**
* A sink that writes all incoming data to two other sinks.
*/
struct TeeSink : Sink struct TeeSink : Sink
{ {
Sink & sink1, & sink2; Sink & sink1, & sink2;
@ -186,7 +212,9 @@ struct TeeSink : Sink
}; };
/* Adapter class of a Source that saves all data read to a sink. */ /**
* Adapter class of a Source that saves all data read to a sink.
*/
struct TeeSource : Source struct TeeSource : Source
{ {
Source & orig; Source & orig;
@ -201,7 +229,9 @@ struct TeeSource : Source
} }
}; };
/* A reader that consumes the original Source until 'size'. */ /**
* A reader that consumes the original Source until 'size'.
*/
struct SizedSource : Source struct SizedSource : Source
{ {
Source & orig; Source & orig;
@ -219,7 +249,9 @@ struct SizedSource : Source
return n; return n;
} }
/* Consume the original source until no remain data is left to consume. */ /**
* Consume the original source until no remain data is left to consume.
*/
size_t drainAll() size_t drainAll()
{ {
std::vector<char> buf(8192); std::vector<char> buf(8192);
@ -232,7 +264,9 @@ struct SizedSource : Source
} }
}; };
/* A sink that that just counts the number of bytes given to it */ /**
* A sink that that just counts the number of bytes given to it
*/
struct LengthSink : Sink struct LengthSink : Sink
{ {
uint64_t length = 0; uint64_t length = 0;
@ -243,7 +277,9 @@ struct LengthSink : Sink
} }
}; };
/* Convert a function into a sink. */ /**
* Convert a function into a sink.
*/
struct LambdaSink : Sink struct LambdaSink : Sink
{ {
typedef std::function<void(std::string_view data)> lambda_t; typedef std::function<void(std::string_view data)> lambda_t;
@ -259,7 +295,9 @@ struct LambdaSink : Sink
}; };
/* Convert a function into a source. */ /**
* Convert a function into a source.
*/
struct LambdaSource : Source struct LambdaSource : Source
{ {
typedef std::function<size_t(char *, size_t)> lambda_t; typedef std::function<size_t(char *, size_t)> lambda_t;
@ -274,8 +312,10 @@ struct LambdaSource : Source
} }
}; };
/* Chain two sources together so after the first is exhausted, the second is /**
used */ * Chain two sources together so after the first is exhausted, the second is
* used
*/
struct ChainSource : Source struct ChainSource : Source
{ {
Source & source1, & source2; Source & source1, & source2;
@ -289,8 +329,10 @@ struct ChainSource : Source
std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun); std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun);
/* Convert a function that feeds data into a Sink into a Source. The /**
Source executes the function as a coroutine. */ * Convert a function that feeds data into a Sink into a Source. The
* Source executes the function as a coroutine.
*/
std::unique_ptr<Source> sinkToSource( std::unique_ptr<Source> sinkToSource(
std::function<void(Sink &)> fun, std::function<void(Sink &)> fun,
std::function<void()> eof = []() { std::function<void()> eof = []() {
@ -376,7 +418,9 @@ Source & operator >> (Source & in, bool & b)
Error readError(Source & source); Error readError(Source & source);
/* An adapter that converts a std::basic_istream into a source. */ /**
* An adapter that converts a std::basic_istream into a source.
*/
struct StreamToSourceAdapter : Source struct StreamToSourceAdapter : Source
{ {
std::shared_ptr<std::basic_istream<char>> istream; std::shared_ptr<std::basic_istream<char>> istream;
@ -399,12 +443,13 @@ struct StreamToSourceAdapter : Source
}; };
/* A source that reads a distinct format of concatenated chunks back into its /**
logical form, in order to guarantee a known state to the original stream, * A source that reads a distinct format of concatenated chunks back into its
even in the event of errors. * logical form, in order to guarantee a known state to the original stream,
* even in the event of errors.
Use with FramedSink, which also allows the logical stream to be terminated *
in the event of an exception. * Use with FramedSink, which also allows the logical stream to be terminated
* in the event of an exception.
*/ */
struct FramedSource : Source struct FramedSource : Source
{ {
@ -450,10 +495,11 @@ struct FramedSource : Source
} }
}; };
/* Write as chunks in the format expected by FramedSource. /**
* Write as chunks in the format expected by FramedSource.
The exception_ptr reference can be used to terminate the stream when you *
detect that an error has occurred on the remote end. * The exception_ptr reference can be used to terminate the stream when you
* detect that an error has occurred on the remote end.
*/ */
struct FramedSink : nix::BufferedSink struct FramedSink : nix::BufferedSink
{ {
@ -487,17 +533,20 @@ struct FramedSink : nix::BufferedSink
}; };
}; };
/* Stack allocation strategy for sinkToSource. /**
Mutable to avoid a boehm gc dependency in libutil. * Stack allocation strategy for sinkToSource.
* Mutable to avoid a boehm gc dependency in libutil.
boost::context doesn't provide a virtual class, so we define our own. *
* boost::context doesn't provide a virtual class, so we define our own.
*/ */
struct StackAllocator { struct StackAllocator {
virtual boost::context::stack_context allocate() = 0; virtual boost::context::stack_context allocate() = 0;
virtual void deallocate(boost::context::stack_context sctx) = 0; virtual void deallocate(boost::context::stack_context sctx) = 0;
/* The stack allocator to use in sinkToSource and potentially elsewhere. /**
It is reassigned by the initGC() method in libexpr. */ * The stack allocator to use in sinkToSource and potentially elsewhere.
* It is reassigned by the initGC() method in libexpr.
*/
static StackAllocator *defaultAllocator; static StackAllocator *defaultAllocator;
}; };

View file

@ -7,10 +7,12 @@
namespace nix { namespace nix {
// If `separator` is found, we return the portion of the string before the /**
// separator, and modify the string argument to contain only the part after the * If `separator` is found, we return the portion of the string before the
// separator. Otherwise, we return `std::nullopt`, and we leave the argument * separator, and modify the string argument to contain only the part after the
// string alone. * separator. Otherwise, we return `std::nullopt`, and we leave the argument
* string alone.
*/
static inline std::optional<std::string_view> splitPrefixTo(std::string_view & string, char separator) { static inline std::optional<std::string_view> splitPrefixTo(std::string_view & string, char separator) {
auto sepInstance = string.find(separator); auto sepInstance = string.find(separator);

View file

@ -13,7 +13,8 @@ int levenshteinDistance(std::string_view first, std::string_view second);
*/ */
class Suggestion { class Suggestion {
public: public:
int distance; // The smaller the better /// The smaller the better
int distance;
std::string suggestion; std::string suggestion;
std::string to_string() const; std::string to_string() const;
@ -43,7 +44,9 @@ public:
std::ostream & operator<<(std::ostream & str, const Suggestion &); std::ostream & operator<<(std::ostream & str, const Suggestion &);
std::ostream & operator<<(std::ostream & str, const Suggestions &); std::ostream & operator<<(std::ostream & str, const Suggestions &);
// Either a value of type `T`, or some suggestions /**
* Either a value of type `T`, or some suggestions
*/
template<typename T> template<typename T>
class OrSuggestions { class OrSuggestions {
public: public:

View file

@ -7,22 +7,22 @@
namespace nix { namespace nix {
/* This template class ensures synchronized access to a value of type /**
T. It is used as follows: * This template class ensures synchronized access to a value of type
* T. It is used as follows:
struct Data { int x; ... }; *
* struct Data { int x; ... };
Sync<Data> data; *
* Sync<Data> data;
{ *
auto data_(data.lock()); * {
data_->x = 123; * auto data_(data.lock());
} * data_->x = 123;
* }
Here, "data" is automatically unlocked when "data_" goes out of *
scope. * Here, "data" is automatically unlocked when "data_" goes out of
* scope.
*/ */
template<class T, class M = std::mutex> template<class T, class M = std::mutex>
class Sync class Sync
{ {

View file

@ -14,7 +14,7 @@ struct TarArchive {
TarArchive(const Path & path); TarArchive(const Path & path);
// disable copy constructor /// disable copy constructor
TarArchive(const TarArchive &) = delete; TarArchive(const TarArchive &) = delete;
void close(); void close();

View file

@ -13,8 +13,10 @@ namespace nix {
MakeError(ThreadPoolShutDown, Error); MakeError(ThreadPoolShutDown, Error);
/* A simple thread pool that executes a queue of work items /**
(lambdas). */ * A simple thread pool that executes a queue of work items
* (lambdas).
*/
class ThreadPool class ThreadPool
{ {
public: public:
@ -23,19 +25,30 @@ public:
~ThreadPool(); ~ThreadPool();
// FIXME: use std::packaged_task? /**
* An individual work item.
*
* \todo use std::packaged_task?
*/
typedef std::function<void()> work_t; typedef std::function<void()> work_t;
/* Enqueue a function to be executed by the thread pool. */ /**
* Enqueue a function to be executed by the thread pool.
*/
void enqueue(const work_t & t); void enqueue(const work_t & t);
/* Execute work items until the queue is empty. Note that work /**
items are allowed to add new items to the queue; this is * Execute work items until the queue is empty.
handled correctly. Queue processing stops prematurely if any *
work item throws an exception. This exception is propagated to * \note Note that work items are allowed to add new items to the
the calling thread. If multiple work items throw an exception * queue; this is handled correctly.
concurrently, only one item is propagated; the others are *
printed on stderr and otherwise ignored. */ * Queue processing stops prematurely if any work item throws an
* exception. This exception is propagated to the calling thread. If
* multiple work items throw an exception concurrently, only one
* item is propagated; the others are printed on stderr and
* otherwise ignored.
*/
void process(); void process();
private: private:
@ -62,9 +75,11 @@ private:
void shutdown(); void shutdown();
}; };
/* Process in parallel a set of items of type T that have a partial /**
ordering between them. Thus, any item is only processed after all * Process in parallel a set of items of type T that have a partial
its dependencies have been processed. */ * ordering between them. Thus, any item is only processed after all
* its dependencies have been processed.
*/
template<typename T> template<typename T>
void processGraph( void processGraph(
ThreadPool & pool, ThreadPool & pool,

View file

@ -17,7 +17,9 @@ typedef std::set<std::string> StringSet;
typedef std::map<std::string, std::string> StringMap; typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, std::string> StringPairs; typedef std::map<std::string, std::string> StringPairs;
/* Paths are just strings. */ /**
* Paths are just strings.
*/
typedef std::string Path; typedef std::string Path;
typedef std::string_view PathView; typedef std::string_view PathView;
typedef std::list<Path> Paths; typedef std::list<Path> Paths;
@ -25,15 +27,19 @@ typedef std::set<Path> PathSet;
typedef std::vector<std::pair<std::string, std::string>> Headers; typedef std::vector<std::pair<std::string, std::string>> Headers;
/* Helper class to run code at startup. */ /**
* Helper class to run code at startup.
*/
template<typename T> template<typename T>
struct OnStartup struct OnStartup
{ {
OnStartup(T && t) { t(); } OnStartup(T && t) { t(); }
}; };
/* Wrap bools to prevent string literals (i.e. 'char *') from being /**
cast to a bool in Attr. */ * Wrap bools to prevent string literals (i.e. 'char *') from being
* cast to a bool in Attr.
*/
template<typename T> template<typename T>
struct Explicit { struct Explicit {
T t; T t;
@ -45,21 +51,25 @@ struct Explicit {
}; };
/* This wants to be a little bit like rust's Cow type. /**
Some parts of the evaluator benefit greatly from being able to reuse * This wants to be a little bit like rust's Cow type.
existing allocations for strings, but have to be able to also use * Some parts of the evaluator benefit greatly from being able to reuse
newly allocated storage for values. * existing allocations for strings, but have to be able to also use
* newly allocated storage for values.
We do not define implicit conversions, even with ref qualifiers, *
since those can easily become ambiguous to the reader and can degrade * We do not define implicit conversions, even with ref qualifiers,
into copying behaviour we want to avoid. */ * since those can easily become ambiguous to the reader and can degrade
* into copying behaviour we want to avoid.
*/
class BackedStringView { class BackedStringView {
private: private:
std::variant<std::string, std::string_view> data; std::variant<std::string, std::string_view> data;
/* Needed to introduce a temporary since operator-> must return /**
a pointer. Without this we'd need to store the view object * Needed to introduce a temporary since operator-> must return
even when we already own a string. */ * a pointer. Without this we'd need to store the view object
* even when we already own a string.
*/
class Ptr { class Ptr {
private: private:
std::string_view view; std::string_view view;
@ -77,8 +87,10 @@ public:
BackedStringView(const BackedStringView &) = delete; BackedStringView(const BackedStringView &) = delete;
BackedStringView & operator=(const BackedStringView &) = delete; BackedStringView & operator=(const BackedStringView &) = delete;
/* We only want move operations defined since the sole purpose of /**
this type is to avoid copies. */ * We only want move operations defined since the sole purpose of
* this type is to avoid copies.
*/
BackedStringView(BackedStringView && other) = default; BackedStringView(BackedStringView && other) = default;
BackedStringView & operator=(BackedStringView && other) = default; BackedStringView & operator=(BackedStringView && other) = default;

View file

@ -22,21 +22,22 @@ const static std::string segmentRegex = "(?:" + pcharRegex + "*)";
const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)"; const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)"; const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
// A Git ref (i.e. branch or tag name). /// A Git ref (i.e. branch or tag name).
const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*"; // FIXME: check /// \todo check that this is correct.
const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*";
extern std::regex refRegex; extern std::regex refRegex;
// Instead of defining what a good Git Ref is, we define what a bad Git Ref is /// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
// This is because of the definition of a ref in refs.c in https://github.com/git/git /// This is because of the definition of a ref in refs.c in https://github.com/git/git
// See tests/fetchGitRefs.sh for the full definition /// See tests/fetchGitRefs.sh for the full definition
const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$"; const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
extern std::regex badGitRefRegex; extern std::regex badGitRefRegex;
// A Git revision (a SHA-1 commit hash). /// A Git revision (a SHA-1 commit hash).
const static std::string revRegexS = "[0-9a-fA-F]{40}"; const static std::string revRegexS = "[0-9a-fA-F]{40}";
extern std::regex revRegex; extern std::regex revRegex;
// A ref or revision, or a ref followed by a revision. /// A ref or revision, or a ref followed by a revision.
const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))"; const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))";
const static std::string flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*"; const static std::string flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*";

View file

@ -7,7 +7,8 @@ namespace nix {
struct ParsedURL struct ParsedURL
{ {
std::string url; std::string url;
std::string base; // URL without query/fragment /// URL without query/fragment
std::string base;
std::string scheme; std::string scheme;
std::optional<std::string> authority; std::optional<std::string> authority;
std::string path; std::string path;
@ -28,7 +29,7 @@ std::map<std::string, std::string> decodeQuery(const std::string & query);
ParsedURL parseURL(const std::string & url); ParsedURL parseURL(const std::string & url);
/* /**
* Although thats not really standardized anywhere, an number of tools * Although thats not really standardized anywhere, an number of tools
* use a scheme of the form 'x+y' in urls, where y is the transport layer * use a scheme of the form 'x+y' in urls, where y is the transport layer
* scheme, and x is the application layer scheme. * scheme, and x is the application layer scheme.