diff --git a/src/libutil/include/nix/util/serialise.hh b/src/libutil/include/nix/util/serialise.hh index d6845a494..1bf06c2e8 100644 --- a/src/libutil/include/nix/util/serialise.hh +++ b/src/libutil/include/nix/util/serialise.hh @@ -230,10 +230,18 @@ struct StringSink : Sink void operator()(std::string_view data) override; }; +/** + * Source type that can be restarted. + */ +struct RestartableSource : Source +{ + virtual void restart() = 0; +}; + /** * A source that reads data from a string. */ -struct StringSource : Source +struct StringSource : RestartableSource { std::string_view s; size_t pos; @@ -257,8 +265,22 @@ struct StringSource : Source size_t read(char * data, size_t len) override; void skip(size_t len) override; + + void restart() override + { + pos = 0; + } }; +/** + * Create a restartable Source from a factory function. + * + * @param factory Factory function that returns a fresh instance of the Source. Gets + * called for each source restart. + * @pre factory must return an equivalent source for each invocation. + */ +std::unique_ptr restartableSourceFromFactory(std::function()> factory); + /** * A sink that writes all incoming data to two other sinks. */ diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc index ba153625e..51cf48d9a 100644 --- a/src/libutil/serialise.cc +++ b/src/libutil/serialise.cc @@ -513,4 +513,41 @@ size_t ChainSource::read(char * data, size_t len) } } +std::unique_ptr restartableSourceFromFactory(std::function()> factory) +{ + struct RestartableSourceImpl : RestartableSource + { + RestartableSourceImpl(decltype(factory) factory_) + : factory_(std::move(factory_)) + , impl(this->factory_()) + { + } + + decltype(factory) factory_; + std::unique_ptr impl = factory_(); + + size_t read(char * data, size_t len) override + { + return impl->read(data, len); + } + + bool good() override + { + return impl->good(); + } + + void skip(size_t len) override + { + return impl->skip(len); + } + + void restart() override + { + impl = factory_(); + } + }; + + return std::make_unique(std::move(factory)); +} + } // namespace nix