LCOV - code coverage report
Current view: top level - libprimis-headers - prop.h (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 242 266 91.0 %
Date: 2024-11-22 05:07:59 Functions: 48 50 96.0 %

          Line data    Source code
       1             : /**
       2             :  * @file prop.h
       3             :  * @brief Type-agnotic property system
       4             :  *
       5             :  * This file provides a type-agnostic property system.
       6             :  * It is used to provide a generic interface for convenient property access for objects,
       7             :  * entities and entire systems.
       8             :  */
       9             : 
      10             : #ifndef PROP_H_
      11             : #define PROP_H_
      12             : 
      13             : #include <any>
      14             : #include <variant>
      15             : 
      16             : #include "cube.h"
      17             : 
      18             : namespace prop
      19             : {
      20             : 
      21             : /**
      22             :  * @brief Storage for a property value
      23             :  *
      24             :  * This type is used to store a property value.
      25             :  * Supported types are:
      26             :  * int, float, bvec, ivec, vec, std::string
      27             :  */
      28             : typedef std::variant<int, float, bvec, ivec, vec, std::string> PropertyValue;
      29             : 
      30             : /**
      31             :  * @brief Callback type for property changes
      32             :  *
      33             :  * @param argument - The argument passed to the callback.
      34             :  */
      35             : typedef std::function<void(std::any argument)> OnChangeCallback;
      36             : 
      37             : /**
      38             :  * @brief Type of a property
      39             :  *
      40             :  * This enum is used to determine the type of a property.
      41             :  * Mandates what sort of type is stored inside the PropertyValue.
      42             :  */
      43             : enum class PropertyType
      44             : {
      45             :     NoType = -1,
      46             : 
      47             :     Int,
      48             :     Float,
      49             :     Color,
      50             :     IntVec,
      51             :     FloatVec,
      52             :     String,
      53             : 
      54             :     Count
      55             : };
      56             : 
      57             : /**
      58             :  * @brief Meta information about a property
      59             :  *
      60             :  * This class stores definition information for a property:
      61             :  * - name (string)
      62             :  * - type (PropertyType)
      63             :  * - min, default and max values (PropertyValue)
      64             :  *
      65             :  * All properties should be statically bound to their PropertyMeta counterparts.
      66             :  */
      67             : class PropertyMeta
      68             : {
      69             : private:
      70             :     std::string name;
      71             :     PropertyType type;
      72             :     PropertyValue min, def, max;
      73             :     OnChangeCallback on_change;
      74             : 
      75             : public:
      76             :     PropertyType get_type() const;
      77             :     PropertyValue get_min() const;
      78             :     PropertyValue get_def() const;
      79             :     PropertyValue get_max() const;
      80             :     std::string get_name() const;
      81             : 
      82             :     void changed(std::any argument) const;
      83             : 
      84          16 :     template<class T> PropertyMeta(std::string _name, PropertyType _type, T _min, T _def, T _max,
      85             :                                    OnChangeCallback _on_change = nullptr) :
      86          16 :         name(_name), type(_type), min(_min), def(_def), max(_max), on_change(_on_change) {}
      87           2 :     template<class T> PropertyMeta(std::string _name, PropertyType _type, T _def,
      88             :                                    OnChangeCallback _on_change = nullptr) :
      89           2 :         name(_name), type(_type), def(_def), on_change(_on_change) {}
      90             : 
      91             :     PropertyMeta(const PropertyMeta&) = delete;
      92             : };
      93             : 
      94             : /**
      95             :  * @brief A property
      96             :  *
      97             :  * @tparam PropertyMetaT - The type of the meta class, defaults to PropertyMeta
      98             :  *
      99             :  * This class is an instance of a property. It stores a value and a reference to its meta class.
     100             :  */
     101             : template<typename PropertyMetaT = PropertyMeta>
     102             : class Property
     103             : {
     104             : private:
     105             :     PropertyValue value;
     106             :     const PropertyMetaT& meta;
     107             : 
     108             :     bool set_check_type(PropertyType type) const;
     109             :     void set_clamped(PropertyValue value);
     110             : 
     111             : public:
     112             :     const PropertyValue& get_value() const;
     113             :     int get_int() const;
     114             :     float get_float() const;
     115             :     const bvec& get_color() const;
     116             :     const ivec& get_ivec() const;
     117             :     const vec& get_fvec() const;
     118             :     const std::string& get_string() const;
     119             :     size_t get_size() const;
     120             :     std::string get_name() const;
     121             :     PropertyType get_type() const;
     122             : 
     123             :     std::string to_string() const;
     124             : 
     125             :     void copy(const Property& prop);
     126             : 
     127             :     void set(PropertyValue value, std::any on_change_argument = std::any());
     128             :     void set_no_cb(PropertyValue value);
     129             : 
     130             :     void reset();
     131             : 
     132             :     void cmd_result() const;
     133             :     void cmd_result_min() const;
     134             :     void cmd_result_def() const;
     135             :     void cmd_result_max() const;
     136             : 
     137             :     virtual void pack(std::vector<uint8_t>& buf) const;
     138             :     virtual size_t unpack(const uint8_t* buf, size_t len);
     139             : 
     140             :     Property(const PropertyMetaT& _meta);
     141          19 :     virtual ~Property() = default;
     142             : };
     143             : 
     144             : 
     145             : 
     146             : ////////////////////
     147             : // Implementation //
     148             : ////////////////////
     149             : 
     150             : 
     151             : 
     152             : /**
     153             :  * @brief Get the integer value of the property
     154             :  *
     155             :  * @tparam PropertyMetaT - The type of the meta class.
     156             :  * @return int
     157             :  *
     158             :  * Caution: This function does not check the type of the property. A former check is assumed.
     159             :  */
     160             : template<typename PropertyMetaT>
     161           7 : int Property<PropertyMetaT>::get_int() const
     162             : {
     163           7 :     return std::get<int>(value);
     164             : }
     165             : 
     166             : /**
     167             :  * @brief Get the float value of the property
     168             :  *
     169             :  * @tparam PropertyMetaT - The type of the meta class.
     170             :  * @return float
     171             :  *
     172             :  * Caution: This function does not check the type of the property. A former check is assumed.
     173             :  */
     174             : template<typename PropertyMetaT>
     175           7 : float Property<PropertyMetaT>::get_float() const
     176             : {
     177           7 :     return std::get<float>(value);
     178             : }
     179             : 
     180             : /**
     181             :  * @brief Get the color value of the property
     182             :  *
     183             :  * @tparam PropertyMetaT - The type of the meta class.
     184             :  * @return bvec
     185             :  *
     186             :  * Caution: This function does not check the type of the property. A former check is assumed.
     187             :  */
     188             : template<typename PropertyMetaT>
     189           7 : const bvec& Property<PropertyMetaT>::get_color() const
     190             : {
     191           7 :     return std::get<bvec>(value);
     192             : }
     193             : 
     194             : /**
     195             :  * @brief Get the integer vector value of the property
     196             :  *
     197             :  * @tparam PropertyMetaT - The type of the meta class.
     198             :  * @return ivec
     199             :  *
     200             :  * Caution: This function does not check the type of the property. A former check is assumed.
     201             :  */
     202             : template<typename PropertyMetaT>
     203           8 : const ivec& Property<PropertyMetaT>::get_ivec() const
     204             : {
     205           8 :     return std::get<ivec>(value);
     206             : }
     207             : 
     208             : /**
     209             :  * @brief Get the float vector value of the property
     210             :  *
     211             :  * @tparam PropertyMetaT - The type of the meta class.
     212             :  * @return vec
     213             :  *
     214             :  * Caution: This function does not check the type of the property. A former check is assumed.
     215             :  */
     216             : template<typename PropertyMetaT>
     217           8 : const vec& Property<PropertyMetaT>::get_fvec() const
     218             : {
     219           8 :     return std::get<vec>(value);
     220             : }
     221             : 
     222             : /**
     223             :  * @brief Get the string value of the property
     224             :  *
     225             :  * @tparam PropertyMetaT - The type of the meta class.
     226             :  * @return std::string
     227             :  *
     228             :  * Caution: This function does not check the type of the property. A former check is assumed.
     229             :  */
     230             : template<typename PropertyMetaT>
     231           6 : const std::string& Property<PropertyMetaT>::get_string() const
     232             : {
     233           6 :     return std::get<std::string>(value);
     234             : }
     235             : 
     236             : /**
     237             :  * @brief Get the size of the property
     238             :  *
     239             :  * @tparam PropertyMetaT - The type of the meta class.
     240             :  * @return size_t
     241             :  *
     242             :  * Returns the size of the stored value in bytes.
     243             :  */
     244             : template<typename PropertyMetaT>
     245          24 : size_t Property<PropertyMetaT>::get_size() const
     246             : {
     247          24 :     switch(get_type())
     248             :     {
     249           5 :     case PropertyType::Int:
     250           5 :         return sizeof(int);
     251           5 :     case PropertyType::Float:
     252           5 :         return sizeof(float);
     253           5 :     case PropertyType::Color:
     254           5 :         return sizeof(bvec);
     255           4 :     case PropertyType::IntVec:
     256           4 :         return sizeof(ivec);
     257           4 :     case PropertyType::FloatVec:
     258           4 :         return sizeof(vec);
     259           1 :     case PropertyType::String:
     260           1 :         return get_string().size();
     261           0 :     default:
     262           0 :         return 0;
     263             :     }
     264             : }
     265             : 
     266             : template<typename PropertyMetaT>
     267           6 : std::string Property<PropertyMetaT>::to_string() const
     268             : {
     269           6 :     switch(get_type())
     270             :     {
     271           1 :     case PropertyType::Int:
     272           1 :         return std::to_string(get_int());
     273             : 
     274           1 :     case PropertyType::Float:
     275           1 :         return std::to_string(get_float());
     276             : 
     277           1 :     case PropertyType::Color:
     278           1 :         return std::to_string(get_color().r) + " " + std::to_string(get_color().g) + " " + std::to_string(get_color().b);
     279             : 
     280           1 :     case PropertyType::IntVec:
     281           1 :         return std::to_string(get_ivec().x) + " " + std::to_string(get_ivec().y) + " " + std::to_string(get_ivec().z);
     282             : 
     283           1 :     case PropertyType::FloatVec:
     284           1 :         return std::to_string(get_fvec().x) + " " + std::to_string(get_fvec().y) + " " + std::to_string(get_fvec().z);
     285             : 
     286           1 :     case PropertyType::String:
     287           1 :         return get_string();
     288             : 
     289           0 :     default:
     290           0 :         return "";
     291             :     }
     292             : }
     293             : 
     294             : template<typename PropertyMetaT>
     295          31 : bool Property<PropertyMetaT>::set_check_type(PropertyType type) const
     296             : {
     297             :     // typename used in debug printout below
     298             :     //static constexpr std::string_view typenames[] =
     299             :     //{
     300             :     //    "int", "float", "color", "int vector", "float vector", "string"
     301             :     //};
     302             : 
     303          31 :     if(get_type() != type)
     304             :     {
     305             :         // conoutf("Error: %s, incorrect property assignment type: got %s, expected %s",
     306             :         //         meta.get_name().c_str(), std::string(typenames[static_cast<size_t>(type)]).c_str(),
     307             :         //         std::string(typenames[static_cast<size_t>(get_type())]).c_str());
     308             : 
     309           0 :         return false;
     310             :     }
     311             : 
     312          31 :     return true;
     313             : }
     314             : 
     315             : /**
     316             :  * @brief Get the name of the property
     317             :  *
     318             :  * @tparam PropertyMetaT - The type of the meta class.
     319             :  * @return std::string
     320             :  *
     321             :  * Returns the name of the property, as per the definition in the meta class.
     322             :  */
     323             : template<typename PropertyMetaT>
     324         227 : std::string Property<PropertyMetaT>::get_name() const
     325             : {
     326         227 :     return meta.get_name();
     327             : }
     328             : 
     329             : /**
     330             :  * @brief Get the type of the property
     331             :  *
     332             :  * @tparam PropertyMetaT - The type of the meta class.
     333             :  * @return std::string
     334             :  *
     335             :  * Returns the type of the property, as per the definition in the meta class.
     336             :  */
     337             : template<typename PropertyMetaT>
     338         116 : PropertyType Property<PropertyMetaT>::get_type() const
     339             : {
     340         116 :     return meta.get_type();
     341             : }
     342             : 
     343             : /**
     344             :  * @brief Copy the value of another property, will not invoke callback
     345             :  *
     346             :  * @tparam PropertyMetaT - The type of the meta class.
     347             :  * @param prop - The property to copy the value from.
     348             :  * @param on_change_arg - Optional argument for on_change callback.
     349             :  *
     350             :  * Note: type check is performed automatically, value of an incompatible type is ignored and reported.
     351             :  * Value is clamped to the range defined in the meta class, if applicable.
     352             :  */
     353             : template<typename PropertyMetaT>
     354             : void Property<PropertyMetaT>::copy(const Property& prop)
     355             : {
     356             :     set_no_cb(prop.value);
     357             : }
     358             : 
     359             : template<typename PropertyMetaT>
     360          31 : void Property<PropertyMetaT>::set_clamped(PropertyValue value)
     361             : {
     362          31 :     switch(get_type())
     363             :     {
     364           7 :         case PropertyType::Int:
     365             :         {
     366           7 :             int v = std::get<int>(value);
     367           7 :             this->value = std::clamp(v, std::get<int>(meta.get_min()), std::get<int>(meta.get_max()));
     368           7 :             break;
     369             :         }
     370             : 
     371           6 :         case PropertyType::Float:
     372             :         {
     373           6 :             float v = std::get<float>(value);
     374           6 :             this->value = std::clamp(v, std::get<float>(meta.get_min()), std::get<float>(meta.get_max()));
     375           6 :             break;
     376             :         }
     377             : 
     378           5 :         case PropertyType::IntVec:
     379             :         {
     380           5 :             ivec v = std::get<ivec>(value);
     381          10 :             this->value = ivec(v).min(std::get<ivec>(meta.get_max()))
     382          10 :                                  .max(std::get<ivec>(meta.get_min()));
     383           5 :             break;
     384             :         }
     385             : 
     386           5 :         case PropertyType::FloatVec:
     387             :         {
     388           5 :             vec v = std::get<vec>(value);
     389          10 :             this->value = vec(v).min(std::get<vec>(meta.get_max()))
     390          10 :                                 .max(std::get<vec>(meta.get_min()));
     391           5 :             break;
     392             :         }
     393             : 
     394           8 :         default:
     395           8 :             this->value = value;
     396           8 :             break;
     397             :     }
     398          31 : }
     399             : 
     400             : /**
     401             :  * @brief Set the value of the property
     402             :  *
     403             :  * @tparam PropertyMetaT - The type of the meta class.
     404             :  * @param value - The new value of the property.
     405             :  * @param on_change_arg - Optional argument for on_change callback.
     406             :  *
     407             :  * Note: type check is performed automatically, value of an incompatible type is ignored and reported.
     408             :  * Value is clamped to the range defined in the meta class, if applicable.
     409             :  */
     410             : template<typename PropertyMetaT>
     411          31 : void Property<PropertyMetaT>::set(PropertyValue value, std::any on_change_arg)
     412             : {
     413          31 :     if(set_check_type(static_cast<PropertyType>(value.index())))
     414             :     {
     415          31 :         set_clamped(value);
     416          31 :         meta.changed(on_change_arg);
     417             :     }
     418          31 : }
     419             : 
     420             : /**
     421             :  * @brief Set the value of the property without invoking callback
     422             :  *
     423             :  * @tparam PropertyMetaT - The type of the meta class.
     424             :  * @param value - The new value of the property.
     425             :  *
     426             :  * Note: type check is performed automatically, value of an incompatible type is ignored and reported.
     427             :  * Value is clamped to the range defined in the meta class, if applicable.
     428             :  */
     429             : template<typename PropertyMetaT>
     430           0 : void Property<PropertyMetaT>::set_no_cb(PropertyValue value)
     431             : {
     432           0 :     if(set_check_type(static_cast<PropertyType>(value.index())))
     433             :     {
     434           0 :         set_clamped(value);
     435             :     }
     436           0 : }
     437             : 
     438             : /**
     439             :  * @brief Reset the value of the property to the default value
     440             :  *
     441             :  * @tparam PropertyMetaT - The type of the meta class.
     442             :  */
     443             : template<typename PropertyMetaT>
     444          30 : void Property<PropertyMetaT>::reset()
     445             : {
     446          30 :     this->value = meta.get_def();
     447          30 : }
     448             : 
     449           6 : static void _prop_cmd_result_value(PropertyValue value, PropertyType type)
     450             : {
     451           6 :     switch(type)
     452             :     {
     453           1 :         case PropertyType::Int:
     454           1 :             intret(std::get<int>(value));
     455           1 :             break;
     456             : 
     457           1 :         case PropertyType::Float:
     458           1 :             floatret(std::get<float>(value));
     459           1 :             break;
     460             : 
     461           1 :         case PropertyType::Color:
     462           1 :             intret(std::get<bvec>(value).tohexcolor());
     463           1 :             break;
     464             : 
     465           1 :         case PropertyType::IntVec:
     466             :         {
     467           1 :             const ivec& v = std::get<ivec>(value);
     468           1 :             result(tempformatstring("%d %d %d", v.x, v.y, v.z));
     469           1 :             break;
     470             :         }
     471             : 
     472           1 :         case PropertyType::FloatVec:
     473             :         {
     474           1 :             const vec& v = std::get<vec>(value);
     475           1 :             result(tempformatstring("%f %f %f", v.x, v.y, v.z));
     476           1 :             break;
     477             :         }
     478             : 
     479           1 :         case PropertyType::String:
     480           1 :             result(std::get<std::string>(value).c_str());
     481           1 :             break;
     482             : 
     483           0 :         default: break;
     484             :     }
     485           6 : }
     486             : 
     487             : /**
     488             :  * @brief Results the value of the property
     489             :  *
     490             :  * @tparam PropertyMetaT - The type of the meta class.
     491             :  */
     492             : template<typename PropertyMetaT>
     493           6 : void Property<PropertyMetaT>::cmd_result() const
     494             : {
     495           6 :     _prop_cmd_result_value(value, get_type());
     496           6 : }
     497             : 
     498             : /**
     499             :  * @brief Results the minimum value of the property
     500             :  *
     501             :  * @tparam PropertyMetaT - The type of the meta class.
     502             :  */
     503             : template<typename PropertyMetaT>
     504             : void Property<PropertyMetaT>::cmd_result_min() const
     505             : {
     506             :     _prop_cmd_result_value(meta.get_min(), get_type());
     507             : }
     508             : 
     509             : /**
     510             :  * @brief Results the default value of the property
     511             :  *
     512             :  * @tparam PropertyMetaT - The type of the meta class.
     513             :  */
     514             : template<typename PropertyMetaT>
     515             : void Property<PropertyMetaT>::cmd_result_def() const
     516             : {
     517             :     _prop_cmd_result_value(meta.get_def(), get_type());
     518             : }
     519             : 
     520             : /**
     521             :  * @brief Results the maximum value of the property
     522             :  *
     523             :  * @tparam PropertyMetaT - The type of the meta class.
     524             :  */
     525             : template<typename PropertyMetaT>
     526             : void Property<PropertyMetaT>::cmd_result_max() const
     527             : {
     528             :     _prop_cmd_result_value(meta.get_max(), get_type());
     529             : }
     530             : 
     531             : /**
     532             :  * @brief Packs the property into a buffer
     533             :  *
     534             :  * @tparam PropertyMetaT - The type of the meta class.
     535             :  * @param buf - The buffer to pack the property into.
     536             :  */
     537             : template<typename PropertyMetaT>
     538           6 : void Property<PropertyMetaT>::pack(std::vector<uint8_t>& buf) const
     539             : {
     540           6 :     size_t data_size = get_size();
     541             : 
     542           6 :     vectorput(buf, data_size);
     543             : 
     544           6 :     switch(get_type())
     545             :     {
     546           1 :         case PropertyType::Int:
     547             :         {
     548           1 :             vectorput(buf, get_int());
     549           1 :             break;
     550             :         }
     551             : 
     552           1 :         case PropertyType::Float:
     553             :         {
     554           1 :             vectorput(buf, get_float());
     555           1 :             break;
     556             :         }
     557             : 
     558           1 :         case PropertyType::Color:
     559             :         {
     560           1 :             vectorput(buf, get_color());
     561           1 :             break;
     562             :         }
     563             : 
     564           1 :         case PropertyType::IntVec:
     565             :         {
     566           1 :             vectorput(buf, get_ivec());
     567           1 :             break;
     568             :         }
     569             : 
     570           1 :         case PropertyType::FloatVec:
     571             :         {
     572           1 :             vectorput(buf, get_fvec());
     573           1 :             break;
     574             :         }
     575             : 
     576           1 :         case PropertyType::String:
     577             :         {
     578           1 :             std::string data = get_string();
     579             :             // Null-terminator not needed, since we know the size
     580           1 :             vectorput(buf, reinterpret_cast<const uint8_t*>(data.data()), data.size());
     581           1 :             break;
     582           1 :         }
     583             : 
     584           0 :         default: break;
     585             :     }
     586           6 : }
     587             : 
     588             : /**
     589             :  * @brief Unpacks the property from a buffer
     590             :  *
     591             :  * @tparam PropertyMetaT - The type of the meta class.
     592             :  * @param buf - The buffer to unpack the property from.
     593             :  * @param buf_size - The size of the buffer.
     594             :  *
     595             :  * @return The number of bytes read from the buffer.
     596             :  */
     597             : template<typename PropertyMetaT>
     598           6 : size_t Property<PropertyMetaT>::unpack(const uint8_t* buf, size_t buf_size)
     599             : {
     600           6 :     size_t buf_read = 0;
     601           6 :     const size_t* data_size_packed = nullptr;
     602             : 
     603           6 :     if(buf_size <= sizeof(*data_size_packed))
     604             :     {
     605             :         // conoutf("Error unpacking prop '%s': not enough data to get the size!", meta.get_name().c_str());
     606           0 :         return 0;
     607             :     }
     608             : 
     609           6 :     data_size_packed = reinterpret_cast<const size_t*>(buf);
     610             : 
     611           6 :     buf_read += sizeof(*data_size_packed);
     612             : 
     613           6 :     static auto size_check = [&](size_t needed_size)
     614             :     {
     615           6 :         if(buf_size - buf_read < needed_size)
     616             :         {
     617             :             // conoutf("Error unpacking prop '%s': not enough data!", meta.get_name().c_str());
     618           0 :             return false;
     619             :         }
     620             : 
     621           6 :         return true;
     622             :     };
     623             : 
     624           6 :     switch(get_type())
     625             :     {
     626           3 :         case PropertyType::Int:
     627             :         case PropertyType::Color:
     628             :         case PropertyType::Float:
     629           3 :             if(*data_size_packed != get_size())
     630             :             {
     631             :                 // conoutf("Error unpacking prop '%s': unexpected data size! Wanted: %lu, got: %lu",
     632             :                 //         meta.get_name().c_str(), get_size(), *data_size_packed);
     633             : 
     634           0 :                 return 0;
     635             :             }
     636           3 :             break;
     637             : 
     638           3 :         default: break;
     639             :     }
     640             : 
     641           6 :     switch(get_type())
     642             :     {
     643           1 :         case PropertyType::Int:
     644             :         {
     645           1 :             if(!size_check(get_size()))
     646             :             {
     647           0 :                 return 0;
     648             :             }
     649             : 
     650             :             int ival;
     651           1 :             memcpy(&ival, buf + buf_read, get_size());
     652           1 :             buf_read += get_size();
     653           1 :             value = ival;
     654           1 :             break;
     655             :         }
     656             : 
     657           1 :         case PropertyType::Float:
     658             :         {
     659           1 :             if(!size_check(get_size()))
     660             :             {
     661           0 :                 return 0;
     662             :             }
     663             : 
     664             :             float fval;
     665           1 :             memcpy(&fval, buf + buf_read, get_size());
     666           1 :             buf_read += get_size();
     667           1 :             value = fval;
     668           1 :             break;
     669             :         }
     670             : 
     671           1 :         case PropertyType::Color:
     672             :         {
     673           1 :             if(!size_check(get_size()))
     674             :             {
     675           0 :                 return 0;
     676             :             }
     677             : 
     678           1 :             bvec cval;
     679           1 :             memcpy(&cval, buf + buf_read, get_size());
     680           1 :             buf_read += get_size();
     681           1 :             value = cval;
     682           1 :             break;
     683             :         }
     684             : 
     685           1 :         case PropertyType::IntVec:
     686             :         {
     687           1 :             if(!size_check(get_size()))
     688             :             {
     689           0 :                 return 0;
     690             :             }
     691             : 
     692           1 :             ivec ivecval;
     693           1 :             memcpy(&ivecval, buf + buf_read, get_size());
     694           1 :             buf_read += get_size();
     695           1 :             value = ivecval;
     696           1 :             break;
     697             :         }
     698             : 
     699           1 :         case PropertyType::FloatVec:
     700             :         {
     701           1 :             if(!size_check(get_size()))
     702             :             {
     703           0 :                 return 0;
     704             :             }
     705             : 
     706           1 :             vec vecval;
     707           1 :             memcpy(&vecval, buf + buf_read, get_size());
     708           1 :             buf_read += get_size();
     709           1 :             value = vecval;
     710           1 :             break;
     711             :         }
     712             : 
     713           1 :         case PropertyType::String:
     714             :         {
     715           1 :             if(!size_check(*data_size_packed))
     716             :             {
     717           0 :                 return 0;
     718             :             }
     719             : 
     720           1 :             std::string sval(reinterpret_cast<const char*>(buf + buf_read), *data_size_packed);
     721           1 :             buf_read += *data_size_packed;
     722           1 :             value = sval;
     723           1 :             break;
     724           1 :         }
     725             : 
     726           0 :         default: break;
     727             :     }
     728             : 
     729           6 :     return buf_read;
     730             : }
     731             : 
     732             : /**
     733             :  * @brief Creates a new property with the given meta class.
     734             :  *
     735             :  * @tparam PropertyMetaT - The type of the meta class.
     736             :  * @param _meta - The meta class.
     737             :  */
     738             : template<typename PropertyMetaT>
     739          30 : Property<PropertyMetaT>::Property(const PropertyMetaT& _meta) : meta(_meta)
     740             : {
     741          30 :     reset();
     742          30 : }
     743             : 
     744             : /**
     745             :  * @brief Gets the type of the property definition.
     746             :  *
     747             :  * @return PropertyType
     748             :  */
     749         116 : PropertyType PropertyMeta::get_type() const
     750             : {
     751         116 :     return type;
     752             : }
     753             : 
     754             : /**
     755             :  * @brief Gets the minimum value of the property definition.
     756             :  *
     757             :  * @return PropertyValue
     758             :  */
     759          23 : PropertyValue PropertyMeta::get_min() const
     760             : {
     761          23 :     return min;
     762             : }
     763             : 
     764             : /**
     765             :  * @brief Gets the default value of the property definition.
     766             :  *
     767             :  * @return PropertyValue
     768             :  */
     769          30 : PropertyValue PropertyMeta::get_def() const
     770             : {
     771          30 :     return def;
     772             : }
     773             : 
     774             : /**
     775             :  * @brief Gets the maximum value of the property definition.
     776             :  *
     777             :  * @return PropertyValue
     778             :  */
     779          23 : PropertyValue PropertyMeta::get_max() const
     780             : {
     781          23 :     return max;
     782             : }
     783             : 
     784             : /**
     785             :  * @brief Gets the name of the property definition.
     786             :  *
     787             :  * @return std::string
     788             :  */
     789         299 : std::string PropertyMeta::get_name() const
     790             : {
     791         299 :     return name;
     792             : }
     793             : 
     794          31 : void PropertyMeta::changed(std::any argument) const
     795             : {
     796          31 :     if(on_change)
     797             :     {
     798           1 :         on_change(argument);
     799             :     }
     800          31 : }
     801             : 
     802             : 
     803             : 
     804             : //////////////////////
     805             : // Helper functions //
     806             : //////////////////////
     807             : 
     808             : 
     809             : 
     810             : /**
     811             :  * @brief Finds a property with the given name in the given array.
     812             :  *
     813             :  * @tparam PropertyT - Property class type
     814             :  * @tparam N - Size of the array
     815             :  * @param name - The name of the property to find.
     816             :  * @param props - The array of properties to search.
     817             :  * @return PropertyT* - The property if found, nullptr otherwise.
     818             :  */
     819             : template<typename PropertyT, std::size_t N>
     820          62 : PropertyT* find_prop(std::string name, std::array<PropertyT, N>& props)
     821             : {
     822         217 :     for(PropertyT& prop : props)
     823             :     {
     824         216 :         if(prop.get_name() == name)
     825             :         {
     826          61 :             return &prop;
     827             :         }
     828             :     }
     829             : 
     830           1 :     return nullptr;
     831             : }
     832             : 
     833             : /**
     834             :  * @brief Finds a property with the given name in the given array.
     835             :  *
     836             :  * @tparam PropertyT - Property class type
     837             :  * @tparam N - Size of the array
     838             :  * @param name - The name of the property to find.
     839             :  * @param props - The array of properties to search.
     840             :  * @return PropertyT* - The property if found, nullptr otherwise.
     841             :  */
     842             : template<typename PropertyT, std::size_t N>
     843           1 : const PropertyT* find_prop(std::string name, const std::array<PropertyT, N>& props)
     844             : {
     845          12 :     for(const PropertyT& prop : props)
     846             :     {
     847          11 :         if(prop.get_name() == name)
     848             :         {
     849           0 :             return &prop;
     850             :         }
     851             :     }
     852             : 
     853           1 :     return nullptr;
     854             : }
     855             : 
     856             : /**
     857             :  * @brief Sets the value of a property with the given name in the given array.
     858             :  *
     859             :  * @tparam PropertyT - Property class type
     860             :  * @tparam N - Size of the array
     861             :  * @param name - The name of the property to set.
     862             :  * @param value - The value to set the property to. Value is clamped to the property's min/max values, if applicable.
     863             :  * @param props - The array of properties to search.
     864             :  * @param on_change_arg - Optional argument to pass to the property's on_change callback.
     865             :  * @return true - The property was found and set.
     866             :  */
     867             : template<typename PropertyT, std::size_t N>
     868          32 : bool set_prop(std::string name, PropertyValue value, std::array<PropertyT, N>& props,
     869             :               std::any on_change_arg = std::any())
     870             : {
     871          32 :     PropertyT* prop = find_prop(name, props);
     872          32 :     if(!prop)
     873             :     {
     874             :         // conoutf("Property %s not found!", name.c_str());
     875           1 :         return false;
     876             :     }
     877             : 
     878          31 :     prop->set(value, on_change_arg);
     879          31 :     return true;
     880             : }
     881             : 
     882             : /**
     883             :  * @brief Finds a property definition with the given name in the given array.
     884             :  *
     885             :  * @tparam PropertyMetaT - PropertyMeta class type
     886             :  * @tparam N - Size of the array
     887             :  * @param name - The name of the property definition to find.
     888             :  * @param prop_metas - The array of property definitions to search.
     889             :  * @return const PropertyMetaT* - The property definition if found, nullptr otherwise.
     890             :  */
     891             : template<typename PropertyMetaT, std::size_t N>
     892             : const PropertyMetaT* find_prop_meta(std::string name, const std::array<PropertyMetaT, N>& prop_metas)
     893             : {
     894             :     for(const PropertyMetaT& prop_meta : prop_metas)
     895             :     {
     896             :         if(prop_meta.get_name() == name)
     897             :         {
     898             :             return &prop_meta;
     899             :         }
     900             :     }
     901             : 
     902             :     return nullptr;
     903             : }
     904             : 
     905             : /**
     906             :  * @brief Packs the given properties into the given buffer.
     907             :  *
     908             :  * @tparam PropertyT - Property class type
     909             :  * @tparam N - Size of the array
     910             :  * @param props - The array of properties to pack.
     911             :  * @param buf - The buffer to pack the properties into.
     912             :  */
     913             : template<typename PropertyT, std::size_t N>
     914           1 : void pack_props(const std::array<PropertyT, N>& props, std::vector<uint8_t>& buf)
     915             : {
     916           7 :     for(const PropertyT& prop : props)
     917             :     {
     918           6 :         prop.pack(buf);
     919             :     }
     920           1 : }
     921             : 
     922             : /**
     923             :  * @brief Unpacks the given buffer into the given properties.
     924             :  *
     925             :  * @tparam PropertyT - Property class type
     926             :  * @tparam N - Size of the array
     927             :  * @param buf - The buffer to unpack.
     928             :  * @param props - The array of properties to unpack into.
     929             :  * @return size_t - The number of properties unpacked.
     930             :  */
     931             : template<typename PropertyT, std::size_t N>
     932           1 : size_t unpack_props(const std::vector<uint8_t>& buf, std::array<PropertyT, N>& props)
     933             : {
     934           1 :     size_t prop_idx = 0;
     935           1 :     size_t read_pos = 0;
     936             : 
     937           7 :     while(read_pos < buf.size())
     938             :     {
     939           6 :         if(prop_idx >= N)
     940             :         {
     941           0 :             break;
     942             :         }
     943             : 
     944           6 :         PropertyT &prop = props[prop_idx];
     945             : 
     946           6 :         int unpacked_size = prop.unpack(buf.data() + read_pos, buf.size() - read_pos);
     947           6 :         if(!unpacked_size)
     948             :         {
     949           0 :             break;
     950             :         }
     951             : 
     952           6 :         read_pos += unpacked_size;
     953           6 :         prop_idx++;
     954             :     }
     955             : 
     956           1 :     return prop_idx;
     957             : }
     958             : 
     959             : template<std::size_t N, typename PropertyT, std::size_t... Is, typename PropertyMetaT>
     960           5 : std::array<PropertyT, N> _make_props_array_impl(std::index_sequence<Is...>,
     961             :                                                const PropertyMetaT (&prop_meta)[N])
     962             : {
     963           5 :     return { PropertyT(prop_meta[Is])... };
     964             : }
     965             : 
     966             : /**
     967             :  * @brief Creates an array of properties from the given property definitions.
     968             :  *
     969             :  * @tparam N - Size of the array
     970             :  * @tparam PropertyT - Property class type
     971             :  * @tparam Is - Index sequence
     972             :  * @tparam PropertyMetaT - PropertyMeta class type
     973             :  * @param prop_meta - The array of property definitions to create properties from.
     974             :  * @return std::array<PropertyT, N> - The array of properties bound to meta information.
     975             :  */
     976             : template<std::size_t N, typename PropertyT, std::size_t... Is, typename PropertyMetaT>
     977           5 : std::array<PropertyT, N> make_props_array(const PropertyMetaT (&prop_meta)[N])
     978             : {
     979           5 :     return _make_props_array_impl<N, PropertyT>(std::make_index_sequence<N>{}, prop_meta);
     980             : }
     981             : 
     982             : }; // namespace prop
     983             : 
     984             : #endif // PROP_H_

Generated by: LCOV version 1.14