1 #ifndef ConscienceEnvironmentInteractionCommandParams_h
2 #define ConscienceEnvironmentInteractionCommandParams_h
10 #include <shared_mutex>
14 using std::type_info, std::any, std::shared_mutex, std::shared_lock, std::unique_lock, std::any_cast, std::function;
18 #define FOR_EACH_PAIR(macro, ...) \
19 __VA_OPT__(MACRO_EXPAND(FOR_EACH_PAIR_HELPER(macro, __VA_ARGS__)))
21 #define FOR_EACH_PAIR_HELPER(macro, a1, a2, ...) \
23 __VA_OPT__(FOR_EACH_PAIR_AGAIN MACRO_PARENS(macro, __VA_ARGS__))
24 #define FOR_EACH_PAIR_AGAIN() FOR_EACH_PAIR_HELPER
26 template <
typename TClass>
28 if (!objectAny.has_value()) {
33 return objectPtr ==
nullptr ? nullptr : objectPtr.get();
34 }
catch (exception &e) {
37 ptr<TClass> objectPtr = any_cast<ptr<TClass>>(objectAny);
38 return objectPtr ==
nullptr ? nullptr : objectPtr.get();
39 }
catch (exception &e) {
42 return any_cast<TClass *>(objectAny);
43 }
catch (exception &e) {
46 return any_cast<const TClass *>(objectAny);
47 }
catch (exception &e) {
49 throw runtime_error(
"cannot get " +
getClassName(
typeid(TClass),
true) +
"* from " +
getClassName(objectAny.type(),
true));
52 template <
class TValue>
55 template <
class TValue>
62 ENUM(CommandParamMetaType,
63 CommandParamMetaType_double,
64 CommandParamMetaType_float,
65 CommandParamMetaType_int,
66 CommandParamMetaType_long,
67 CommandParamMetaType_unsigned_long_long,
68 CommandParamMetaType_bool,
69 CommandParamMetaType_string,
70 CommandParamMetaType_list,
71 CommandParamMetaType_map,
72 CommandParamMetaType_object,
73 CommandParamMetaType_optional,
74 CommandParamMetaType_enum,
75 CommandParamMetaType_entityReflexion,
76 CommandParamMetaType_entityModel,
77 CommandParamMetaType_placeModel,
78 CommandParamMetaType_objectModel);
122 virtual map<string, JsonSerializableData> toJsonMap() = 0;
133 string headerFileRelativePath =
"";
136 return enumQualifiedName +
" - values=" +
mapToString(values) +
" - headerFileRelativePath=" + headerFileRelativePath;
161 CommandParamMetaType
type;
164 vector<const CscCommandDataTypeNodeMetadata *> nestedParams;
167 optional<CscCommandPtrType> ptrType = {};
188 const string &getName()
const;
193 const string &getDoc()
const;
195 CommandParamMetaType getType()
const;
197 bool isValueRequired()
const;
202 string typeToString()
const;
207 const vector<const CscCommandDataTypeNodeMetadata *> &getNestedParams()
const;
217 optional<CscCommandPtrType> getPtrType()
const;
224 bool isTypeOrOptionalOfType(CommandParamMetaType commandParamMeta)
const;
226 static vector<const CscCommandDataTypeNodeMetadata *> parseFromFieldsList(
const string &fieldsList);
231 void appendDoc(
const string &doc);
239 void collectReferencedObjectTypesMetadataRecursively(vector<const CscCommandDataTypeMetadata *> &targetList)
const;
240 void collectEnumsMetadataRecursively(vector<const CscEnumInfos *> &targetList)
const;
253 static map<string, CscCommandDataTypeMetadata *> theMap;
264 static map<string, const CscCommandDataTypeMetadata *> theMap;
295 string headerFileRelativePath;
296 string paramsClassNameWithNamespace;
297 string paramsClassName;
301 vector<const CscCommandDataTypeNodeMetadata *> params;
302 function<any()> createNullInstanceFunction;
306 const type_info ¶msClass,
307 int version,
const string &commandId,
308 const string &fieldsList,
309 const string &description);
311 const string ¶msClassNameWithNamespace,
312 const string ¶msClassName,
313 int version,
const string &commandId,
314 const vector<const CscCommandDataTypeNodeMetadata *> ¶ms,
315 const string &description);
321 const string getClassName(
bool withNamespace =
true)
const;
326 const string &getCommandId()
const;
331 const string &getHeaderFileRelativePath()
const;
336 vector<const CscCommandDataTypeMetadata *> getAllObjectTypesMetadata()
const;
341 vector<const CscEnumInfos *> getAllEnumsMetadata()
const;
343 void collectReferencedObjectTypesMetadataRecursively(vector<const CscCommandDataTypeMetadata *> &targetList)
const;
344 void collectEnumsMetadataRecursively(vector<const CscEnumInfos *> &targetList)
const;
349 int getVersion()
const;
350 const string &getDescription()
const;
351 const vector<const CscCommandDataTypeNodeMetadata *> &getParams()
const;
357 vector<string> getParamNames()
const;
359 void update(
const string &headerFileRelativePath,
const string &classQualifiedName,
const string &classSimpleName,
const string &doc,
const vector<const CscCommandDataTypeNodeMetadata *> ¶msMetadata,
const string &commandId);
366 static map<string, const CscCommandDataTypeMetadata *> getAllCommandsMetadata();
370 static vector<string> getKnownCommandIds();
382 static map<const type_info *, function<optional<JsonSerializableData>(
const any &
object)>> serializers;
389 bool existing = serializers.find(&typeInfo) != serializers.end();
390 LOG_DEBUG(
"register deserializer for " +
string(typeInfo.name()) +
" -- existing=" +
boolToString(existing));
391 serializers[&typeInfo] = serializer;
397 function<optional<JsonSerializableData>(
const any &
object)> SERIALIZER_STRING = [](
const any &object) -> optional<JsonSerializableData> {
398 const string *stringPtr = anyToPointer<string>(
object);
399 if (stringPtr ==
nullptr) {
406 template <
typename TData>
410 const type_info &resultType =
typeid(TData);
411 auto jsonSerializerMatch = serializers.find(&resultType);
412 if (jsonSerializerMatch == serializers.end()) {
413 using TDataCleaned = std::remove_cvref_t<TData>;
414 if constexpr (std::is_same_v<TDataCleaned, string>) {
415 return SERIALIZER_STRING;
417 if constexpr (std::is_arithmetic_v<TDataCleaned> || std::is_enum_v<TDataCleaned>) {
418 return [](
const any &object) -> optional<JsonSerializableData> {
419 const TDataCleaned *objectPtr = anyToPointer<TDataCleaned>(
object);
420 if (objectPtr ==
nullptr) {
423 if constexpr (std::is_enum_v<TDataCleaned>) {
424 using Under = std::underlying_type_t<TDataCleaned>;
433 return jsonSerializerMatch->second;
439 #define FIELDS_PAIR_PRINT(type, name) type name;
441 template <
typename T>
444 template <IsMap TMap>
447 template <IsOptional TOptional>
450 template <IsVector TVector>
453 template <
typename T>
456 return any_cast<T>(anyValue);
457 }
catch (
const std::bad_any_cast &e) {
463 template <IsMap TMap>
465 using K =
typename TMap::key_type;
466 using V =
typename TMap::mapped_type;
467 if (anyValue.type() ==
typeid(TMap)) {
468 return any_cast<TMap>(anyValue);
472 map<K, any> mapAny = any_cast<map<K, any>>(anyValue);
474 for (
auto it : mapAny) {
475 result[it.first] = field_value_any_cast<V>(it.second);
479 }
catch (
const std::bad_any_cast &e) {
485 template <IsOptional TOptional>
487 using TElement =
typename TOptional::value_type;
488 if (anyValue.type() ==
typeid(TOptional)) {
489 return any_cast<TOptional>(anyValue);
492 if (anyValue.type() ==
typeid(optional<any>)) {
493 auto theOptional = any_cast<optional<any>>(anyValue);
494 if (theOptional.has_value()) {
495 result = field_value_any_cast<TElement>(theOptional.value());
497 }
else if (anyValue.has_value()) {
498 result = field_value_any_cast<TElement>(anyValue);
504 template <IsVector TVector>
506 using TElement =
typename TVector::value_type;
507 if (anyValue.type() ==
typeid(TVector)) {
508 return any_cast<TVector>(anyValue);
511 vector<any> vectorAny = any_cast<vector<any>>(anyValue);
513 for (
auto it : vectorAny) {
514 result.push_back(field_value_any_cast<TElement>(it));
517 }
catch (
const std::bad_any_cast &e) {
523 #define FIELDS_ASSIGN_FROM_MAP_PRINT(FIELD_type, FIELD_name) \
525 if (fieldsValues.find(#FIELD_name) != fieldsValues.end()) { \
526 any actualValue = fieldsValues.at(#FIELD_name); \
527 if (string(#FIELD_type) == "string" && typeid(const char *) == actualValue.type()) { \
528 actualValue = string(any_cast<const char *>(actualValue)); \
530 LOGGER_TRACE("set " + string(#FIELD_name)); \
531 actualValue = field_value_any_cast<FIELD_type>(actualValue); \
532 targetObject->FIELD_name = any_cast<FIELD_type>(actualValue); \
534 LOGGER_WARN(string("cannot find ") + #FIELD_name) \
536 } catch (const std::bad_any_cast &e) { \
537 LOGGER_INFO(string("cannot set ") + #FIELD_type + " " + #FIELD_name + ": " + e.what()); \
541 template <
typename T>
544 template <
typename T>
548 template <typename T>
552 template <typename T>
558 template <
IsMap TMap>
561 template <typename T>
565 template <typename T>
569 template <typename T>
572 using TPointee = std::remove_cvref_t<typename PointeeType<std::remove_cvref_t<T>>::pointee_type>;
574 if (value ==
nullptr) {
577 if constexpr (std::is_base_of_v<CscCommandDataTypeBase, TPointee>) {
579 return jsonObject->toJsonMap();
581 throw runtime_error(
"cannot retrieve data type as CscCommandDataTypeBase: " +
getClassName(
typeid(TPointee),
true));
583 function<optional<JsonSerializableData>(
const any &
object)> serializer = getCommandDataJsonSerializer<TPointee>();
584 optional<JsonSerializableData> jsonMap = serializer(value);
585 if (jsonMap.has_value()) {
586 return jsonMap.value();
591 throw runtime_error(
"unsupported object type for serialization: " +
getClassName(
typeid(TPointee),
true));
594 template <
typename T>
597 if (value ==
nullptr) {
603 template <
typename T>
605 if (!value.has_value()) {
611 template <IsMap TMap>
613 using K =
typename TMap::key_type;
614 map<K, JsonSerializableData> jsonMap;
615 for (
auto it : value) {
621 template <IsVector TVector>
623 vector<JsonSerializableData> jsonList;
624 for (
auto it : value) {
632 template <
typename T>
633 requires (std::is_convertible_v<T, JsonSerializableData> && !HasBuiltinCommandJsonSerialization<T>)
638 template <
typename T>
639 requires (!std::is_convertible_v<T, JsonSerializableData> && !HasBuiltinCommandJsonSerialization<T>)
641 function<optional<JsonSerializableData>(
const any &
object)> serializer = getCommandDataJsonSerializer<T>();
642 optional<JsonSerializableData> jsonMap = serializer(&value);
643 if (jsonMap.has_value()) {
644 return jsonMap.value();
649 #define FIELDS_ASSIGN_INTO_JSONMAP_PRINT(FIELD_type, FIELD_name) \
651 JsonSerializableData jsonSerializableValue = field_value_to_json_serializable(object->FIELD_name); \
652 jsonMap[#FIELD_name] = jsonSerializableValue; \
653 } catch (const exception &e) { \
654 LOGGER_INFO(string("cannot set ") + #FIELD_type + " " + #FIELD_name + " into map: " + e.what()); \
658 #define FIELDS_ASSIGN_INTO_JSONMAP_PRINT_NOTYPE(FIELD_name) \
659 FIELDS_ASSIGN_INTO_JSONMAP_PRINT(UnspecifiedType, FIELD_name)
661 template <
typename T>
672 CSC_DLL_IMPORTEXPORT map<string, any>
parseCommandParametersAsMap(
const string &commandId,
const vector<string> &commandStringArguments, optional<int> knowledgeId,
bool objectsAsMap,
bool resolveObjects =
true,
bool permissive =
false);
680 return fs::is_directory(CscKeyDirectories::getInstance()->getUserCustomCommandCodeDir(commandId));