GCC Code Coverage Report


Directory: ./
File: ecapp/Exceptions.h
Date: 2026-09-23 16:22:15
Exec Total Coverage
Lines: 12 14 85.7%
Branches: 0 0 -%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * This file is part of the ecapp library (EtherCAT application devices).
4 *
5 * Copyright (C) 2026 Florian Pose <fp@igh.de>
6 *
7 * The ecapp library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation, version 3 of the
10 * License.
11 *
12 * The ecapp library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with the ecapp library. If not, see
19 * <https://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23 #ifndef ECAPP_EXCEPTIONS_H
24 #define ECAPP_EXCEPTIONS_H
25
26 /****************************************************************************/
27
28 #include "ecapp_export.h"
29
30 #include <stdexcept>
31 #include <string>
32 #include <variant>
33
34 /****************************************************************************/
35
36 namespace EcApp {
37
38 /** Base class for all exceptions thrown by ecapp. */
39 19 class ECAPP_EXPORT Error : public std::runtime_error
40 {
41 public:
42 19 explicit Error(const std::string &what) : std::runtime_error(what) {}
43
44 // Declared here but defined out-of-line in Exceptions.cpp -- its
45 // *only* purpose is to give this class a key function, so its
46 // vtable is bound to that one translation unit with ordinary
47 // external linkage. Without one (every member otherwise inline),
48 // the vtable has vague (COMDAT-like) linkage instead; some
49 // compilers' LTO then judge it unreachable from outside this
50 // library and drop it from the shared object entirely, breaking
51 // catch-by-reference/dynamic_cast for callers linked against it.
52 ~Error() override;
53 };
54
55 /** Thrown by createSubDevice() when no registered device matches the
56 * requested name, or vendor/product/revision combination. */
57 8 class ECAPP_EXPORT UnknownDevice : public Error
58 {
59 public:
60 8 explicit UnknownDevice(const std::string &what) : Error(what) {}
61 ~UnknownDevice() override; // key function -- see Error::~Error()
62 };
63
64 /** Thrown by SubDevice::inputIndex()/outputIndex() when no channel with
65 * the requested name exists on this device. */
66 10 class ECAPP_EXPORT UnknownChannel : public Error
67 {
68 public:
69 10 explicit UnknownChannel(const std::string &what) : Error(what) {}
70 ~UnknownChannel() override; // key function -- see Error::~Error()
71 };
72
73 /** Thrown by capability() when a device does not implement the requested
74 * capability interface (e.g. setInputType() on a device without
75 * switchable analog ranges). Wrong-type channel access instead throws
76 * std::bad_variant_access from ChannelValue itself. */
77 1 class ECAPP_EXPORT UnsupportedCapability : public Error
78 {
79 public:
80 1 explicit UnsupportedCapability(const std::string &what) : Error(what) {}
81 ~UnsupportedCapability() override; // key function -- see Error::~Error()
82 };
83
84 /** Thrown by SubDevice::setAlias() when the aliases vector's size does
85 * not equal the target kind's channel count. */
86 ✗ class ECAPP_EXPORT AliasCountMismatch : public Error
87 {
88 public:
89 ✗ explicit AliasCountMismatch(const std::string &what) : Error(what) {}
90 ~AliasCountMismatch() override; // key function -- see Error::~Error()
91 };
92
93 /** Thrown in place of a bare std::bad_variant_access by
94 * SubDevice::readInput<T>()/setOutput() and bindInput<T>()/ bindOutput<T>()'s
95 * upfront type check when a channel does not hold the type T requested of it
96 * -- what() names the channel (kind and index) that was mis-accessed.
97 *
98 * Inherits std::bad_variant_access directly (not Error) so it stays catchable
99 * wherever the plain std::get<T>() exception was caught before. Not thrown
100 * for BoundInput/BoundOutput (see SubDevice.h): those resolve and check the
101 * type once, at bindInput<T>()/bindOutput<T>() time, and are documented to
102 * never throw afterwards. */
103 4 class ECAPP_EXPORT ChannelTypeMismatch : public std::bad_variant_access
104 {
105 public:
106 4 explicit ChannelTypeMismatch(std::string what) : message_(std::move(what))
107 4 {}
108
109 2 const char *what() const noexcept override { return message_.c_str(); }
110
111 private:
112 std::string message_;
113 };
114
115 } // namespace EcApp
116
117 #endif // ECAPP_EXCEPTIONS_H
118
119 /****************************************************************************/
120