| Directory: | ./ |
|---|---|
| File: | pdcom5/src/Subscription.cpp |
| Date: | 2025-10-26 04:10:09 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 40 | 85 | 47.1% |
| Branches: | 21 | 182 | 11.5% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * Copyright (C) 2021 Richard Hacker (lerichi at gmx dot net), | ||
| 4 | * Florian Pose (fp at igh dot de), | ||
| 5 | * Bjarne von Horn (vh at igh dot de). | ||
| 6 | * | ||
| 7 | * This file is part of the PdCom library. | ||
| 8 | * | ||
| 9 | * The PdCom library is free software: you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU Lesser General Public License as published by | ||
| 11 | * the Free Software Foundation, either version 3 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | * | ||
| 14 | * The PdCom library is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
| 17 | * License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Lesser General Public License | ||
| 20 | * along with the PdCom library. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | * | ||
| 22 | *****************************************************************************/ | ||
| 23 | |||
| 24 | #include "Subscription.h" | ||
| 25 | |||
| 26 | #include "Process.h" | ||
| 27 | #include "TemplateVodoo.inc" | ||
| 28 | #include "Variable.h" | ||
| 29 | |||
| 30 | #include <algorithm> | ||
| 31 | #include <array> | ||
| 32 | #include <cstring> | ||
| 33 | #include <pdcom5/Exception.h> | ||
| 34 | #include <pdcom5/Subscriber.h> | ||
| 35 | #include <pdcom5/Subscription.h> | ||
| 36 | #include <sstream> | ||
| 37 | |||
| 38 | |||
| 39 | using PdCom::Subscription; | ||
| 40 | |||
| 41 | ✗ | Subscription::Subscription(Subscription &&s) noexcept : | |
| 42 | ✗ | pimpl(std::move(s.pimpl)), state_(s.state_) | |
| 43 | { | ||
| 44 | ✗ | if (pimpl) | |
| 45 | ✗ | pimpl->This_ = this; | |
| 46 | ✗ | s.state_ = State::Invalid; | |
| 47 | } | ||
| 48 | |||
| 49 | |||
| 50 | 56 | Subscription::Subscription( | |
| 51 | PdCom::Subscriber &subscriber, | ||
| 52 | const PdCom::Variable &variable, | ||
| 53 | 56 | const PdCom::Selector &selector) | |
| 54 | { | ||
| 55 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
|
56 | if (!selector.impl_) |
| 56 | ✗ | throw InvalidArgument("Selector must not be null"); | |
| 57 |
1/2✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
|
112 | pimpl = PdCom::impl::Variable::subscribe( |
| 58 | 112 | this, variable, subscriber, selector); | |
| 59 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
|
56 | if (!pimpl) |
| 60 | ✗ | throw InvalidSubscription(); | |
| 61 |
1/2✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
|
56 | pimpl->path_ = variable.getPath(); |
| 62 | 56 | } | |
| 63 | |||
| 64 | 28 | Subscription::Subscription( | |
| 65 | PdCom::Subscriber &subscriber, | ||
| 66 | PdCom::Process &process, | ||
| 67 | const std::string &path, | ||
| 68 | 29 | const PdCom::Selector &selector) | |
| 69 | { | ||
| 70 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
|
28 | if (!selector.impl_) |
| 71 | ✗ | throw InvalidArgument("Selector must not be null"); | |
| 72 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
56 | pimpl = PdCom::impl::Process::fromUApi(process).subscribe( |
| 73 | 56 | this, path, subscriber, selector); | |
| 74 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 27 times.
|
28 | if (!pimpl) |
| 75 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | throw InvalidSubscription(); |
| 76 |
1/2✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
|
27 | pimpl->path_ = path; |
| 77 | 27 | } | |
| 78 | |||
| 79 | 67 | Subscription &Subscription::operator=(Subscription &&p) noexcept | |
| 80 | { | ||
| 81 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | if (&p == this) |
| 82 | ✗ | return *this; | |
| 83 | 67 | std::swap(p.pimpl, pimpl); | |
| 84 | 67 | std::swap(p.state_, state_); | |
| 85 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 65 times.
|
67 | if (pimpl) |
| 86 | 2 | pimpl->This_ = this; | |
| 87 |
2/2✓ Branch 2 taken 65 times.
✓ Branch 3 taken 2 times.
|
67 | if (p.pimpl) |
| 88 | 65 | p.pimpl->This_ = &p; | |
| 89 | 67 | return *this; | |
| 90 | } | ||
| 91 | |||
| 92 | 13 | void Subscription::poll() | |
| 93 | { | ||
| 94 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
13 | if (pimpl) |
| 95 | 13 | pimpl->poll(); | |
| 96 | else | ||
| 97 | ✗ | throw InvalidSubscription(); | |
| 98 | 13 | } | |
| 99 | |||
| 100 | 1277 | const void *Subscription::getData() const | |
| 101 | { | ||
| 102 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1277 times.
|
1277 | if (!pimpl) |
| 103 | ✗ | throw InvalidSubscription(); | |
| 104 | 1277 | return pimpl->getData(); | |
| 105 | } | ||
| 106 | |||
| 107 | 2508 | PdCom::Variable Subscription::getVariable() const | |
| 108 | { | ||
| 109 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2508 times.
|
2508 | if (!pimpl) |
| 110 | ✗ | throw InvalidSubscription(); | |
| 111 | 2508 | return PdCom::impl::Variable::toUApi(pimpl->variable_); | |
| 112 | } | ||
| 113 | |||
| 114 | ✗ | PdCom::Process *Subscription::getProcess() const | |
| 115 | { | ||
| 116 | ✗ | if (!pimpl) | |
| 117 | ✗ | throw InvalidSubscription(); | |
| 118 | ✗ | if (auto p = pimpl->process_.lock()) { | |
| 119 | ✗ | return p->This; | |
| 120 | } | ||
| 121 | ✗ | throw ProcessGoneAway(); | |
| 122 | } | ||
| 123 | |||
| 124 | ✗ | std::string Subscription::getPath() const | |
| 125 | { | ||
| 126 | ✗ | if (!pimpl) | |
| 127 | ✗ | throw InvalidSubscription(); | |
| 128 | ✗ | return pimpl->path_; | |
| 129 | } | ||
| 130 | |||
| 131 | 56 | std::shared_ptr<PdCom::impl::Subscription> PdCom::impl::Variable::subscribe( | |
| 132 | PdCom::Subscription *subscription, | ||
| 133 | const PdCom::Variable &var, | ||
| 134 | PdCom::Subscriber &subscriber, | ||
| 135 | const PdCom::Selector &selector) | ||
| 136 | { | ||
| 137 |
1/2✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
|
112 | auto impl_var = fromUApi(var); |
| 138 |
1/2✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
|
112 | if (const auto p = impl_var->process.lock()) |
| 139 | return p->subscribe( | ||
| 140 |
1/2✓ Branch 7 taken 56 times.
✗ Branch 8 not taken.
|
112 | subscription, std::move(impl_var), subscriber, selector); |
| 141 | else | ||
| 142 | ✗ | throw ProcessGoneAway(); | |
| 143 | } | ||
| 144 | |||
| 145 | |||
| 146 | namespace { | ||
| 147 | template <class T> | ||
| 148 | ✗ | inline T convert(T val) | |
| 149 | { | ||
| 150 | ✗ | return val; | |
| 151 | } | ||
| 152 | ✗ | inline int convert(int8_t val) | |
| 153 | { | ||
| 154 | ✗ | return val; | |
| 155 | } | ||
| 156 | ✗ | inline unsigned convert(uint8_t val) | |
| 157 | { | ||
| 158 | ✗ | return val; | |
| 159 | } | ||
| 160 | |||
| 161 | template <class T> | ||
| 162 | struct Printer | ||
| 163 | { | ||
| 164 | static void | ||
| 165 | ✗ | print(std::ostream &os, const void *buf, char delim, size_t nelem) | |
| 166 | { | ||
| 167 | ✗ | const T *value = reinterpret_cast<const T *>(buf); | |
| 168 | |||
| 169 | ✗ | if (nelem > 1) | |
| 170 | ✗ | os << '['; | |
| 171 | |||
| 172 | ✗ | for (size_t i = 0; i < nelem; ++i) { | |
| 173 | ✗ | if (i) | |
| 174 | ✗ | os << delim; | |
| 175 | ✗ | os << convert(*value++); | |
| 176 | } | ||
| 177 | |||
| 178 | ✗ | if (nelem > 1) | |
| 179 | ✗ | os << ']'; | |
| 180 | } | ||
| 181 | }; | ||
| 182 | |||
| 183 | using printFn = void (*)(std::ostream &, const void *, char, size_t); | ||
| 184 | |||
| 185 | template <PdCom::TypeInfo::DataType... src_types> | ||
| 186 | constexpr std::array<printFn, sizeof...(src_types)> | ||
| 187 | getPrintFns(sequence<src_types...>) | ||
| 188 | { | ||
| 189 | return {{Printer<typename PdCom::details::DataTypeTraits< | ||
| 190 | src_types>::value_type>::print...}}; | ||
| 191 | } | ||
| 192 | } // namespace | ||
| 193 | |||
| 194 | ✗ | void PdCom::Subscription::print(std::ostream &os, char delimiter) const | |
| 195 | { | ||
| 196 | static constexpr auto printers = getPrintFns(DataTypeSequence {}); | ||
| 197 | static_assert( | ||
| 198 | printers.size() == DataTypeCount, | ||
| 199 | "Print function vector size mismatch"); | ||
| 200 | |||
| 201 | ✗ | if (getVariable().empty()) | |
| 202 | ✗ | throw InvalidSubscription(); | |
| 203 | |||
| 204 | ✗ | printers[getVariable().getTypeInfo().type]( | |
| 205 | ✗ | os, getData(), delimiter, | |
| 206 | ✗ | getVariable().getSizeInfo().totalElements()); | |
| 207 | } | ||
| 208 |