Skip to content

Commit 241480d

Browse files
committed
hmon: add C++ interface to logic monitor
Add C++ interface to logic monitor.
1 parent 63df054 commit 241480d

12 files changed

Lines changed: 1270 additions & 8 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"rust-analyzer.cargo.features": [
1313
"stub_supervisor_api_client"
1414
],
15+
"rust-analyzer.cargo.noDefaultFeatures": true,
1516
"rust-analyzer.check.command": "clippy",
1617
"rust-analyzer.rustfmt.overrideCommand": [
1718
"${workspaceFolder}/.vscode/rustfmt.sh"

src/health_monitoring_lib/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ CC_SOURCES = [
2929
"cpp/common.cpp",
3030
"cpp/deadline_monitor.cpp",
3131
"cpp/heartbeat_monitor.cpp",
32+
"cpp/logic_monitor.cpp",
3233
"cpp/health_monitor.cpp",
3334
]
3435

@@ -37,6 +38,7 @@ CC_HDRS = [
3738
"cpp/include/score/hm/tag.h",
3839
"cpp/include/score/hm/deadline/deadline_monitor.h",
3940
"cpp/include/score/hm/heartbeat/heartbeat_monitor.h",
41+
"cpp/include/score/hm/logic/logic_monitor.h",
4042
"cpp/include/score/hm/health_monitor.h",
4143
]
4244

src/health_monitoring_lib/cpp/health_monitor.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ using namespace score::hm;
1919
using namespace score::hm::internal;
2020
using namespace score::hm::deadline;
2121
using namespace score::hm::heartbeat;
22+
using namespace score::hm::logic;
2223

2324
// Functions below must match functions defined in `crate::ffi`.
2425

@@ -34,12 +35,18 @@ FFICode health_monitor_builder_add_deadline_monitor(FFIHandle health_monitor_bui
3435
FFICode health_monitor_builder_add_heartbeat_monitor(FFIHandle health_monitor_builder_handle,
3536
const MonitorTag* monitor_tag,
3637
FFIHandle heartbeat_monitor_builder_handle);
38+
FFICode health_monitor_builder_add_logic_monitor(FFIHandle health_monitor_builder_handle,
39+
const MonitorTag* monitor_tag,
40+
FFIHandle logic_monitor_builder_handle);
3741
FFICode health_monitor_get_deadline_monitor(FFIHandle health_monitor_handle,
3842
const MonitorTag* monitor_tag,
3943
FFIHandle* deadline_monitor_handle_out);
4044
FFICode health_monitor_get_heartbeat_monitor(FFIHandle health_monitor_handle,
4145
const MonitorTag* monitor_tag,
4246
FFIHandle* heartbeat_monitor_handle_out);
47+
FFICode health_monitor_get_logic_monitor(FFIHandle health_monitor_handle,
48+
const MonitorTag* monitor_tag,
49+
FFIHandle* logic_monitor_handle_out);
4350
FFICode health_monitor_start(FFIHandle health_monitor_handle);
4451
FFICode health_monitor_destroy(FFIHandle health_monitor_handle);
4552
}
@@ -92,6 +99,20 @@ HealthMonitorBuilder HealthMonitorBuilder::add_heartbeat_monitor(const MonitorTa
9299
return std::move(*this);
93100
}
94101

102+
HealthMonitorBuilder HealthMonitorBuilder::add_logic_monitor(const MonitorTag& monitor_tag,
103+
LogicMonitorBuilder&& monitor) &&
104+
{
105+
auto monitor_handle = monitor.drop_by_rust();
106+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value());
107+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(health_monitor_builder_handle_.as_rust_handle().has_value());
108+
109+
auto result{health_monitor_builder_add_logic_monitor(
110+
health_monitor_builder_handle_.as_rust_handle().value(), &monitor_tag, monitor_handle.value())};
111+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
112+
113+
return std::move(*this);
114+
}
115+
95116
HealthMonitorBuilder HealthMonitorBuilder::with_internal_processing_cycle(std::chrono::milliseconds cycle_duration) &&
96117
{
97118
internal_processing_cycle_duration_ = cycle_duration;
@@ -155,6 +176,18 @@ score::cpp::expected<HeartbeatMonitor, Error> HealthMonitor::get_heartbeat_monit
155176
return score::cpp::expected<HeartbeatMonitor, Error>(HeartbeatMonitor{handle});
156177
}
157178

179+
score::cpp::expected<LogicMonitor, Error> HealthMonitor::get_logic_monitor(const MonitorTag& monitor_tag)
180+
{
181+
FFIHandle handle{nullptr};
182+
auto result{health_monitor_get_logic_monitor(health_monitor_, &monitor_tag, &handle)};
183+
if (result != kSuccess)
184+
{
185+
return score::cpp::unexpected(static_cast<Error>(result));
186+
}
187+
188+
return score::cpp::expected<LogicMonitor, Error>(LogicMonitor{handle});
189+
}
190+
158191
void HealthMonitor::start()
159192
{
160193
auto result{health_monitor_start(health_monitor_)};

src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <score/hm/common.h>
1717
#include <score/hm/deadline/deadline_monitor.h>
1818
#include <score/hm/heartbeat/heartbeat_monitor.h>
19+
#include <score/hm/logic/logic_monitor.h>
1920
#include <score/hm/tag.h>
2021

2122
namespace score::hm
@@ -47,6 +48,9 @@ class HealthMonitorBuilder final
4748
HealthMonitorBuilder add_heartbeat_monitor(const MonitorTag& monitor_tag,
4849
heartbeat::HeartbeatMonitorBuilder&& monitor) &&;
4950

51+
/// Adds a logic monitor for a specific identifier tag.
52+
HealthMonitorBuilder add_logic_monitor(const MonitorTag& monitor_tag, logic::LogicMonitorBuilder&& monitor) &&;
53+
5054
/// Sets the cycle duration for supervisor API notifications.
5155
/// This duration determines how often the health monitor notifies the supervisor that the system is alive.
5256
HealthMonitorBuilder with_supervisor_api_cycle(std::chrono::milliseconds cycle_duration) &&;
@@ -78,6 +82,7 @@ class HealthMonitor final
7882

7983
score::cpp::expected<deadline::DeadlineMonitor, Error> get_deadline_monitor(const MonitorTag& monitor_tag);
8084
score::cpp::expected<heartbeat::HeartbeatMonitor, Error> get_heartbeat_monitor(const MonitorTag& monitor_tag);
85+
score::cpp::expected<logic::LogicMonitor, Error> get_logic_monitor(const MonitorTag& monitor_tag);
8186

8287
void start();
8388

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/********************************************************************************
2+
* Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Apache License Version 2.0 which is available at
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* SPDX-License-Identifier: Apache-2.0
12+
********************************************************************************/
13+
#ifndef SCORE_HM_LOGIC_LOGIC_MONITOR_H
14+
#define SCORE_HM_LOGIC_LOGIC_MONITOR_H
15+
16+
#include "score/hm/common.h"
17+
#include "score/hm/tag.h"
18+
#include <score/expected.hpp>
19+
#include <vector>
20+
21+
namespace score::hm
22+
{
23+
// Forward declaration
24+
class HealthMonitor;
25+
class HealthMonitorBuilder;
26+
} // namespace score::hm
27+
28+
namespace score::hm::logic
29+
{
30+
31+
class LogicMonitorBuilder final : public internal::RustDroppable<LogicMonitorBuilder>
32+
{
33+
public:
34+
/// Create a new `LogicMonitorBuilder`.
35+
///
36+
/// - `initial_state` - starting point.
37+
LogicMonitorBuilder(const StateTag& initial_state);
38+
39+
LogicMonitorBuilder(const LogicMonitorBuilder&) = delete;
40+
LogicMonitorBuilder& operator=(const LogicMonitorBuilder&) = delete;
41+
42+
LogicMonitorBuilder(LogicMonitorBuilder&&) = default;
43+
LogicMonitorBuilder& operator=(LogicMonitorBuilder&&) = delete;
44+
45+
/// Add state along with allowed transitions.
46+
/// If state already exists - it is overwritten.
47+
LogicMonitorBuilder add_state(const StateTag& state, const std::vector<StateTag>& allowed_states) &&;
48+
49+
protected:
50+
std::optional<internal::FFIHandle> _drop_by_rust_impl()
51+
{
52+
return monitor_builder_handle_.drop_by_rust();
53+
}
54+
55+
private:
56+
internal::DroppableFFIHandle monitor_builder_handle_;
57+
58+
// Allow to hide drop_by_rust implementation
59+
friend class internal::RustDroppable<LogicMonitorBuilder>;
60+
61+
// Allow HealthMonitorBuilder to access drop_by_rust implementation
62+
friend class ::score::hm::HealthMonitorBuilder;
63+
};
64+
65+
class LogicMonitor final
66+
{
67+
public:
68+
LogicMonitor(const LogicMonitor&) = delete;
69+
LogicMonitor& operator=(const LogicMonitor&) = delete;
70+
71+
LogicMonitor(LogicMonitor&& other) noexcept = default;
72+
LogicMonitor& operator=(LogicMonitor&& other) noexcept = default;
73+
74+
/// Perform transition to a new state.
75+
/// On success, current state is returned.
76+
score::cpp::expected<StateTag, Error> transition(const StateTag& state);
77+
78+
/// Current monitor state.
79+
score::cpp::expected<StateTag, Error> state();
80+
81+
private:
82+
explicit LogicMonitor(internal::FFIHandle monitor_handle);
83+
84+
// Only `HealthMonitor` is allowed to create `LogicMonitor` instances.
85+
friend class score::hm::HealthMonitor;
86+
internal::DroppableFFIHandle monitor_handle_;
87+
};
88+
89+
} // namespace score::hm::logic
90+
91+
#endif // SCORE_HM_LOGIC_LOGIC_MONITOR_H

src/health_monitoring_lib/cpp/include/score/hm/tag.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
#define SCORE_HM_TAG_H
1616

1717
#include <cstddef>
18+
#include <string_view>
1819

1920
namespace score::hm
2021
{
2122

2223
/// Common string-based tag.
24+
template <typename T>
2325
class Tag
2426
{
2527
public:
@@ -29,21 +31,40 @@ class Tag
2931
{
3032
}
3133

34+
bool operator==(const T& other) const noexcept
35+
{
36+
std::string_view this_sv{data_, length_};
37+
std::string_view other_sv{other.data_, other.length_};
38+
return this_sv.compare(other_sv) == 0;
39+
}
40+
41+
bool operator!=(const T& other) const noexcept
42+
{
43+
return !(*this == other);
44+
}
45+
3246
private:
3347
/// SAFETY: This has to be FFI compatible with the Rust side representation.
34-
const char* const data_;
48+
const char* data_;
3549
size_t length_;
3650
};
3751

3852
/// Monitor tag.
39-
class MonitorTag : public Tag
53+
class MonitorTag : public Tag<MonitorTag>
4054
{
4155
public:
4256
using Tag::Tag;
4357
};
4458

4559
/// Deadline tag.
46-
class DeadlineTag : public Tag
60+
class DeadlineTag : public Tag<DeadlineTag>
61+
{
62+
public:
63+
using Tag::Tag;
64+
};
65+
66+
/// State tag.
67+
class StateTag : public Tag<StateTag>
4768
{
4869
public:
4970
using Tag::Tag;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/********************************************************************************
2+
* Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Apache License Version 2.0 which is available at
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* SPDX-License-Identifier: Apache-2.0
12+
********************************************************************************/
13+
#include "score/hm/logic/logic_monitor.h"
14+
#include <score/assert.hpp>
15+
16+
namespace
17+
{
18+
extern "C" {
19+
using namespace score::hm;
20+
using namespace score::hm::internal;
21+
using namespace score::hm::logic;
22+
23+
FFICode logic_monitor_builder_create(const StateTag* initial_state, FFIHandle* logic_monitor_builder_handle_out);
24+
FFICode logic_monitor_builder_destroy(FFIHandle logic_monitor_builder_handle);
25+
FFICode logic_monitor_builder_add_state(FFIHandle logic_monitor_builder_handle,
26+
const StateTag* state,
27+
const StateTag* allowed_states,
28+
size_t num_allowed_states);
29+
FFICode logic_monitor_destroy(FFIHandle logic_monitor_handle);
30+
FFICode logic_monitor_transition(FFIHandle logic_monitor_handle, const StateTag* target_state);
31+
FFICode logic_monitor_state(FFIHandle logic_monitor_handle, StateTag* state_out);
32+
}
33+
34+
FFIHandle logic_monitor_builder_create_wrapper(const StateTag& initial_state)
35+
{
36+
FFIHandle handle{nullptr};
37+
auto result{logic_monitor_builder_create(&initial_state, &handle)};
38+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
39+
return handle;
40+
}
41+
} // namespace
42+
43+
namespace score::hm::logic
44+
{
45+
LogicMonitorBuilder::LogicMonitorBuilder(const StateTag& initial_state)
46+
: monitor_builder_handle_{logic_monitor_builder_create_wrapper(initial_state), &logic_monitor_builder_destroy}
47+
{
48+
}
49+
50+
LogicMonitorBuilder LogicMonitorBuilder::add_state(const StateTag& state,
51+
const std::vector<StateTag>& allowed_states) &&
52+
{
53+
auto monitor_builder_handle{monitor_builder_handle_.as_rust_handle()};
54+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_builder_handle.has_value());
55+
56+
auto result{logic_monitor_builder_add_state(
57+
monitor_builder_handle.value(), &state, allowed_states.data(), allowed_states.size())};
58+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
59+
60+
return std::move(*this);
61+
}
62+
63+
LogicMonitor::LogicMonitor(FFIHandle monitor_handle) : monitor_handle_{monitor_handle, &logic_monitor_destroy} {}
64+
65+
score::cpp::expected<StateTag, Error> LogicMonitor::transition(const StateTag& state)
66+
{
67+
auto monitor_handle{monitor_handle_.as_rust_handle()};
68+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value());
69+
70+
auto result{logic_monitor_transition(monitor_handle.value(), &state)};
71+
if (result != kSuccess)
72+
{
73+
return score::cpp::unexpected(static_cast<Error>(result));
74+
}
75+
76+
return score::cpp::expected<StateTag, Error>(state);
77+
}
78+
79+
score::cpp::expected<StateTag, Error> LogicMonitor::state()
80+
{
81+
auto monitor_handle{monitor_handle_.as_rust_handle()};
82+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value());
83+
84+
StateTag state_tag{""};
85+
auto result{logic_monitor_state(monitor_handle.value(), &state_tag)};
86+
if (result != kSuccess)
87+
{
88+
return score::cpp::unexpected(static_cast<Error>(result));
89+
}
90+
91+
return score::cpp::expected<StateTag, Error>(state_tag);
92+
}
93+
94+
} // namespace score::hm::logic

0 commit comments

Comments
 (0)