Skip to content

Commit 462013f

Browse files
fixup
1 parent d41446a commit 462013f

File tree

7 files changed

+518
-83
lines changed

7 files changed

+518
-83
lines changed

tesseract_common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ add_library(
9696
src/profile.cpp
9797
src/property_tree.cpp
9898
src/resource_locator.cpp
99+
src/schema_registration.cpp
99100
src/schema_registry.cpp
100101
src/stopwatch.cpp
101102
src/types.cpp

tesseract_common/include/tesseract_common/fwd.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ class Timer;
8080
// Profile Dictionary
8181
class Profile;
8282
class ProfileDictionary;
83+
84+
// property_tree.h
85+
class PropertyTree;
86+
87+
// schema_registry.h
88+
class SchemaRegistry;
8389
} // namespace tesseract_common
8490

8591
#endif // TESSERACT_COMMON_TESSERACT_COMMON_FWD_H

tesseract_common/include/tesseract_common/property_tree.h

Lines changed: 114 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ namespace tesseract_common
1313
{
1414
namespace property_type
1515
{
16+
/**
17+
* @brief A utility for constructing the list type
18+
* @param type The type assoicated with the list
19+
* @return The string representation of the std::vector<type>, aka. type[]
20+
*/
21+
std::string createList(std::string_view type);
22+
23+
/**
24+
* @brief A utility for constructing the map type
25+
* @param key_type The type assoicated with the map key
26+
* @param value_type The type assoicated with the map value
27+
* @return The string representation of the std::make<key_type, value_type>, aka. {key_type : value_type}
28+
*/
29+
std::string createMap(std::string_view key_type, std::string_view value_type);
30+
1631
// Integral Types
1732
constexpr std::string_view BOOL{ "bool" };
1833
constexpr std::string_view CHAR{ "char" };
@@ -26,11 +41,11 @@ constexpr std::string_view DOUBLE{ "double" };
2641

2742
// Eigen Types
2843
constexpr std::string_view EIGEN_ISOMETRY_3D{ "Eigen::Isometry3d" };
29-
constexpr std::string_view EIGEN_MATRIX_XD{ "Eigen::MatrixXd" };
44+
// constexpr std::string_view EIGEN_MATRIX_XD{ "Eigen::MatrixXd" };
3045
constexpr std::string_view EIGEN_VECTOR_XD{ "Eigen::VectorXd" };
31-
constexpr std::string_view EIGEN_MATRIX_2D{ "Eigen::Matrix2d" };
46+
// constexpr std::string_view EIGEN_MATRIX_2D{ "Eigen::Matrix2d" };
3247
constexpr std::string_view EIGEN_VECTOR_2D{ "Eigen::Vector2d" };
33-
constexpr std::string_view EIGEN_MATRIX_3D{ "Eigen::Matrix3d" };
48+
// constexpr std::string_view EIGEN_MATRIX_3D{ "Eigen::Matrix3d" };
3449
constexpr std::string_view EIGEN_VECTOR_3D{ "Eigen::Vector3d" };
3550
} // namespace property_type
3651

@@ -77,21 +92,22 @@ class PropertyTree
7792
PropertyTree() = default;
7893

7994
/**
80-
* @brief Merge schema metadata into this node.
81-
*
82-
* Copies attributes from the schema, applies defaults for non-required
83-
* properties, registers schema validators, and recursively merges children.
84-
* @param schema PropertyTree containing schema definitions.
95+
* @brief Given that *this* is purely a schema tree, merge in the
96+
* user’s YAML config to populate all values (and apply defaults).
97+
* @param config The user-supplied YAML::Node (possibly null).
98+
* @param allow_extra_properties If false, “extra” keys in config will be flagged.
8599
*/
86-
void mergeSchema(const PropertyTree& schema);
100+
void mergeConfig(const YAML::Node& config, bool allow_extra_properties = false);
87101

88102
/**
89103
* @brief Validate the tree using registered validators.
90104
*
91105
* Recursively invokes all validators on this node and its children.
92106
* Throws on the first error encountered.
107+
*
108+
* @param allow_extra_properties Indicate if extra properties are allowed
93109
*/
94-
void validate() const;
110+
void validate(bool allow_extra_properties = false) const;
95111

96112
/**
97113
* @brief Register a custom validator for this node.
@@ -139,6 +155,12 @@ class PropertyTree
139155
*/
140156
bool isNull() const;
141157

158+
/**
159+
* @brief Check if property is a container of child properties
160+
* @return True if container, otherwise false
161+
*/
162+
bool isContainer() const;
163+
142164
/**
143165
* @brief List all immediate child keys.
144166
* @return Vector of child key strings.
@@ -204,11 +226,19 @@ class PropertyTree
204226

205227
private:
206228
YAML::Node value_; /**< Value stored at this node */
229+
YAML::Node follow_; /**< Follow stored at this node */
207230
std::map<std::string, YAML::Node> attributes_; /**< Metadata attributes */
208231
std::map<std::string, PropertyTree> children_; /**< Nested child nodes */
209232
std::vector<ValidatorFn> validators_; /**< Validators to invoke */
210233
};
211234

235+
/**
236+
* @brief Check if type is a sequence
237+
* @param type The type to check
238+
* @return If it is a sequence the underlying type is returned
239+
*/
240+
std::optional<std::string> isSequenceType(std::string_view type);
241+
212242
/**
213243
* @brief Validator: ensure 'required' attribute is present and non-null.
214244
* @param node Node to validate.
@@ -217,18 +247,86 @@ class PropertyTree
217247
void validateRequired(const PropertyTree& node);
218248

219249
/**
220-
* @brief Validator: enforce 'minimum'/'maximum' range constraints.
250+
* @brief Validator: enforce that node's value is in 'enum' list.
221251
* @param node Node to validate.
222-
* @throws runtime_error if out of range.
252+
* @throws runtime_error if not found.
253+
*/
254+
void validateEnum(const PropertyTree& node);
255+
256+
/**
257+
* @brief Validtor: ensure node value is of type YAML::NodeType::Map
258+
* @param node Node to validate.
259+
* @throws runtime_error if not correct type.
223260
*/
224-
void validateRange(const PropertyTree& node);
261+
void validateMap(const PropertyTree& node);
225262

226263
/**
227-
* @brief Validator: enforce that node's value is in 'enum' list.
264+
* @brief Validtor: ensure node value is of type YAML::NodeType::Sequence
265+
* @param node Node to validate.
266+
* @throws runtime_error if not correct type.
267+
*/
268+
void validateSequence(const PropertyTree& node);
269+
270+
void validateCustomType(const PropertyTree& node);
271+
272+
/**
273+
* @brief Validate that the node’s value can be interpreted as the provided type.
274+
* @param node PropertyTree node whose value to validate.
275+
* @throws std::runtime_error or YAML::BadConversion if the value is not a valid type.
276+
*/
277+
template <typename T>
278+
void validateTypeCast(const PropertyTree& node)
279+
{
280+
try
281+
{
282+
node.getValue().as<T>();
283+
}
284+
catch (const std::exception& e)
285+
{
286+
std::throw_with_nested(e);
287+
}
288+
}
289+
290+
/**
291+
* @brief Validator: type cast and enforce 'minimum'/'maximum' range constraints.
228292
* @param node Node to validate.
229-
* @throws runtime_error if not found.
293+
* @throws runtime_error if out of range.
230294
*/
231-
void validateEnum(const PropertyTree& node);
295+
template <typename T>
296+
void validateTypeCastWithRange(const PropertyTree& node)
297+
{
298+
// Get value
299+
const T val = [&]() {
300+
try
301+
{
302+
return node.getValue().as<T>();
303+
}
304+
catch (const std::exception& e)
305+
{
306+
std::throw_with_nested(e);
307+
}
308+
}();
309+
310+
// If minimum attribute exist, validate
311+
auto min_attr = node.getAttribute(property_attribute::MINIMUM);
312+
if (min_attr)
313+
{
314+
const auto minv = min_attr->as<T>();
315+
if (val < minv)
316+
std::throw_with_nested(std::runtime_error("Property value " + std::to_string(val) + " is less than minimum " +
317+
std::to_string(minv)));
318+
}
319+
320+
// If maximum attribute exist, validate
321+
auto max_attr = node.getAttribute(property_attribute::MAXIMUM);
322+
if (max_attr)
323+
{
324+
const auto maxv = max_attr->as<T>();
325+
if (val > maxv)
326+
std::throw_with_nested(std::runtime_error("Property value " + std::to_string(val) + " is greater than maximum " +
327+
std::to_string(maxv)));
328+
}
329+
}
232330

233331
} // namespace tesseract_common
234332

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef TESSERACT_COMMON_SCHEMA_REGISTRATION_H
2+
#define TESSERACT_COMMON_SCHEMA_REGISTRATION_H
3+
4+
#include <string>
5+
#include <functional>
6+
7+
namespace tesseract_common
8+
{
9+
class PropertyTree;
10+
11+
struct SchemaRegistrar
12+
{
13+
SchemaRegistrar(const std::string& key, const std::string& path);
14+
15+
SchemaRegistrar(const std::string& key, const std::function<PropertyTree()>& fn);
16+
};
17+
18+
} // namespace tesseract_common
19+
20+
/// Macro to register either a file‐based schema or a function‐built schema
21+
#define TESSERACT_REGISTER_SCHEMA(KEY, SCHEMA_SOURCE) \
22+
namespace \
23+
{ \
24+
/* now a const POD, linter is happy */ \
25+
static const int _reg_##KEY = []() -> int { \
26+
using namespace tesseract_common; \
27+
/* calls the appropriate SchemaRegistrar constructor */ \
28+
SchemaRegistrar(#KEY, SCHEMA_SOURCE); \
29+
return 0; \
30+
}(); \
31+
}
32+
33+
#endif // TESSERACT_COMMON_SCHEMA_REGISTRATION_H

0 commit comments

Comments
 (0)