// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #ifndef CSCORE_PROPERTYCONTAINER_H_ #define CSCORE_PROPERTYCONTAINER_H_ #include #include #include #include #include #include #include #include #include #include #include #include "PropertyImpl.h" #include "cscore_cpp.h" namespace wpi { class Logger; class json; } // namespace wpi namespace cs { class PropertyContainer { public: virtual ~PropertyContainer() = default; int GetPropertyIndex(const wpi::Twine& name) const; wpi::ArrayRef EnumerateProperties(wpi::SmallVectorImpl& vec, CS_Status* status) const; CS_PropertyKind GetPropertyKind(int property) const; wpi::StringRef GetPropertyName(int property, wpi::SmallVectorImpl& buf, CS_Status* status) const; int GetProperty(int property, CS_Status* status) const; virtual void SetProperty(int property, int value, CS_Status* status); int GetPropertyMin(int property, CS_Status* status) const; int GetPropertyMax(int property, CS_Status* status) const; int GetPropertyStep(int property, CS_Status* status) const; int GetPropertyDefault(int property, CS_Status* status) const; wpi::StringRef GetStringProperty(int property, wpi::SmallVectorImpl& buf, CS_Status* status) const; virtual void SetStringProperty(int property, const wpi::Twine& value, CS_Status* status); std::vector GetEnumPropertyChoices(int property, CS_Status* status) const; bool SetPropertiesJson(const wpi::json& config, wpi::Logger& logger, wpi::StringRef logName, CS_Status* status); wpi::json GetPropertiesJsonObject(CS_Status* status); protected: // Get a property; must be called with m_mutex held. PropertyImpl* GetProperty(int property) { if (property <= 0 || static_cast(property) > m_propertyData.size()) return nullptr; return m_propertyData[property - 1].get(); } const PropertyImpl* GetProperty(int property) const { if (property <= 0 || static_cast(property) > m_propertyData.size()) return nullptr; return m_propertyData[property - 1].get(); } // Create or update a property; must be called with m_mutex held. // @tparam NewFunc functor that returns a std::unique_ptr // @tparam UpdateFunc functor that takes a PropertyImpl&. template int CreateOrUpdateProperty(const wpi::Twine& name, NewFunc newFunc, UpdateFunc updateFunc) { wpi::SmallVector nameBuf; int& ndx = m_properties[name.toStringRef(nameBuf)]; if (ndx == 0) { // create a new index ndx = m_propertyData.size() + 1; m_propertyData.emplace_back(newFunc()); } else { // update existing updateFunc(*GetProperty(ndx)); } return ndx; } template int CreateProperty(const wpi::Twine& name, NewFunc newFunc) { return CreateOrUpdateProperty(name, newFunc, [](PropertyImpl&) {}); } // Create an "empty" property. This is called by GetPropertyIndex to create // properties that don't exist (as GetPropertyIndex can't fail). // Note: called with m_mutex held. // The default implementation simply creates a PropertyImpl object. virtual std::unique_ptr CreateEmptyProperty( const wpi::Twine& name) const; // Cache properties. Implementations must return false and set status to // CS_SOURCE_IS_DISCONNECTED if not possible to cache. // The default implementation simply sets m_property_cached to true. virtual bool CacheProperties(CS_Status* status) const; virtual void NotifyPropertyCreated(int propIndex, PropertyImpl& prop) = 0; // Update property value; must be called with m_mutex held. virtual void UpdatePropertyValue(int property, bool setString, int value, const wpi::Twine& valueStr) = 0; // Whether CacheProperties() has been successful at least once (and thus // should not be called again) mutable std::atomic_bool m_properties_cached{false}; mutable wpi::mutex m_mutex; // Cached properties (protected with m_mutex) mutable std::vector> m_propertyData; mutable wpi::StringMap m_properties; }; } // namespace cs #endif // CSCORE_PROPERTYCONTAINER_H_