ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
resources.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of sub-namespace #alib::lang::resources of module \alib_basecamp of
4 * the \aliblong.
5 *
6 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
7 * Published under \ref mainpage_license "Boost Software License".
8 **************************************************************************************************/
9#ifndef HPP_ALIB_LANG_RESOURCES_RESOURCES
10#define HPP_ALIB_LANG_RESOURCES_RESOURCES 1
11
12#if !defined (HPP_ALIB_STRINGS_STRING)
14#endif
15
16#if !defined (HPP_ALIB_STRINGS_LOCALSTRING)
18#endif
19
20
21#if !defined(ALIB_RESOURCES_OMIT_DEFAULTS)
22# define ALIB_RESOURCES_OMIT_DEFAULTS 0
23#endif
24
25#if ALIB_DEBUG_RESOURCES && !defined (_GLIBCXX_VECTOR) && !defined(_VECTOR_)
26# include <vector>
27#endif
28
29
30
31namespace alib { namespace lang::resources {
32
33/** ************************************************************************************************
34 * This purely abstract class provides an interface to store and retrieve "resourced" string data
35 * which are organized in a two-level key hierarchy named <em>"resource category"</em>
36 * and <em>"resource name"</em>. The latter are of narrow string type.
37 *
38 * \see
39 * For detailed documentation on when and how this interface is used, please consult chapter
40 * \ref alib_basecamp_resources "3. Namespace alib::lang::resources" of the Programmer's Manual of
41 * module \alib_basecamp.
42 *
43 * \see
44 * Two built-in implementations of this pure abstract interface are provided with
45 * \alib{lang::resources;LocalResourcePool} and \alib{lang::resources;ConfigResourcePool}.
46 * Please consult their reference documentation for further details.
47 *
48 **************************************************************************************************/
50{
51 public:
52
53 /** Virtual destructor. */
54 virtual ~ResourcePool()
55 {}
56
57
58 /** ********************************************************************************************
59 * Used to store a resource string.
60 *
61 * In the context of \alibmods, which usually are the only areas where instances of this
62 * type are available (used), this method must only invoked during the process of
63 * \ref alib_manual_bootstrapping "bootstrapping" \alib (and corresponding custom modules).
64 *
65 * \attention
66 * The life-cycle of the given string's buffers, have to survive this resource instance.
67 * Usually the strings passed here are constant C++ string literals, residing an the data
68 * segment of an executable
69 *
70 * \note
71 * Usually, method #Bootstrap should be preferred, which asserts in debug-compilations,
72 * if a resource already existed. The use of this method is for special cases, for example
73 * to replace (patch) resources of dependent modules.
74 *
75 * @param category Category string of the resource to add.
76 * @param name Name string of the resource.
77 * @param data The resource data.
78 * @return \c true if the resource did exist and was replaced, \c false if it was an insertion.
79 **********************************************************************************************/
80 virtual
81 bool BootstrapAddOrReplace(const NString& category, const NString& name, const String& data)= 0;
82
83 /** ********************************************************************************************
84 * Simple inline method that invokes virtual method #BootstrapAddOrReplace.
85 * In debug-compilations, it is asserted that a resource with the given key did not exist
86 * already.
87 *
88 * The use of this method is preferred over a direct invocation of #BootstrapAddOrReplace.
89 *
90 * @param category Category string of the resource to add.
91 * @param name Name string of the resource.
92 * @param data The resource data.
93 **********************************************************************************************/
94 inline
95 void Bootstrap( const NString& category, const NString& name, const String& data )
96 {
97 #if ALIB_DEBUG
98 bool result=
99 #endif
100 BootstrapAddOrReplace(category, name, data);
101
102 ALIB_ASSERT_ERROR( result, "RESOURCES",
103 NString256( "Doubly defined resource \"" ) << name
104 << "\" in category: " << category )
105 }
106
107 /** ********************************************************************************************
108 * Same as #Bootstrap but accepts an array of name/value pairs to be filled into
109 * the given parameter \p{category}.
110 *
111 * \attention
112 * <b>The given list has to be finished with a final \c nullptr argument for the next
113 * name!</b>
114 *
115 * In the context of \alibmods, which usually are the only areas where instances of this
116 * type are available (used), this method must only invoked during the process of
117 * \ref alib_manual_bootstrapping "bootstrapping" \alib (and corresponding custom modules).
118 *
119 * \attention
120 * The life-cycle of the given string's buffers, have to survive this resource instance.
121 * Usually the strings passed here are constant C++ string literals, residing an the data
122 * segment of an executable
123
124 * \note
125 * The use of variadic C-style arguments <c>"..."</c> in general is \b not recommended
126 * to be used.
127 * We still do it here, because this method is usually used with implementations
128 * of \alib{lang;Camp::bootstrap} to load static default values.
129 * This approach saves a lot of otherwise needed single invocations (reduces code size) and
130 * allows a clean code for the init methods.<br>
131 * For technical reasons, parameter \p{category } is declared as type <c>const nchar*</c>.
132 *
133 *
134 * @param category The category of the resources given.
135 * @param ... A list of pairs of <b>const nchar*</b> and <b>const character*</b>
136 * keys and data, including a terminating \c nullptr value.
137 **********************************************************************************************/
138 virtual
139 void BootstrapBulk( const nchar* category, ... ) = 0;
140
141#if defined(ALIB_DOX)
142 /** ********************************************************************************************
143 * Returns a resource.
144 * On failure (resource not found), a \e nulled string is returned.
145 *
146 * \note
147 * Usually resource pools are associated with \alib{lang;Camp} objects and resources should be
148 * loaded using its "shortcut methods" \alib{lang::Camp;TryResource}
149 * and \alib{lang::Camp;GetResource}.
150 * If used directly, argument \p{dbgAssert} has to be enclosed in macro \ref ALIB_DBG
151 * (including the separting comma).
152 *
153 * @param category Category string of the resource.
154 * @param name Name string of the resource
155 * @param dbgAssert This parameter is available only in debug mode. If \c true, an assertion
156 * is raised if the resource was not found.
157 * @return The resource string, respectively a \e nulled string on failure.
158 **********************************************************************************************/
159 virtual
160 const String& Get( const NString& category, const NString& name, bool dbgAssert ) = 0;
161#else
162 virtual
163 const String& Get( const NString& category, const NString& name ALIB_DBG(,bool dbgAssert))= 0;
164#endif
165
166#if defined(ALIB_DOX)
167 /** ********************************************************************************************
168 * Convenience inlined method that accepts parameter name as \alib{characters;character}
169 * instead of \alib{characters;nchar} based string type. The rationale for this is that often,
170 * resource name keys are read from other resourced strings and need conversion if used.
171 * This avoids external conversion prior to invoking this method.
172 *
173 * This method is available only when \alib is compiled with type \alib{characters;character}
174 * not being equivalent to \alib{characters;nchar}.
175 *
176 * After string conversion simply returns result of virtual method
177 * #Get(const NString&, const NString&, bool).
178 *
179 * @param category Category string of the resource.
180 * @param name Name string of the resource
181 * @param dbgAssert This parameter is available only in debug mode. If \c true, an assertion
182 * is raised if the resource was not found.
183 * @return The resource string, respectively a \e nulled string on failure.
184 **********************************************************************************************/
185 const String& Get( const NString& category, const String& name, bool dbgAssert );
186#else
187 #if ALIB_CHARACTERS_WIDE
188 const String& Get( const NString& category, const String& name ALIB_DBG(,bool dbgAssert) )
189 {
190 NString128 nName( name );
191 return Get( category, nName ALIB_DBG(, dbgAssert ) );
192 }
193 #endif
194#endif
195
196 #if ALIB_DEBUG_RESOURCES
197 /** ****************************************************************************************
198 * Returns a vector of tuples for each resourced element. Each tuple contains:
199 * 0. The category name
200 * 1. The resource name
201 * 2. The resource value
202 * 3. The number of requests for the resource performed by a using data.
203 *
204 * While being useful to generaly inspect the resources, a high number of requests
205 * might indicate a performance penality for a using software. Such can usually be
206 * mitigated in a very simple fashion by "caching" a resource string in a local
207 * or global/static string variable.
208 *
209 * \par Availability
210 * Available only if compiler symbol \ref ALIB_DEBUG_RESOURCES is set.
211 *
212 * \attention
213 * This method is implemented only with the default pool instance of type
214 * \alib{lang::resources;LocalResourcePool} is used. Otherwise, an \alib warning is raised
215 * and an empty vector is returned.
216 *
217 * \see
218 * Methods #DbgGetCategories and #DbgDump.
219 *
220 * @return The externalized resource string.
221 ******************************************************************************************/
223 virtual
224 std::vector<std::tuple<NString, NString, String, integer>>
225 DbgGetList();
226
227 /** ****************************************************************************************
228 * Implements abstract method \alib{lang::resources;ResourcePool::DbgGetCategories}.
229 *
230 * \par Availability
231 * Available only if compiler symbol \ref ALIB_DEBUG_RESOURCES is set.
232 *
233 * \attention
234 * This method is implemented only with the default pool instance of type
235 * \alib{lang::resources;LocalResourcePool} is used. Otherwise, an \alib warning is raised and
236 * an empty vector is returned.
237 *
238 * \see
239 * Methods #DbgGetList and #DbgDump.
240 *
241 * @return The externalized resource string.
242 ******************************************************************************************/
244 virtual
245 std::vector<std::pair<NString, integer>>
247
248 #if ALIB_CAMP
249 /** ************************************************************************************
250 * Writes the list of resources obtainable with #DbgGetList to an \b %AString.
251 *
252 * \par Availability
253 * Available only if compiler symbol \ref ALIB_DEBUG_RESOURCES is set and furthermore
254 * if module \alib_basecamp is included in the \alibdist.
255 *
256 * \see
257 * Methods #DbgGetList and #DbgGetCategories.
258 *
259 * @param list The list of resources, obtained with #DbgGetList.
260 * @param catFilter Comma-separated list of names of categories to print.
261 * Defaults to nulled string, which includes all caegories.
262 * @param format The format of a line.
263 * Defaults to <b>"({3:}) {1}={2!TAB20!ESC<!Q}\\n"</b>.
264 * @return The dump of all resources.
265 **************************************************************************************/
267 static
268 AString DbgDump( std::vector<std::tuple<NString, NString, String, integer>>& list,
269 const NString& catFilter = nullptr,
270 const String& format = A_CHAR("({3:}) {1}={2!TAB20!ESC<!Q}\n") );
271 #endif //ALIB_CAMP
272 #endif
273}; // class ResourcePool
274
275/** ************************************************************************************************
276 * Simple TMP struct that associates resource information to given type \p{T} .
277 *
278 * Extends <c>std::false_type</c> by default to indicate that it is not specialized for a specific
279 * type. Specializations need to extend <c>std::true_type</c> instead.
280 *
281 * \see
282 * - Helper macros \ref ALIB_RESOURCED and ALIB_RESOURCED_IN_MODULE that specialize this struct.
283 * - Helper type \alib{lang::resources;ResourcedType}.
284 * - Manual chapter \ref alib_basecamp_resources_t_resourced "3.5. Indirect Resource Access" of the
285 * Programmer's Manual of this module.
286 *
287 * @tparam T The type to define resource information for.
288 **************************************************************************************************/
289template<typename T>
290struct T_Resourced : public std::false_type
291{
292 /**
293 * Returns a pointer to the resource pool associated with \p{T}.
294 * @return The resource pool of \p{T}.
295 */
296 static constexpr ResourcePool* Pool() { return nullptr; }
297
298 /**
299 * Returns a resource category associated with \p{T}.
300 * @return The resource category.
301 */
302 static constexpr NString Category() { return NullNString(); }
303
304 /**
305 * Returns a resource name associated with \p{T}.
306 * @return The resource category.
307 */
308 static constexpr NString Name() { return NullNString(); }
309};
310
311/** ************************************************************************************************
312 * Static helper struct used to access resources of types that dispose about a specialization of
313 * type-traits struct \alib{lang::resources;T_Resourced}.
314 *
315 * @see
316 * - Type-traits struct \alib{lang::resources;T_Resourced}
317 * - Manual chapter \ref alib_basecamp_resources_t_resourced_resourced of the Programmer's Manual of this
318 * module.
319 *
320 * @tparam T A type equipped with resource information by a specialization of
321 * \alib{lang::resources;T_Resourced}.
322 **************************************************************************************************/
323template<typename T>
325{
326 #if defined(ALIB_DOX)
327 /**
328 * Static methodthat receives a resource string for a type which has a specialization
329 * of \alib{lang::resources;T_Resourced} defined.
330 *
331 * @tparam TEnableIf Not to be specified. Used by the compiler to select the availability
332 * of this method.
333 * @return The externalized resource string.
334 */
335 template<typename TEnableIf= T>
336 static inline
337 const String& Get();
338 #else
339 template<typename TEnableIf= T>
340 static
342 Get()
343 {
345 T_Resourced<T>::Name () ALIB_DBG(, true) );
346 }
347 #endif
348
349
350 #if defined(ALIB_DOX)
351 /**
352 * Variant of parameterless version \alib{lang::resources::ResourcedType;Get();Get} that ignores the
353 * resource name given for a type with \alib{lang::resources;T_Resourced}, but instead uses the given
354 * name.
355 *
356 * @tparam TEnableIf Not to be specified. Used by the compiler to select the availability
357 * of this method.
358 * @param name The resource name to use, given as string of narrow character width.
359 * @param dbgAssert This parameter is available only in debug mode. If \c true, an assertion
360 * is raised if the resource was not found.
361 * @return The externalized resource string.
362 */
363 template<typename TEnableIf= T>
364 static inline
365 const String& Get( const NString& name, bool dbgAssert );
366 #else
367 template<typename TEnableIf= T>
368 static
370 Get( const NString& name ALIB_DBG(, bool dbgAssert) )
371 {
372 return T_Resourced<T>::Pool()->Get( T_Resourced<T>::Category(), name ALIB_DBG(, dbgAssert) );
373 }
374 #endif
375
376
377 #if ALIB_CHARACTERS_WIDE && defined(ALIB_DOX)
378 /**
379 * Variant of method \alib{lang::resources::ResourcedType;Get(const NString&; bool)} that
380 * accepts a character string of standard character width instead of a narrow type.
381 *
382 * \par Availability
383 * Available only if \ref ALIB_CHARACTERS_WIDE evaluates to \c true.
384 *
385 * @tparam TEnableIf Not to be specified. Used by the compiler to select the availability
386 * of this method.
387 * @param name The resource name to use, given as string of standard character width.
388 * @param dbgAssert This parameter is available only in debug mode. If \c true, an assertion
389 * is raised if the resource was not found.
390 * @return The externalized resource string.
391 */
392 template<typename TEnableIf= T>
393 static inline
394 const String& Get( const String& name, bool dbgAssert );
395 #endif
396 #if ALIB_CHARACTERS_WIDE && !defined(ALIB_DOX)
397 template<typename TEnableIf= T>
398 static
400 Get( const String& resourceName ALIB_DBG(, bool dbgAssert) )
401 {
403 resourceName ALIB_DBG(, dbgAssert) );
404 }
405 #endif
406
407 /**
408 * Together with sibling method #TypeNamePostfix, this method may be used to receive the
409 * first portion of a type's human readable name.
410 *
411 * The method tries to standardize resourcing names of C++ types along with the resource string
412 * that is defined with type-traits struct \alib{lang::resources;T_Resourced} for a type.
413 *
414 * The prefix is tried to be retrieved by extending the resource name returned by method
415 * \alib{lang::resources;T_Resourced::Name} by character <c>'<'</c>.
416 *
417 * \alib uses this method internally, for example with specializations
418 * \alib{strings::APPENDABLES;T_Append<TEnum,TChar>;T_Append<TEnum,TChar>}
419 * \alib{strings::APPENDABLES;T_Append<TEnumBitwise,TChar>;T_Append<TEnumBitwise,TChar>}
420 * used to write element names of enum types.
421 *
422 * If either \alib{lang::resources;T_Resourced} is \e not specialized for \p{TEnum}, or a resource
423 * named \"\p{name}<b>></b>\" is not found, an empty string is returned.<br>
424 *
425 * @return The prefix string.
426 */
427 static
429 {
430 if constexpr( T_Resourced<T>::value )
431 {
432 NString256 resourceName( T_Resourced<T>::Name() );
433 resourceName << "<";
434 auto& pf= T_Resourced<T>::Pool()->Get( T_Resourced<T>::Category(), resourceName
435 ALIB_DBG(, false) );
436 if( pf.IsNotNull() )
437 return pf;
438 }
439
440 return EMPTY_STRING;
441 }
442
443 /**
444 * Same as #TypeNamePrefix but for the postfix string of a types name. Consequently, extends the
445 * resource string's name searched by character character <c>'>'</c>.
446 *
447 * @return The postfix string.
448 */
449 static
451 {
453 if constexpr( T_Resourced<T>::value )
454 {
455 NString256 resourceName( T_Resourced<T>::Name() );
456 resourceName << ">";
457 auto& pf= T_Resourced<T>::Pool()->Get( T_Resourced<T>::Category(), resourceName
458 ALIB_DBG(, false) );
459 if( pf.IsNotNull() )
460 return pf;
461 }
463
464 return EMPTY_STRING;
465 }
466
467}; // struct ResourcedType
468
469/**
470 * Utility type that may be used to store resourcing information.
471 *
472 * Besides constructor #ResourceInfo(ResourcePool*, NString, NString) and corresponding #Set method,
473 * templated alternatives exist, which are applicable if \alib{lang::resources;T_Resourced}
474 * is specialized for the template type.
475 */
477{
478 /** The resource pool. */
480
481 /** The resource category within #Pool. */
483
484 /** The resource category within #Pool. */
486
487 /** Defaulted constructor leaving the fields uninitialized. */
488 ResourceInfo() noexcept = default;
489
490 /**
491 * Constructor setting the fields of this object as given.
492 *
493 * @param pool The resource pool.
494 * @param category The resource category.
495 * @param name The resource name.
496 */
497 template<typename T>
498 ResourceInfo( resources::ResourcePool* pool, NString category, NString name )
499 : Pool (pool )
500 , Category(category)
501 , Name (name )
502 {}
503
504 /**
505 * Templated constructor which sets the fields of this object according to the values provided
506 * with a specialization of \alib{lang::resources;T_Resourced} for type \p{T}.
507 *
508 * @tparam T Type that disposes about a specialization of \b T_Resourced. Deduced by the
509 * compiler
510 * @param sample A sample instance of type \p{T}. Exclusively used to have the compiler
511 * deduce type \p{T} (otherwise ignored).
512 */
513 template<typename T>
514 ResourceInfo(const T& sample)
515 {
516 Set( sample );
517 }
518
519 /**
520 * Sets the fields of this object as given.
521 *
522 * @param pool The resource pool.
523 * @param category The resource category.
524 * @param name The resource name.
525 */
526 void Set( resources::ResourcePool* pool, NString category, NString name )
527 {
528 Pool = pool;
529 Category = category;
530 Name = name;
531 }
532
533 #if defined(ALIB_DOX)
534 /**
535 * Sets the fields of this object according to the values provided with a specialization of
536 * \alib{lang::resources;T_Resourced} for type \p{T}.
537 *
538 * @tparam T Type that disposes about a specialization of \b T_Resourced. Deduced by the
539 * compiler
540 * @param sample A sample instance of type \p{T}. Exclusively used to have the compiler
541 * deduce type \p{T} (otherwise ignored).
542 */
543 template<typename T>
544 void Set(const T& sample);
545 #else
546 template<typename T>
548 Set(const T& )
549 {
553 }
554 #endif
555
556 /**
557 * Receives the resource string according to this info object.
558 *
559 * @return The externalized resource string.
560 */
561 inline
562 const String& Get()
563 {
564 return Pool->Get( Category, Name ALIB_DBG(, true) );
565 }
566
567
568 #if defined(ALIB_DOX)
569 /**
570 * Variant of parameterless version #Get() that ignores field #Name and instead uses given
571 * argument \p{name} .
572 *
573 * @param name The resource name to use, given as string of narrow character width.
574 * @param dbgAssert This parameter is available only in debug mode. If \c true, an assertion
575 * is raised if the resource was not found.
576 * @return The externalized resource string.
577 */
578 inline
579 const String& Get( const NString& name, bool dbgAssert );
580 #else
581 const String& Get( const NString& name ALIB_DBG(, bool dbgAssert) )
582 {
583 return Pool->Get( Category, name ALIB_DBG(, dbgAssert) );
584 }
585 #endif
586
587
588 #if ALIB_CHARACTERS_WIDE && defined(ALIB_DOX)
589 /**
590 * Variant of mehtod Get(const NString&, bool) that accepts a character string of standard
591 * character width instead of a narrow type.
592 *
593 * \par Availability
594 * Available only if \ref ALIB_CHARACTERS_WIDE evaluates to \c true.
595 *
596 * @param name The resource name to use, given as string of standard character width.
597 * @param dbgAssert This parameter is available only in debug mode. If \c true, an assertion
598 * is raised if the resource was not found.
599 * @return The externalized resource string.
600 */
601 inline
602 const String& Get( const String& name, bool dbgAssert );
603 #endif
604 #if ALIB_CHARACTERS_WIDE && !defined(ALIB_DOX)
605 const String& Get( const String& name ALIB_DBG(, bool dbgAssert) )
606 {
607 return Pool->Get( Category, name ALIB_DBG(, dbgAssert) );
608 }
609 #endif
610}; // ResourceInfo
611
612
613} // namespace alib[::lang::resources]
614
615/// Type alias in namespace \b alib.
617
618/// Type alias in namespace \b alib.
619template<typename T>
621
622/// Type alias in namespace \b alib.
623template<typename T>
625
626/// Type alias in namespace \b alib.
628
629} // namespace [alib]
630
631// #################################################################################################
632// T_Resourced Macro
633// #################################################################################################
634#define ALIB_RESOURCED( T, ResPool, ResCategory, ResName ) \
635namespace alib::lang::resources { \
636template<> struct T_Resourced<T> : public std::true_type \
637{ \
638 static ResourcePool* Pool() { return ResPool; } \
639 static constexpr NString Category() { return ResCategory; } \
640 static constexpr NString Name() { return ResName; } \
641};}
642
643#if ALIB_CAMP
644# define ALIB_RESOURCED_IN_MODULE( T, Camp, ResName ) \
645 ALIB_RESOURCED( T, &Camp.GetResourcePool(), Camp.ResourceCategory, ResName )
646#endif
647
648
649#endif // HPP_ALIB_LANG_RESOURCES_RESOURCES
const String & Get(const NString &category, const String &name, bool dbgAssert)
void Bootstrap(const NString &category, const NString &name, const String &data)
Definition resources.hpp:95
virtual ALIB_API std::vector< std::tuple< NString, NString, String, integer > > DbgGetList()
virtual void BootstrapBulk(const nchar *category,...)=0
static ALIB_API AString DbgDump(std::vector< std::tuple< NString, NString, String, integer > > &list, const NString &catFilter=nullptr, const String &format=A_CHAR("({3:}) {1}={2!TAB20!ESC<!Q}\n"))
virtual const String & Get(const NString &category, const NString &name, bool dbgAssert)=0
virtual ALIB_API std::vector< std::pair< NString, integer > > DbgGetCategories()
virtual bool BootstrapAddOrReplace(const NString &category, const NString &name, const String &data)=0
#define A_CHAR(STR)
#define ATMP_VOID_IF(Cond)
Definition tmp.hpp:52
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_API
Definition alib.hpp:538
#define ALIB_WARNINGS_ALLOW_NULL_POINTER_PASSING
Definition alib.hpp:641
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_DBG(...)
Definition alib.hpp:457
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:53
@ Get
Denotes to search data.
Definition alib.cpp:57
ALIB_API CString EMPTY_STRING
A global instance of a nulled zero-terminated string of standard character size.
Definition string.cpp:476
NLocalString< 256 > NString256
Type alias name for TLocalString<nchar,256> .
constexpr NString NullNString()
Definition string.hpp:2510
characters::nchar nchar
Type alias in namespace alib.
const String & Get(const NString &name, bool dbgAssert)
resources::ResourcePool * Pool
void Set(resources::ResourcePool *pool, NString category, NString name)
static const String & Get(const NString &name, bool dbgAssert)
static const String & TypeNamePrefix()
static const String & TypeNamePostfix()
static constexpr ResourcePool * Pool()
static constexpr NString Category()
static constexpr NString Name()