Skip to content

Commit

Permalink
WIP make it bidirectional and use for type = tarball
Browse files Browse the repository at this point in the history
  • Loading branch information
roberth committed Jan 9, 2024
1 parent 7fef87c commit f014413
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/libexpr/value.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include "symbol-table.hh"
#include "value/context.hh"
#include "input-accessor.hh"
#include "libfetchers/input-accessor.hh"

#if HAVE_BOEHMGC
#include <gc/gc_allocator.h>
Expand Down
12 changes: 12 additions & 0 deletions src/libfetchers/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ namespace nix::fetchers {
throw Error("expected a string, but value is of type " + attrType(in));
}

nix::fetchers::Attr parsers::String::unparse (const std::string & in) const {
return in;
}

// parsers::Int

std::shared_ptr<Schema> parsers::Int::getSchema() const {
Expand All @@ -31,6 +35,10 @@ namespace nix::fetchers {
throw Error("expected an int, but value is of type " + attrType(in));
}

nix::fetchers::Attr parsers::Int::unparse (const uint64_t & in) const {
return in;
}

// parsers::Bool

std::shared_ptr<Schema> parsers::Bool::getSchema() const {
Expand All @@ -44,4 +52,8 @@ namespace nix::fetchers {
else
throw Error("expected a bool, but value is of type " + attrType(in));
}

nix::fetchers::Attr parsers::Bool::unparse (const bool & in) const {
return Explicit<bool>{in};
}
}
146 changes: 138 additions & 8 deletions src/libfetchers/parser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

#include "attrs.hh"
#include "error.hh"
#include "libexpr/nixexpr.hh"
#include "schema.hh"
#include "map.hh"
#include <cstdint>
#include <memory>
#include <string>

namespace nix::fetchers {

Expand All @@ -26,6 +28,11 @@ namespace nix::fetchers {

virtual std::shared_ptr<Schema> getSchema() const = 0;
virtual Out parse (const In & in) const = 0;
virtual In unparse (const Out & out) const = 0;
virtual std::string show(const Out_ & out) const {
// FIXME
return "<error>";
};
};

namespace parsers {
Expand All @@ -35,22 +42,58 @@ namespace nix::fetchers {
public:
std::shared_ptr<Schema> getSchema() const override;
std::string parse(const Attr & in) const override;
Attr unparse(const std::string & out) const override;
// std::string show(const std::string & out) const override;
};

/** Accepts an int `Attr`. Rejects the other types. */
class Int : public Parser<Attr, uint64_t> {
public:
std::shared_ptr<Schema> getSchema() const override;
uint64_t parse(const Attr & in) const override;
Attr unparse(const uint64_t & out) const override;
// std::string show(const uint64_t & out) const override;
};

/** Accepts a bool `Attr`. Rejects the other types. */
class Bool : public Parser<Attr, bool> {
public:
std::shared_ptr<Schema> getSchema() const override;
bool parse(const Attr & in) const override;
Attr unparse(const bool & out) const override;
// std::string show(const bool & out) const override;
};

// TODO
// template <typename Out>
// class Enum : public Parser<Attr, Out> {
// std::map<Attr, Out> values;
// std::map<Out, Attr> reverseValues;

// public:
// Enum(std::map<Attr, Out> values) : values(values) {}

// std::shared_ptr<Schema> getSchema() const override {
// // FIXME
// throw Error("not implemented");
// }

// Out parse(const Attr & in) const override {
// auto it = values.find(in);
// if (it != values.end()) {
// return it->second;
// } else {
// throw Error("expected one of: %s", mapJoin(values, ", ", [](auto & pair) {
// return pair.first.toString();
// }));
// }
// }

// std::string show(const Out & out) const override {
// throw UnimplementedError("Enum.show");
// }
// };

template <typename Out>
class Attr : public Parser<std::optional<nix::fetchers::Attr>, Out>{
public:
Expand All @@ -59,6 +102,8 @@ namespace nix::fetchers {

virtual Out parse(const std::optional<nix::fetchers::Attr> & in) const override = 0;

// virtual std::optional<nix::fetchers::Attr> unparse(const Out & out) const override = 0;

virtual bool isRequired() const = 0;

std::shared_ptr<Schema> getSchema() const override {
Expand All @@ -69,10 +114,17 @@ namespace nix::fetchers {

virtual std::shared_ptr<Schema> getAttrValueSchema() const = 0;

virtual std::optional<std::string> showDefaultValue() const {
return std::nullopt;
}

// std::string show(const Out & out) const override;

Schema::Attrs::Attr getAttrSchema() {
Schema::Attrs::Attr attrSchema;
attrSchema.type = getAttrValueSchema();
attrSchema.required = isRequired();
attrSchema.defaultValue = showDefaultValue();
return attrSchema;
}
};
Expand All @@ -88,13 +140,14 @@ namespace nix::fetchers {
}
}

template <typename Parser>
template <typename From, typename Parser>
class OptionalAttr : public Attr<std::optional<typename Parser::Out>> {
Parser parser;
std::function<std::optional<typename Parser::Out>(const From &)> restore;

public:
OptionalAttr(std::string name, Parser parser)
: Attr<std::optional<typename Parser::Out>>(name), parser(parser) {}
OptionalAttr(std::string name, Parser parser, std::function<std::optional<typename Parser::Out>(const From &)> restore)
: Attr<std::optional<typename Parser::Out>>(name), parser(parser), restore(restore) {}

bool isRequired() const override { return false; }

Expand All @@ -107,18 +160,32 @@ namespace nix::fetchers {
}
}

std::optional<nix::fetchers::Attr> unparse(const std::optional<typename Parser::Out> & out) const override {
// "map"
if (out) {
return parser.unparse(*out);
} else {
return std::nullopt;
}
}

std::optional<nix::fetchers::Attr> unparseAttr(const From & out) const {
return unparse(restore(out));
}

std::shared_ptr<Schema> getAttrValueSchema() const override {
return parser.getSchema();
}
};

template <typename Parser>
template <typename From, typename Parser>
class RequiredAttr : public Attr<typename Parser::Out> {
Parser parser;
std::function<typename Parser::Out(const From &)> restore;

public:
RequiredAttr(std::string name, Parser parser)
: Attr<typename Parser::Out>(name), parser(parser) {}
RequiredAttr(std::string name, Parser parser, std::function<typename Parser::Out(const From &)> restore)
: Attr<typename Parser::Out>(name), parser(parser), restore(restore) {}

bool isRequired() const override { return true; }

Expand All @@ -130,11 +197,58 @@ namespace nix::fetchers {
}
}

std::optional<nix::fetchers::Attr> unparse(const typename Parser::Out & out) const override {
return parser.unparse(out);
}

std::optional<nix::fetchers::Attr> unparseAttr(const From & out) const {
return unparse(restore(out));
}

std::shared_ptr<Schema> getAttrValueSchema() const override {
return parser.getSchema();
}
};

template <typename From, typename Parser>
class DefaultAttr : public Attr<typename Parser::Out> {
Parser parser;
typename Parser::Out defaultValue;
std::function<typename Parser::Out(const From &)> restore;

public:
DefaultAttr(std::string name, Parser parser, typename Parser::Out defaultValue, std::function<typename Parser::Out(const From &)> restore)
: Attr<typename Parser::Out>(name), parser(parser), defaultValue(defaultValue), restore(restore) {}

bool isRequired() const override { return false; }

typename Parser::Out parse(const std::optional<nix::fetchers::Attr> & in) const override {
if (in) {
return parser.parse(*in);
} else {
return defaultValue;
}
}

std::optional<nix::fetchers::Attr> unparse(const typename Parser::Out & out) const override {
// We might do this, but then the output is less useful.
// if (out == defaultValue)
// return std::nullopt;
return parser.unparse(out);
}

std::optional<nix::fetchers::Attr> unparseAttr(const From & out) const {
return unparse(restore(out));
}

std::optional<std::string> showDefaultValue() const override {
return parser.show(defaultValue);
}

std::shared_ptr<Schema> getAttrValueSchema() const override {
return parser.getSchema();
}
};

/**
Perform a side effect for each item in a tuple. `f` must be callable for each item.
Expand Down Expand Up @@ -181,13 +295,13 @@ namespace nix::fetchers {
Schema::Attrs attrSchema;

traverse_(
[this, &attrSchema](auto * parser) {
[&attrSchema](auto * parser) {
attrSchema.attrs[parser->name] = parser->getAttrSchema();
},
this->parsers
);

schema = std::make_shared<Schema>(attrSchema);
schema = std::make_shared<Schema>(Schema(attrSchema));
this->attrSchema = std::get_if<Schema::Attrs>(&schema->choice);
assert(this->attrSchema);
}
Expand All @@ -206,6 +320,22 @@ namespace nix::fetchers {
);
}

nix::fetchers::Attrs unparse(const std::invoke_result_t<Callable, typename AttrParsers::Out ...> & out) const override {
nix::fetchers::Attrs ret;
// for each of the parsers, unparse the output and add it to the attrs in ret
traverse_(
[&ret, &out](auto * parser) {
auto attr = parser->unparseAttr(out);
if (attr) {
ret[parser->name] = *attr;
}
},
parsers
);

return ret;
}

std::shared_ptr<Schema> getSchema() const override {
return schema;
}
Expand Down
6 changes: 4 additions & 2 deletions src/libfetchers/schema.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <map>
#include <memory>
#include <optional>
#include <variant>
#include <array>

Expand All @@ -20,6 +21,7 @@ struct Schema {
struct Attr {
bool required;
std::shared_ptr<Schema> type;
std::optional<std::string> defaultValue;
bool operator==(const Attr & other) const;
};
std::map<std::string, Attr> attrs;
Expand All @@ -43,8 +45,8 @@ struct Schema {
std::variant<Primitive, Attrs> choice;
bool operator==(const Schema & other) const;

Schema(Primitive && p) : choice(p) {};
Schema(Attrs && p) : choice(p) {};
Schema(Primitive p) : choice(p) {};
Schema(Attrs p) : choice(p) {};
};

}
Loading

0 comments on commit f014413

Please sign in to comment.