Common System 0.2.0
Common interfaces and patterns for system integration
Loading...
Searching...
No Matches
concepts.cppm
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
22module;
23
24#include <chrono>
25#include <concepts>
26#include <functional>
27#include <future>
28#include <memory>
29#include <string>
30#include <type_traits>
31#include <vector>
32
33export module kcenon.common:concepts;
34
35// Forward declarations for interface types
37class IJob;
38}
39
40export namespace kcenon::common::concepts {
41
42// ============================================================================
43// Core Concepts (Result/Optional)
44// ============================================================================
45
50template<typename T>
51concept Resultable = requires(const T t) {
52 { t.is_ok() } -> std::convertible_to<bool>;
53 { t.is_err() } -> std::convertible_to<bool>;
54};
55
60template<typename T>
61concept Unwrappable = requires(T t) {
62 typename T::value_type;
63 { t.unwrap() } -> std::same_as<typename std::add_lvalue_reference<
64 typename std::add_const<typename T::value_type>::type>::type>;
65 { t.unwrap_or(std::declval<typename T::value_type>()) }
66 -> std::convertible_to<typename T::value_type>;
67};
68
73template<typename T>
74concept Mappable = requires(const T t) {
75 { t.map(std::declval<std::function<int(typename T::value_type)>>()) };
76};
77
82template<typename T>
83concept Chainable = requires(const T t) {
84 { t.and_then(std::declval<std::function<T(typename T::value_type)>>()) };
85};
86
91template<typename T>
92concept MonadicResult = Resultable<T> && Mappable<T> && Chainable<T>;
93
98template<typename T>
99concept OptionalLike = requires(const T t) {
100 { t.has_value() } -> std::convertible_to<bool>;
101 { t.is_some() } -> std::convertible_to<bool>;
102 { t.is_none() } -> std::convertible_to<bool>;
103};
104
109template<typename T>
110concept ErrorInfo = requires(const T t) {
111 { t.code } -> std::convertible_to<int>;
112 { t.message } -> std::convertible_to<std::string>;
113 { t.module } -> std::convertible_to<std::string>;
114};
115
120template<typename T>
121concept ValueOrError = Resultable<T> && requires(const T t) {
122 { t.value() };
123 { t.error() };
124};
125
126// ============================================================================
127// Callable Concepts
128// ============================================================================
129
134template<typename F, typename... Args>
135concept Invocable = std::invocable<F, Args...>;
136
141template<typename F, typename... Args>
142concept VoidCallable = Invocable<F, Args...> &&
143 std::is_void_v<std::invoke_result_t<F, Args...>>;
144
149template<typename F, typename R, typename... Args>
150concept ReturnsResult = Invocable<F, Args...> &&
151 std::convertible_to<std::invoke_result_t<F, Args...>, R>;
152
157template<typename F, typename... Args>
158concept NoexceptCallable = Invocable<F, Args...> &&
159 std::is_nothrow_invocable_v<F, Args...>;
160
165template<typename F, typename... Args>
166concept Predicate = Invocable<F, Args...> &&
167 std::convertible_to<std::invoke_result_t<F, Args...>, bool>;
168
173template<typename F, typename Arg>
174concept UnaryFunction = Invocable<F, Arg>;
175
180template<typename F, typename Arg1, typename Arg2>
181concept BinaryFunction = Invocable<F, Arg1, Arg2>;
182
187template<typename T>
188concept JobLike = requires(T t) {
189 { t.execute() };
190 { t.get_name() } -> std::convertible_to<std::string>;
191 { t.get_priority() } -> std::convertible_to<int>;
192};
193
198template<typename T>
199concept ExecutorLike = requires(T t, std::unique_ptr<interfaces::IJob> job, bool wait) {
200 { t.worker_count() } -> std::convertible_to<size_t>;
201 { t.is_running() } -> std::convertible_to<bool>;
202 { t.pending_tasks() } -> std::convertible_to<size_t>;
203 { t.shutdown(wait) } -> std::same_as<void>;
204};
205
210template<typename F, typename T>
211concept TaskFactory = Invocable<F> &&
212 std::convertible_to<std::invoke_result_t<F>, std::unique_ptr<T>>;
213
218template<typename F, typename R>
219concept AsyncCallable = Invocable<F> &&
220 std::same_as<std::invoke_result_t<F>, R>;
221
226template<typename F>
227concept DelayedCallable = VoidCallable<F> &&
228 std::move_constructible<std::decay_t<F>>;
229
230// ============================================================================
231// Event Concepts
232// ============================================================================
233
238template<typename T>
239concept EventType = std::is_class_v<T> &&
240 std::is_copy_constructible_v<T>;
241
246template<typename H, typename E>
247concept EventHandler = std::invocable<H, const E&> &&
248 std::is_void_v<std::invoke_result_t<H, const E&>>;
249
254template<typename F, typename E>
255concept EventFilter = std::invocable<F, const E&> &&
256 std::convertible_to<std::invoke_result_t<F, const E&>, bool>;
257
262template<typename T>
263concept TimestampedEvent = EventType<T> && requires(const T t) {
264 { t.timestamp } -> std::convertible_to<std::chrono::steady_clock::time_point>;
265};
266
271template<typename T>
272concept NamedEvent = EventType<T> && requires(const T t) {
273 { t.module_name } -> std::convertible_to<std::string>;
274};
275
280template<typename T>
281concept ErrorEvent = EventType<T> && requires(const T t) {
282 { t.error_message } -> std::convertible_to<std::string>;
283 { t.error_code } -> std::convertible_to<int>;
284};
285
290template<typename T>
291concept MetricEvent = EventType<T> && requires(const T t) {
292 { t.name } -> std::convertible_to<std::string>;
293 { t.value } -> std::convertible_to<double>;
294 { t.unit } -> std::convertible_to<std::string>;
295};
296
301template<typename T>
302concept ModuleLifecycleEvent = NamedEvent<T> && TimestampedEvent<T>;
303
308template<typename T>
309concept FullErrorEvent = ErrorEvent<T> && NamedEvent<T> && TimestampedEvent<T>;
310
315template<typename T>
316concept FullMetricEvent = MetricEvent<T> && TimestampedEvent<T>;
317
322template<typename T>
323concept EventBusLike = requires(T t, uint64_t id) {
324 { t.start() } -> std::same_as<void>;
325 { t.stop() } -> std::same_as<void>;
326 { t.is_running() } -> std::convertible_to<bool>;
327 { t.unsubscribe(id) } -> std::same_as<void>;
328};
329
330// ============================================================================
331// Service Concepts (DI)
332// ============================================================================
333
338template<typename T>
339concept ServiceInterface = std::is_class_v<T> && std::has_virtual_destructor_v<T>;
340
345template<typename Impl, typename Interface>
346concept ServiceImplementation = std::derived_from<Impl, Interface> &&
347 std::is_constructible_v<Impl>;
348
353template<typename F, typename T>
354concept ServiceFactory = Invocable<F> &&
355 std::convertible_to<std::invoke_result_t<F>, std::shared_ptr<T>>;
356
361template<typename T>
362concept Validatable = requires(const T t) {
363 { t.validate() } -> std::convertible_to<bool>;
364};
365
366// ============================================================================
367// Container Concepts
368// ============================================================================
369
374template<typename T>
375concept Container = requires(T t) {
376 typename T::value_type;
377 typename T::size_type;
378 { t.size() } -> std::convertible_to<typename T::size_type>;
379 { t.empty() } -> std::convertible_to<bool>;
380 { t.begin() };
381 { t.end() };
382};
383
388template<typename T>
389concept SequenceContainer = Container<T> && requires(T t, typename T::value_type v) {
390 { t.push_back(v) };
391 { t.front() } -> std::same_as<typename T::value_type&>;
392 { t.back() } -> std::same_as<typename T::value_type&>;
393};
394
399template<typename T>
400concept ResizableContainer = Container<T> && requires(T t, typename T::size_type n) {
401 { t.resize(n) };
402 { t.reserve(n) };
403 { t.capacity() } -> std::convertible_to<typename T::size_type>;
404};
405
406// ============================================================================
407// Logger Concepts
408// ============================================================================
409
414template<typename T>
415concept BasicLogger = requires(T t, const std::string& msg) {
416 { t.log(msg) };
417};
418
423template<typename T>
424concept FlushableLogger = BasicLogger<T> && requires(T t) {
425 { t.flush() };
426};
427
428// ============================================================================
429// Monitoring Concepts
430// ============================================================================
431
436template<typename T>
437concept CounterMetric = requires(T t, const std::string& name, int64_t val) {
438 { t.increment(name) };
439 { t.increment(name, val) };
440};
441
446template<typename T>
447concept GaugeMetric = requires(T t, const std::string& name, double val) {
448 { t.set_gauge(name, val) };
449};
450
455template<typename T>
456concept HistogramMetric = requires(T t, const std::string& name, double val) {
457 { t.observe(name, val) };
458};
459
460// ============================================================================
461// Transport Concepts
462// ============================================================================
463
468template<typename T>
469concept Sendable = requires(T t, const std::string& data) {
470 { t.send(data) };
471};
472
477template<typename T>
478concept Receivable = requires(T t) {
479 { t.receive() } -> std::convertible_to<std::string>;
480};
481
486template<typename T>
488
489} // namespace kcenon::common::concepts
A type that can receive data.
A type that can send data.
A type that represents any transport client (HTTP or UDP).
Definition transport.h:261
C++20 concepts for compile-time type validation.
Definition callable.h:44