XRTraits C++ OpenXR Utilities
Type Safety, Dynamic Typing, and OpenXR Structures

OpenXR, based largely in the practice developed in Vulkan, has a system where most structure types contain two "meta" members to provide polymorphism and extensibity.

The next member is either nullptr or points to some other structure type that begins with type and next members. Thus, these next pointers form a singly-linked list of structures that can be queried for their dynamic type.

Types like this are sometimes referred to in this library and its documentation as "XR tagged types" or "XR tagged structs" since they contain a member tagging them with their dynamic type, as in a discriminated/tagged union type. Most but not all XR tagged types are associated with a distinct value of the XrStructureType enum. This association is made in the XML registry for OpenXR - look at the "values" attribute of the member tag wrapping type for any such struct to see its corresponding enum value ("type tag").

For example, XrInstanceCreateInfo is associated with XR_TYPE_INSTANCE_CREATE_INFO as this is found in its definition in the registry:

<member values="XR_TYPE_INSTANCE_CREATE_INFO"><type>XrStructureType</type> <name>type</name></member>

Type traits

This library originated with some C++11/14 "type traits" that are generated from the XML registry specification of OpenXR to support type-safe usage of these next chains - see xrtraits::traits.

It is important to note that this library can wrap all "type-unsafe" operations with OpenXR structs. With these utilities, it is possible to completely avoid using reinterpret_cast() directly: use the higher-level constructs instead. The type-safety checks of clang-tidy have been left enabled since these generic high-level constructs locally suppress those warnings in their implementation.

OpenXR Structs as Parameters - DynamicVerified

Because of the dynamic typing possibility of OpenXR structs, it is important to distinguish "pointers to structs we got from somebody else" from "references to structs with verified dynamic type". This library includes the xrtraits::DynamicVerified<T> type template which wraps a pointer to an OpenXR tagged struct type, acting just like a pointer but asserting that the dynamic type has been checked to match with the static OpenXR struct type T. For the sake of simplicity, we will use XrInstanceCreateInfo as the example type here, but all XR tagged types with known tag can be substituted in place of XrInstanceCreateInfo. The transition from a passed-in XrInstanceCreateInfo * (which might be null, or might have the wrong dynamic type), to code that can safely assume that they have a pointer/reference to an OpenXR struct with a known type, should only take place once for each parameter, and ideally should be distinguished in a compiler-checked way. The Dynamic Typing verification tools provide both verification and type-checked distinction. Calling xrtraits::verifyDynamicType() performs null pointer checking, verification of dynamic type, and wrapping the pointer in a DynamicVerified type to indicate to code elsewhere that they can rely on the static type. In most cases, code outside of externally-exposed APIs should only deal with types already wrapped in DynamicVerified or a related safe type.

xrtraits::DynamicVerifiedOrNull is a related type that is weaker than DynamicVerified. It only asserts that if the contained pointer is not null, then the dynamic type matches. However, since it can be used to store/pass a null pointer, it can be used with optional parameters.

If you need to create an OpenXR tagged type on the stack, you may use xrtraits::Initialized<T> instead of creating it directly. This automatically zeros the memory and initializes the type member appropriately. If you pass another such type, it will set the next pointer for you as well, to create chained structures. (Any additional arguments passed to the constructor are forwarded to the struct initializer itself after type and next.) It also (weakly) conceals the type and next members from your code, to make it harder to accidentally modify these values. If you're in search of a collection of OpenXR structs, look into xrtraits::make_zeroed_vector(). However, if you need a collection of empty structs, you might be trying to use the two-call idiom, in which case see functionality in TwoCall.h to simplify it further.

Copyright and License for this DynamicTypes.md page

For this page only:

Copyright 2018-2019 Collabora, Ltd.

SPDX-License-Identifier: BSL-1.0