Skip to content

Commit

Permalink
Merge pull request managarm#693 from no92/mbus-disjunction
Browse files Browse the repository at this point in the history
  • Loading branch information
no92 authored Jul 11, 2024
2 parents 04ec361 + 214b7c8 commit b732734
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 59 deletions.
83 changes: 58 additions & 25 deletions mbus/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ async::result<helix::UniqueDescriptor> Entity::bind() {

struct EqualsFilter;
struct Conjunction;
struct Disjunction;

using AnyFilter = std::variant<
EqualsFilter,
Conjunction
Conjunction,
Disjunction
>;

struct EqualsFilter {
Expand All @@ -109,17 +111,41 @@ struct EqualsFilter {
};

struct Conjunction {
explicit Conjunction(std::vector<AnyFilter> operands)
: _operands(std::move(operands)) { }
explicit Conjunction(std::vector<AnyFilter> operands);

const std::vector<AnyFilter> &getOperands() const {
return _operands;
}
const std::vector<AnyFilter> &getOperands() const;

private:
std::vector<AnyFilter> _operands;
std::vector<AnyFilter> operands_;
};

struct Disjunction {
explicit Disjunction(std::vector<AnyFilter> operands);

const std::vector<AnyFilter> &getOperands() const;

private:
std::vector<AnyFilter> operands_;
};

Conjunction::Conjunction(std::vector<AnyFilter> operands)
: operands_{std::move(operands)} {

}

const std::vector<AnyFilter> &Conjunction::getOperands() const {
return operands_;
}

Disjunction::Disjunction(std::vector<AnyFilter> operands)
: operands_{std::move(operands)} {

}

const std::vector<AnyFilter> &Disjunction::getOperands() const {
return operands_;
}

static bool matchesFilter(const Entity *entity, const AnyFilter &filter) {
if(auto real = std::get_if<EqualsFilter>(&filter); real) {
auto &properties = entity->getProperties();
Expand All @@ -132,6 +158,11 @@ static bool matchesFilter(const Entity *entity, const AnyFilter &filter) {
return std::all_of(operands.begin(), operands.end(), [&] (const AnyFilter &operand) {
return matchesFilter(entity, operand);
});
}else if(auto real = std::get_if<Disjunction>(&filter); real) {
auto &operands = real->getOperands();
return std::any_of(operands.begin(), operands.end(), [&] (const AnyFilter &operand) {
return matchesFilter(entity, operand);
});
}else{
throw std::runtime_error("Unexpected filter");
}
Expand Down Expand Up @@ -161,28 +192,30 @@ std::shared_ptr<Entity> getEntityById(int64_t id) {
}

static AnyFilter decodeFilter(managarm::mbus::AnyFilter &protoFilter) {
// HACK(qookie): This is a massive hack. I thought bragi had "has_foo" getters, but
// apparently I misremembered... We should add them, but for now this
// will suffice (and I think we'll get rid of filters on the protocol
// level anyway).
// If the equals filter value is empty, assume this is actually a conjunction.
if (protoFilter.equals_filter().value().size() == 0) {
std::vector<AnyFilter> operands;
for(auto &protoOperand : protoFilter.conjunction().operands()) {
operands.push_back(EqualsFilter{
protoOperand.path(),
protoOperand.value()
});
switch(protoFilter.type()) {
case managarm::mbus::FilterType::EQUALS: {
return EqualsFilter{protoFilter.path(), protoFilter.value()};
}
case managarm::mbus::FilterType::CONJUNCTION: {
std::vector<AnyFilter> operands;
for(auto &op : protoFilter.operands()) {
operands.push_back(decodeFilter(op));
}
return Conjunction{operands};
}
case managarm::mbus::FilterType::DISJUNCTION: {
std::vector<AnyFilter> operands;
for(auto &op : protoFilter.operands()) {
operands.push_back(decodeFilter(op));
}
return Disjunction{operands};
}
default: {
throw std::runtime_error("Unexpected filter type");
}
return Conjunction(std::move(operands));
} else {
return EqualsFilter{protoFilter.equals_filter().path(),
protoFilter.equals_filter().value()};
}
}



async::result<std::tuple<uint64_t, uint64_t>>
tryEnumerate(managarm::mbus::EnumerateResponse &resp, uint64_t inSeq, const AnyFilter &filter) {
auto actualSeq = co_await globalSeq.async_wait(inSeq);
Expand Down
18 changes: 14 additions & 4 deletions protocols/mbus/include/protocols/mbus/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ using EntityId = int64_t;
struct NoFilter;
struct EqualsFilter;
struct Conjunction;
struct Disjunction;

using AnyFilter = std::variant<
NoFilter,
EqualsFilter,
Conjunction
Conjunction,
Disjunction
>;

struct NoFilter { };
Expand All @@ -48,10 +50,18 @@ struct EqualsFilter {
};

struct Conjunction {
Conjunction(std::vector<AnyFilter> &&operands)
: operands_{std::move(operands)} { }
Conjunction(std::vector<AnyFilter> &&operands);

const std::vector<AnyFilter> &operands() const & { return operands_; }
const std::vector<AnyFilter> &operands() const &;

private:
std::vector<AnyFilter> operands_;
};

struct Disjunction {
Disjunction(std::vector<AnyFilter> &&operands);

const std::vector<AnyFilter> &operands() const &;

private:
std::vector<AnyFilter> operands_;
Expand Down
21 changes: 8 additions & 13 deletions protocols/mbus/mbus.bragi
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,18 @@ struct Property {
}
}

struct EqualsFilter {
string path;
string value;
}

// TODO(qookie): Maybe this should just be merged straight into AnyFilter?
struct Conjunction {
// TODO(qookie): Bring back ability to nest Conjunctions together?
// Seems pointless unless we also add a Disjunction
// and let the user do AND(..., OR(..., AND(...)))
EqualsFilter[] operands;
enum FilterType {
EQUALS,
CONJUNCTION,
DISJUNCTION
}

struct AnyFilter {
FilterType type;
tags {
tag(1) EqualsFilter equals_filter;
tag(2) Conjunction conjunction;
tag(1) string path;
tag(2) string value;
tag(3) AnyFilter[] operands;
}
}

Expand Down
57 changes: 40 additions & 17 deletions protocols/mbus/src/client_ng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,37 +217,34 @@ async::result<Result<void>> EntityManager::serveRemoteLane(helix::UniqueLane lan
// mbus Enumerator class.
// ------------------------------------------------------------------------

static void encodeFilter(const AnyFilter &filter, auto &msg) {
static const managarm::mbus::AnyFilter encodeFilter(const AnyFilter &filter) {
managarm::mbus::AnyFilter flt;

if(auto alt = std::get_if<EqualsFilter>(&filter); alt) {
managarm::mbus::EqualsFilter eqf;
eqf.set_path(alt->path());
eqf.set_value(alt->value());
flt.set_equals_filter(std::move(eqf));
flt.set_type(managarm::mbus::FilterType::EQUALS);
flt.set_path(alt->path());
flt.set_value(alt->value());
}else if(auto alt = std::get_if<Conjunction>(&filter); alt) {
managarm::mbus::Conjunction conj;
flt.set_type(managarm::mbus::FilterType::CONJUNCTION);
for(auto &operand : alt->operands()) {
auto eqf = std::get_if<EqualsFilter>(&operand);
assert(eqf && "Sorry, unimplemented: Non-EqualsFilter in Conjunction");

managarm::mbus::EqualsFilter flt{};

flt.set_path(eqf->path());
flt.set_value(eqf->value());
conj.add_operands(std::move(flt));
flt.add_operands(encodeFilter(operand));
}
}else if(auto alt = std::get_if<Disjunction>(&filter); alt) {
flt.set_type(managarm::mbus::FilterType::DISJUNCTION);
for(auto &operand : alt->operands()) {
flt.add_operands(encodeFilter(operand));
}
flt.set_conjunction(std::move(conj));
}else{
throw std::runtime_error("Unexpected filter type");
}

msg.set_filter(std::move(flt));
return flt;
}

async::result<Result<EnumerationResult>> Enumerator::nextEvents() {
managarm::mbus::EnumerateRequest req;
req.set_seq(curSeq_);
encodeFilter(filter_, req);
req.set_filter(encodeFilter(filter_));

auto [offer, sendHead, sendTail, recvRespHead] =
co_await helix_ng::exchangeMsgs(
Expand Down Expand Up @@ -311,4 +308,30 @@ async::result<Result<EnumerationResult>> Enumerator::nextEvents() {
co_return result;
}

// ------------------------------------------------------------------------
// mbus Conjunction class.
// ------------------------------------------------------------------------

Conjunction::Conjunction(std::vector<AnyFilter> &&operands)
: operands_{std::move(operands)} {

}

const std::vector<AnyFilter> &Conjunction::operands() const & {
return operands_;
}

// ------------------------------------------------------------------------
// mbus Disjunction class.
// ------------------------------------------------------------------------

Disjunction::Disjunction(std::vector<AnyFilter> &&operands)
: operands_{std::move(operands)} {

}

const std::vector<AnyFilter> &Disjunction::operands() const & {
return operands_;
}

} // namespace mbus_ng

0 comments on commit b732734

Please sign in to comment.