diff --git a/mbus/src/main.cpp b/mbus/src/main.cpp index 71e861a0a..fafe33ff4 100644 --- a/mbus/src/main.cpp +++ b/mbus/src/main.cpp @@ -90,10 +90,12 @@ async::result Entity::bind() { struct EqualsFilter; struct Conjunction; +struct Disjunction; using AnyFilter = std::variant< EqualsFilter, - Conjunction + Conjunction, + Disjunction >; struct EqualsFilter { @@ -109,17 +111,41 @@ struct EqualsFilter { }; struct Conjunction { - explicit Conjunction(std::vector operands) - : _operands(std::move(operands)) { } + explicit Conjunction(std::vector operands); - const std::vector &getOperands() const { - return _operands; - } + const std::vector &getOperands() const; private: - std::vector _operands; + std::vector operands_; }; +struct Disjunction { + explicit Disjunction(std::vector operands); + + const std::vector &getOperands() const; + +private: + std::vector operands_; +}; + +Conjunction::Conjunction(std::vector operands) + : operands_{std::move(operands)} { + +} + +const std::vector &Conjunction::getOperands() const { + return operands_; +} + +Disjunction::Disjunction(std::vector operands) + : operands_{std::move(operands)} { + +} + +const std::vector &Disjunction::getOperands() const { + return operands_; +} + static bool matchesFilter(const Entity *entity, const AnyFilter &filter) { if(auto real = std::get_if(&filter); real) { auto &properties = entity->getProperties(); @@ -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(&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"); } @@ -161,28 +192,30 @@ std::shared_ptr 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 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 operands; + for(auto &op : protoFilter.operands()) { + operands.push_back(decodeFilter(op)); + } + return Conjunction{operands}; + } + case managarm::mbus::FilterType::DISJUNCTION: { + std::vector 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> tryEnumerate(managarm::mbus::EnumerateResponse &resp, uint64_t inSeq, const AnyFilter &filter) { auto actualSeq = co_await globalSeq.async_wait(inSeq); diff --git a/protocols/mbus/include/protocols/mbus/client.hpp b/protocols/mbus/include/protocols/mbus/client.hpp index ef3a1549a..bf021f490 100644 --- a/protocols/mbus/include/protocols/mbus/client.hpp +++ b/protocols/mbus/include/protocols/mbus/client.hpp @@ -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 { }; @@ -48,10 +50,18 @@ struct EqualsFilter { }; struct Conjunction { - Conjunction(std::vector &&operands) - : operands_{std::move(operands)} { } + Conjunction(std::vector &&operands); - const std::vector &operands() const & { return operands_; } + const std::vector &operands() const &; + +private: + std::vector operands_; +}; + +struct Disjunction { + Disjunction(std::vector &&operands); + + const std::vector &operands() const &; private: std::vector operands_; diff --git a/protocols/mbus/mbus.bragi b/protocols/mbus/mbus.bragi index 4fb4d3236..7080c8abf 100644 --- a/protocols/mbus/mbus.bragi +++ b/protocols/mbus/mbus.bragi @@ -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; } } diff --git a/protocols/mbus/src/client_ng.cpp b/protocols/mbus/src/client_ng.cpp index dc427d9e2..5b60e8d53 100644 --- a/protocols/mbus/src/client_ng.cpp +++ b/protocols/mbus/src/client_ng.cpp @@ -217,37 +217,34 @@ async::result> 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(&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(&filter); alt) { - managarm::mbus::Conjunction conj; + flt.set_type(managarm::mbus::FilterType::CONJUNCTION); for(auto &operand : alt->operands()) { - auto eqf = std::get_if(&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(&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> 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( @@ -311,4 +308,30 @@ async::result> Enumerator::nextEvents() { co_return result; } +// ------------------------------------------------------------------------ +// mbus Conjunction class. +// ------------------------------------------------------------------------ + +Conjunction::Conjunction(std::vector &&operands) + : operands_{std::move(operands)} { + +} + +const std::vector &Conjunction::operands() const & { + return operands_; +} + +// ------------------------------------------------------------------------ +// mbus Disjunction class. +// ------------------------------------------------------------------------ + +Disjunction::Disjunction(std::vector &&operands) + : operands_{std::move(operands)} { + +} + +const std::vector &Disjunction::operands() const & { + return operands_; +} + } // namespace mbus_ng