Skip to content

Commit b824c45

Browse files
author
Pavel Siska
committed
fieldSchema
1 parent 6818963 commit b824c45

File tree

1 file changed

+294
-0
lines changed

1 file changed

+294
-0
lines changed

new-process-api/fieldSchema.hpp

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
/**
2+
* @file
3+
* @author Pavel Siska <[email protected]>
4+
* @brief Provides the FieldSchema class for registering scalar, vector, directional, and biflow
5+
* fields.
6+
*
7+
* FieldSchema is responsible for managing field metadata within a specific group.
8+
* It allows adding scalar and vector fields, as well as pairs of fields that
9+
* represent either directional or biflow traffic. The class interfaces with
10+
* FieldManager to register fields and maintain consistency in FlowRecords.
11+
*
12+
* The template methods enable flexible accessor functions for fields, supporting:
13+
* - Scalar values
14+
* - Vector values (std::span)
15+
* - Directional field pairs (forward/reverse)
16+
* - Biflow field pairs (A/B)
17+
*
18+
* @note FieldSchema instances are constructed by FieldManager and are tied to
19+
* a specific field group.
20+
*
21+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
22+
*/
23+
24+
#pragma once
25+
26+
#include "fieldHandler.hpp"
27+
#include "fieldManager.hpp"
28+
#include "fieldSchemaTypeTraits.hpp"
29+
30+
#include <cstdint>
31+
#include <string_view>
32+
#include <type_traits>
33+
#include <utility>
34+
35+
namespace ipxp {
36+
37+
/**
38+
* @class FieldSchema
39+
* @brief Manages registration of scalar, vector, directional, and biflow fields.
40+
*
41+
* This class acts as a bridge between user-provided accessor functions and the FieldManager,
42+
* ensuring type consistency and correct registration.
43+
*
44+
* ## Example: Adding a scalar field
45+
* @code
46+
* FieldSchema schema = fieldManager.createFieldSchema("my_group");
47+
*
48+
* schema.addScalarField("packet_count", [](const void* rec) {
49+
* return static_cast<const MyRecord*>(rec)->pktCount;
50+
* });
51+
* @endcode
52+
*
53+
* ## Example: Adding a vector field
54+
* @code
55+
* schema.addVectorField("payload", [](const void* rec) {
56+
* auto r = static_cast<const MyRecord*>(rec);
57+
* return std::span<const uint8_t>(r->payload, r->payloadLength);
58+
* });
59+
* @endcode
60+
*
61+
* ## Example: Adding a directional pair of scalar fields
62+
* @code
63+
* schema.addScalarDirectionalFields(
64+
* "fwd_packets", "rev_packets",
65+
* [](const void* rec) { return static_cast<const MyRecord*>(rec)->fwdCount; },
66+
* [](const void* rec) { return static_cast<const MyRecord*>(rec)->revCount; }
67+
* );
68+
* @endcode
69+
*/
70+
class FieldSchema {
71+
public:
72+
/**
73+
* @brief Registers a scalar field.
74+
*
75+
* @tparam AccessorFunction Callable returning the field value.
76+
* @param fieldName Name of the field.
77+
* @param accessorFunction Function that retrieves the field value.
78+
* @return FieldHandler Handle to the registered field.
79+
*/
80+
template<typename AccessorFunction>
81+
[[nodiscard]] FieldHandler
82+
addScalarField(std::string_view fieldName, AccessorFunction&& accessorFunction)
83+
{
84+
return addFieldGeneric<ScalarAccessor>(
85+
fieldName,
86+
std::forward<AccessorFunction>(accessorFunction));
87+
}
88+
89+
/**
90+
* @brief Registers a vector field.
91+
*
92+
* @tparam AccessorFunction Callable returning a `std::span` of values.
93+
* @param fieldName Name of the field.
94+
* @param accessorFunction Function that retrieves the field values.
95+
* @return FieldHandler Handle to the registered field.
96+
*/
97+
template<typename AccessorFunction>
98+
[[nodiscard]] FieldHandler
99+
addVectorField(std::string_view fieldName, AccessorFunction&& accessorFunction)
100+
{
101+
return addFieldGeneric<VectorAccessor>(
102+
fieldName,
103+
std::forward<AccessorFunction>(accessorFunction));
104+
}
105+
106+
/**
107+
* @brief Registers a pair of scalar fields representing directional traffic.
108+
*
109+
* @tparam ForwardAccessorFunction Accessor for the forward direction.
110+
* @tparam ReverseAccessorFunction Accessor for the reverse direction.
111+
* @param forwardFieldName Name of the forward field.
112+
* @param reverseFieldName Name of the reverse field.
113+
* @param forwardAccessorFunction Getter for the forward value.
114+
* @param reverseAccessorFunction Getter for the reverse value.
115+
* @return Pair of FieldHandler objects for forward and reverse fields.
116+
*/
117+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
118+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addScalarDirectionalFields(
119+
std::string_view forwardFieldName,
120+
std::string_view reverseFieldName,
121+
ForwardAccessorFunction&& forwardAccessorFunction,
122+
ReverseAccessorFunction&& reverseAccessorFunction)
123+
{
124+
return addPairFieldsGeneric<ScalarAccessor>(
125+
forwardFieldName,
126+
reverseFieldName,
127+
std::forward<ForwardAccessorFunction>(forwardAccessorFunction),
128+
std::forward<ReverseAccessorFunction>(reverseAccessorFunction),
129+
PairType::Directional);
130+
}
131+
132+
/**
133+
* @brief Registers a pair of vector fields representing directional traffic.
134+
*
135+
* @tparam ForwardAccessorFunction Accessor for the forward direction.
136+
* @tparam ReverseAccessorFunction Accessor for the reverse direction.
137+
* @param forwardFieldName Name of the forward field.
138+
* @param reverseFieldName Name of the reverse field.
139+
* @param forwardAccessorFunction Getter for the forward value.
140+
* @param reverseAccessorFunction Getter for the reverse value.
141+
* @return Pair of FieldHandler objects for forward and reverse fields.
142+
*/
143+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
144+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addVectorDirectionalFields(
145+
std::string_view forwardFieldName,
146+
std::string_view reverseFieldName,
147+
ForwardAccessorFunction&& forwardAccessorFunction,
148+
ReverseAccessorFunction&& reverseAccessorFunction)
149+
{
150+
return addPairFieldsGeneric<VectorAccessor>(
151+
forwardFieldName,
152+
reverseFieldName,
153+
std::forward<ForwardAccessorFunction>(forwardAccessorFunction),
154+
std::forward<ReverseAccessorFunction>(reverseAccessorFunction),
155+
PairType::Directional);
156+
}
157+
158+
/**
159+
* @brief Registers a pair of scalar fields representing biflow traffic.
160+
*
161+
* @param aFieldName Name of the "A" field.
162+
* @param bFieldName Name of the "B" field.
163+
* @param aGetter Getter for the "A" value.
164+
* @param bGetter Getter for the "B" value.
165+
*/
166+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
167+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addScalarBiflowFields(
168+
std::string_view aFieldName,
169+
std::string_view bFieldName,
170+
ForwardAccessorFunction&& aGetter,
171+
ReverseAccessorFunction&& bGetter)
172+
{
173+
return addPairFieldsGeneric<ScalarAccessor>(
174+
aFieldName,
175+
bFieldName,
176+
std::forward<ForwardAccessorFunction>(aGetter),
177+
std::forward<ReverseAccessorFunction>(bGetter),
178+
PairType::Biflow);
179+
}
180+
181+
/**
182+
* @brief Registers a pair of vector fields representing biflow traffic.
183+
*
184+
* @param aFieldName Name of the "A" field.
185+
* @param bFieldName Name of the "B" field.
186+
* @param aGetter Getter for the "A" value.
187+
* @param bGetter Getter for the "B" value.
188+
*/
189+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
190+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addVectorBiflowFields(
191+
std::string_view aFieldName,
192+
std::string_view bFieldName,
193+
ForwardAccessorFunction&& aGetter,
194+
ReverseAccessorFunction&& bGetter)
195+
{
196+
return addPairFieldsGeneric<VectorAccessor>(
197+
aFieldName,
198+
bFieldName,
199+
std::forward<ForwardAccessorFunction>(aGetter),
200+
std::forward<ReverseAccessorFunction>(bGetter),
201+
PairType::Biflow);
202+
}
203+
204+
private:
205+
template<typename AccessorFunction>
206+
using FieldType = std::invoke_result_t<AccessorFunction, const void*>;
207+
208+
template<typename AccessorFunction>
209+
using ElementType = typename span_element_type<FieldType<AccessorFunction>>::type;
210+
211+
enum class PairType : uint8_t {
212+
Directional,
213+
Biflow,
214+
};
215+
216+
// Can be constructed only by FieldManager
217+
friend class FieldManager;
218+
219+
FieldSchema(std::string_view groupName, FieldManager& manager)
220+
: m_groupName(std::string(groupName))
221+
, m_fieldManager(manager)
222+
{
223+
}
224+
225+
template<template<typename> class Accessor, typename AccessorFunction>
226+
[[nodiscard]] FieldHandler
227+
addFieldGeneric(std::string_view fieldName, AccessorFunction&& accessorFunction)
228+
{
229+
using T = FieldType<AccessorFunction>;
230+
return m_fieldManager.registerField(
231+
m_groupName,
232+
fieldName,
233+
Accessor<T> {std::forward<AccessorFunction>(accessorFunction)});
234+
}
235+
236+
// T
237+
template<
238+
template<typename> class Accessor,
239+
typename ForwardAccessorFunction,
240+
typename ReverseAccessorFunction>
241+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addPairFieldsGeneric(
242+
std::string_view fieldNameA,
243+
std::string_view fieldNameB,
244+
ForwardAccessorFunction&& forwardAccessorFunction,
245+
ReverseAccessorFunction&& reverseAccessorFunctionB,
246+
PairType pairType)
247+
{
248+
using TaRaw = FieldType<ForwardAccessorFunction>;
249+
using TbRaw = FieldType<ReverseAccessorFunction>;
250+
251+
static_assert(
252+
std::is_same_v<TaRaw, TbRaw>,
253+
"Accessor functions for pair fields must return the same type");
254+
255+
using Ta = std::conditional_t<
256+
is_scalar_accessor<Accessor, FieldType<ForwardAccessorFunction>>::value,
257+
TaRaw,
258+
ElementType<ForwardAccessorFunction>>;
259+
260+
using Tb = std::conditional_t<
261+
is_scalar_accessor<Accessor, FieldType<ReverseAccessorFunction>>::value,
262+
TbRaw,
263+
ElementType<ReverseAccessorFunction>>;
264+
265+
const Accessor<Ta> accessorA {
266+
std::forward<ForwardAccessorFunction>(forwardAccessorFunction)};
267+
const Accessor<Tb> accessorB {
268+
std::forward<ReverseAccessorFunction>(reverseAccessorFunctionB)};
269+
270+
switch (pairType) {
271+
case PairType::Biflow:
272+
return m_fieldManager.registerBiflowPairFields(
273+
m_groupName,
274+
fieldNameA,
275+
fieldNameB,
276+
std::move(accessorA),
277+
std::move(accessorB));
278+
case PairType::Directional:
279+
return m_fieldManager.registerDirectionalPairFields(
280+
m_groupName,
281+
fieldNameA,
282+
fieldNameB,
283+
std::move(accessorA),
284+
std::move(accessorB));
285+
}
286+
287+
__builtin_unreachable();
288+
}
289+
290+
std::string m_groupName;
291+
FieldManager& m_fieldManager;
292+
};
293+
294+
} // namespace ipxp

0 commit comments

Comments
 (0)