Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
OptionsFile.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_DataExchange_OptionsFile_h_
5#define _Stroika_Foundation_DataExchange_OptionsFile_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <filesystem>
10#include <optional>
11
14#include "Stroika/Foundation/DataExchange/ObjectVariantMapper.h"
19
20/**
21 * \file
22 *
23 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
24 *
25 * TODO:
26 * @todo eFailedToReadFile should be broken into failed to read, and failed to upgrade.
27 *
28 * @todo Look at http://s11n.net/
29 *
30 * GIST:
31 * if you have mapper object for type T) � one line create object that writes/reads
32 * it to/from filesystem (defaults to good places) � and handles logging warning if created,
33 * or bad, and rewrites for if changes detected (added/renamed etc).
34 * Maybe hook / configure options for these features.
35 *
36 * \em Design Note:
37 */
38
40
41 using Characters::String;
42 using Memory::BLOB;
43
44 /**
45 * Simple wrapper on ObjectVariantMapper code, and code to serialize to/from JSON/XML etc, to wrap
46 * all this into an easy to use (but configurable/customizable) helper to serialize configuration data
47 * between disk and module-specific C++ objects.
48 *
49 * This is SOMEWHAT flexible and customizable, but not so much. Its mostly intended to be a one-size-fits all
50 * utility that will often be useful, and will save some typing. If it does fit your needs, don't use it, and
51 * use ObjectVariantMapper and the reader abstractions directly.
52 *
53 * \par Example Usage
54 * \code
55 * struct MyData_ {
56 * bool fEnabled = false;
57 * optional<DateTime> fLastSynchronizedAt;
58 * };
59 * // Execution::Logger::Activator logMgrActivator; // be sure a line like this in Main before the 'of' object usage
60 * OptionsFile of {
61 * "MyModule",
62 * [] () -> ObjectVariantMapper {
63 * ObjectVariantMapper mapper;
64 * mapper.AddClass<MyData_> (initializer_list<StructFieldInfo> {
65 * { "Enabled"sv, &MyData_::fEnabled },
66 * { "Last-Synchronized-At"sv, &MyData_::fLastSynchronizedAt },
67 * });
68 * return mapper;
69 * } (),
70 * OptionsFile::kDefaultUpgrader,
71 * [] (const String & moduleName, const String & fileSuffix) -> String {
72 * return IO::FileSystem::WellKnownLocations::GetTemporary () + moduleName;
73 * }
74 * };
75 * MyData_ m = of.Read<MyData_> (MyData_{}); // will return default values if file not present
76 * of.Write (m); // test writing
77 * \endcode
78 */
80 public:
81 /**
82 */
83 struct LoggerMessage;
84
85 public:
86 /**
87 */
88 using LoggerType = function<void (const LoggerMessage& message)>;
89
90 public:
91 /**
92 * \note - Since this uses Execution::Logger::sThe, if therefore requires use of
93 * Execution::Logger::Activator logMgrActivator
94 */
95 static const LoggerType kDefaultLogger;
96
97 public:
98 /**
99 */
100 using ModuleNameToFileNameMapperType = function<filesystem::path (const String& moduleName, const String& fileSuffix)>;
101
102 public:
103 /**
104 */
105 static ModuleNameToFileNameMapperType mkFilenameMapper (const String& appName);
106
107 public:
108 /**
109 * Optionally provide (based on filenames/locations) information about the incoming file(read file)
110 * version.
111 */
112 using ModuleNameToFileVersionMapperType = function<optional<Common::Version> (const String& moduleName)>;
113
114 public:
115 /**
116 */
117 static const ModuleNameToFileVersionMapperType kDefaultModuleNameToFileVersionMapper;
118
119 public:
120 /**
121 * This function gets a crack at revising the form (in variant/tree form) of the data to accomodate a version
122 * change. The version may not be known, in which case the function is still called, but with the verison information
123 * missing.
124 */
125 using ModuleDataUpgraderType = function<VariantValue (const optional<Common::Version>& version, const VariantValue& rawVariantValue)>;
126
127 public:
128 /**
129 * kDefaultUpgrader does nothing (no-op)
130 */
132
133 public:
134 /**
135 * Format serializer
136 */
138
139 public:
140 /**
141 * Format serializer
142 */
144
145 public:
146 /**
147 */
148 OptionsFile (const String& modName, const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader = kDefaultUpgrader,
149 ModuleNameToFileNameMapperType moduleNameToFileNameMapper = mkFilenameMapper ("Put-Your-App-Name-Here"sv),
150 ModuleNameToFileVersionMapperType moduleNameToReadFileVersion = kDefaultModuleNameToFileVersionMapper,
151 LoggerType logger = kDefaultLogger, Variant::Reader reader = kDefaultReader, Variant::Writer writer = kDefaultWriter);
152 OptionsFile (const String& modName, const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
153 ModuleNameToFileNameMapperType moduleNameToReadFileNameMapper, ModuleNameToFileNameMapperType moduleNameToWriteFileNameMapper,
154 ModuleNameToFileVersionMapperType moduleNameToReadFileVersion = kDefaultModuleNameToFileVersionMapper,
155 LoggerType logger = kDefaultLogger, Variant::Reader reader = kDefaultReader, Variant::Writer writer = kDefaultWriter);
156 OptionsFile (const String& modName, const ObjectVariantMapper& mapper, ModuleDataUpgraderType moduleUpgrader,
157 ModuleNameToFileNameMapperType moduleNameToReadFileNameMapper, ModuleNameToFileNameMapperType moduleNameToWriteFileNameMapper,
158 ModuleNameToFileVersionMapperType moduleNameToReadFileVersion, LoggerType logger, Variant::Reader reader,
159 Variant::Writer writer, const String& fileSuffix);
160
161 public:
162 /**
163 * Read the content of the associated file as a BLOB.
164 */
165 nonvirtual BLOB ReadRaw () const;
166
167 public:
168 /**
169 * Writes the given blob to the associated file, if it represents a change. This will silently
170 * avoid writing, if the blob is already the same as what is on disk.
171 */
172 nonvirtual void WriteRaw (const BLOB& blob);
173
174 public:
175 /**
176 * Just a parameter to Read() function.
177 */
178 enum class ReadFlags {
179 eNoWriteIfChanged,
180 eWriteIfChanged,
181 };
182
183 public:
184 /**
185 * Read () reads in the data from the associated options file, and returns it as a struct you've defined.
186 *
187 * The mapping to/from external format is defined by OptionsFile constructor parameters.
188 *
189 * The predefined (template specialization) of Read<VariantValue> doesn't use ObjectVariantMapper:
190 * it does the raw read (just using the Reader object).
191 *
192 * Note also that Read<VariantValue> does use any provided ModuleDataUpgrader, so that the data is upgraded
193 * before its seen by the object variant mapper.
194 *
195 * Read () will emit warnings, and maps to 'isMissing' or default value (depending on overload) if
196 * read data is corrupted. To avoid this behavior, use ReadRaw() directly.
197 */
198 template <typename T>
199 nonvirtual optional<T> Read ();
200 template <typename T>
201 nonvirtual T Read (const T& defaultObj, ReadFlags readFlags = ReadFlags::eWriteIfChanged);
202
203 public:
204 /**
205 * Note - predefined version Write<VariantValue> doesn't use ObjectVariantMapper.
206 *
207 * Write () serializes T, and then invokes WriteRaw ().
208 *
209 * \note WriteRaw () - and so Write () makes no changes to the external file if the contents being
210 * written serialize to the same value.
211 */
212 template <typename T>
213 nonvirtual void Write (const T& optionsObject);
214
215 private:
216 nonvirtual filesystem::path GetReadFilePath_ () const;
217 nonvirtual filesystem::path GetWriteFilePath_ () const;
218
219 private:
220 String fModuleName_;
221 ObjectVariantMapper fMapper_;
222 ModuleDataUpgraderType fModuleDataUpgrader_;
223 ModuleNameToFileNameMapperType fModuleNameToReadFileNameMapper_;
224 ModuleNameToFileNameMapperType fModuleNameToWriteFileNameMapper_;
225 ModuleNameToFileVersionMapperType fModuleNameToFileVersionMapper_;
226 LoggerType fLogger_;
227 Variant::Reader fReader_;
228 Variant::Writer fWriter_;
229 String fFileSuffix_;
230 };
231
232 /**
233 */
234 struct OptionsFile::LoggerMessage {
235 enum class Msg {
236 eSuccessfullyReadFile,
237 eFailedToWriteFile,
238 eFailedToReadFile,
239 eFailedToParseReadFile,
240 eFailedToParseReadFileBadFormat,
241 eFailedToCompareReadFile,
242 eWritingConfigFile_SoDefaultsEditable,
243 eWritingConfigFile_BecauseUpgraded,
244 eWritingConfigFile_BecauseSomethingChanged,
245 eFailedToWriteInUseValues,
246 };
247 Msg fMsg;
248 optional<filesystem::path> fFileName;
249 optional<String> fDetails;
250
251 LoggerMessage (Msg msg, const filesystem::path& fn, const optional<String>& details = nullopt);
252 nonvirtual String FormatMessage () const;
253 };
254
255 template <>
256 optional<VariantValue> OptionsFile::Read ();
257 template <>
258 void OptionsFile::Write (const VariantValue& optionsObject);
259
260}
261
262/*
263 ********************************************************************************
264 ***************************** Implementation Details ***************************
265 ********************************************************************************
266 */
267#include "OptionsFile.inl"
268
269#endif /*_Stroika_Foundation_DataExchange_OptionsFile_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void WriteRaw(const BLOB &blob)
static const Variant::Writer kDefaultWriter
function< optional< Common::Version >(const String &moduleName)> ModuleNameToFileVersionMapperType
nonvirtual void Write(const T &optionsObject)
static const ModuleDataUpgraderType kDefaultUpgrader
function< VariantValue(const optional< Common::Version > &version, const VariantValue &rawVariantValue)> ModuleDataUpgraderType
static const Variant::Reader kDefaultReader
abstract class specifying interface for readers that map a source like XML or JSON to a VariantValue ...
abstract class specifying interface for writers VariantValue objects to serialized formats like JSON,...
Definition Writer.h:37
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...