Initialize interface structures so they can be extended in the future

We guarantee that we will only add to the end of these interfaces, and any new fields will be optional.
This commit is contained in:
Sam Lantinga
2024-09-05 16:28:48 -07:00
parent 434193d153
commit 702ed83f72
13 changed files with 130 additions and 22 deletions

View File

@@ -83,10 +83,17 @@ typedef enum SDL_IOWhence
* already offers several common types of I/O streams, via functions like
* SDL_IOFromFile() and SDL_IOFromMem().
*
* This structure should be initialized using SDL_INIT_INTERFACE()
*
* \since This struct is available since SDL 3.0.0.
*
* \sa SDL_INIT_INTERFACE
*/
typedef struct SDL_IOStreamInterface
{
/* The version of this interface */
Uint32 version;
/**
* Return the number of bytes in this SDL_IOStream
*
@@ -138,6 +145,15 @@ typedef struct SDL_IOStreamInterface
} SDL_IOStreamInterface;
/* Check the size of SDL_IOStreamInterface
*
* If this assert fails, either the compiler is padding to an unexpected size,
* or the interface has been updated and this should be updated to match and
* the code using this interface should be updated to handle the old version.
*/
SDL_COMPILE_TIME_ASSERT(SDL_IOStreamInterface_SIZE,
(sizeof(void *) == 4 && sizeof(SDL_IOStreamInterface) == 24) ||
(sizeof(void *) == 8 && sizeof(SDL_IOStreamInterface) == 48));
/**
* The read/write operation structure.
@@ -347,20 +363,18 @@ extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_IOFromDynamicMem(void);
* read/write a common data source, you should use the built-in
* implementations in SDL, like SDL_IOFromFile() or SDL_IOFromMem(), etc.
*
* You must free the returned pointer with SDL_CloseIO().
*
* This function makes a copy of `iface` and the caller does not need to keep
* this data around after this call.
* it around after this call.
*
* \param iface the function pointers that implement this SDL_IOStream.
* \param userdata the app-controlled pointer that is passed to iface's
* functions when called.
* \param iface the interface that implements this SDL_IOStream, initialized using SDL_INIT_INTERFACE().
* \param userdata the pointer that will be passed to the interface functions.
* \returns a pointer to the allocated memory on success or NULL on failure;
* call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_CloseIO
* \sa SDL_INIT_INTERFACE
* \sa SDL_IOFromConstMem
* \sa SDL_IOFromFile
* \sa SDL_IOFromMem

View File

@@ -414,16 +414,18 @@ typedef struct SDL_VirtualJoystickSensorDesc
/**
* The structure that describes a virtual joystick.
*
* All elements of this structure are optional and can be left 0.
* This structure should be initialized using SDL_INIT_INTERFACE(). All elements of this structure are optional.
*
* \since This struct is available since SDL 3.0.0.
*
* \sa SDL_AttachVirtualJoystick
* \sa SDL_INIT_INTERFACE
* \sa SDL_VirtualJoystickSensorDesc
* \sa SDL_VirtualJoystickTouchpadDesc
*/
typedef struct SDL_VirtualJoystickDesc
{
Uint32 version; /**< the version of this interface */
Uint16 type; /**< `SDL_JoystickType` */
Uint16 padding; /**< unused */
Uint16 vendor_id; /**< the USB vendor ID of this joystick */
@@ -454,10 +456,20 @@ typedef struct SDL_VirtualJoystickDesc
void (SDLCALL *Cleanup)(void *userdata); /**< Cleans up the userdata when the joystick is detached */
} SDL_VirtualJoystickDesc;
/* Check the size of SDL_VirtualJoystickDesc
*
* If this assert fails, either the compiler is padding to an unexpected size,
* or the interface has been updated and this should be updated to match and
* the code using this interface should be updated to handle the old version.
*/
SDL_COMPILE_TIME_ASSERT(SDL_VirtualJoystickDesc_SIZE,
(sizeof(void *) == 4 && sizeof(SDL_VirtualJoystickDesc) == 84) ||
(sizeof(void *) == 8 && sizeof(SDL_VirtualJoystickDesc) == 136));
/**
* Attach a new virtual joystick.
*
* \param desc joystick description.
* \param desc joystick description, initialized using SDL_INIT_INTERFACE().
* \returns the joystick instance ID, or 0 on failure; call SDL_GetError() for
* more information.
*

View File

@@ -529,6 +529,49 @@ SDL_COMPILE_TIME_ASSERT(enum, sizeof(SDL_DUMMY_ENUM) == sizeof(int));
extern "C" {
#endif
/**
* A macro to initialize an SDL interface.
*
* This macro will initialize an SDL interface structure and should be called before you fill out the fields with your implementation.
*
* You can use it like this:
*
* ```c
* SDL_IOStreamInterface iface;
*
* SDL_INIT_INTERFACE(&iface);
*
* // Fill in the interface function pointers with your implementation
* iface.seek = ...
*
* stream = SDL_OpenIO(&iface, NULL);
* ```
*
* If you are using designated initializers, you can use the size of the interface as the version, e.g.
*
* ```c
* SDL_IOStreamInterface iface = {
* .version = sizeof(iface),
* .seek = ...
* };
* stream = SDL_OpenIO(&iface, NULL);
* ```
*
* \threadsafety It is safe to call this macro from any thread.
*
* \since This macro is available since SDL 3.0.0.
*
* \sa SDL_IOStreamInterface
* \sa SDL_StorageInterface
* \sa SDL_VirtualJoystickDesc
*/
#define SDL_INIT_INTERFACE(iface) \
do { \
SDL_zerop(iface); \
(iface)->version = sizeof(*(iface)); \
} while (0)
#ifndef SDL_DISABLE_ALLOCA
#define SDL_stack_alloc(type, count) (type*)alloca(sizeof(type)*(count))
#define SDL_stack_free(data)

View File

@@ -52,10 +52,17 @@ extern "C" {
* It is not usually necessary to do this; SDL provides standard
* implementations for many things you might expect to do with an SDL_Storage.
*
* This structure should be initialized using SDL_INIT_INTERFACE()
*
* \since This struct is available since SDL 3.0.0.
*
* \sa SDL_INIT_INTERFACE
*/
typedef struct SDL_StorageInterface
{
/* The version of this interface */
Uint32 version;
/* Called when the storage is closed */
SDL_bool (SDLCALL *close)(void *userdata);
@@ -90,6 +97,15 @@ typedef struct SDL_StorageInterface
Uint64 (SDLCALL *space_remaining)(void *userdata);
} SDL_StorageInterface;
/* Check the size of SDL_StorageInterface
*
* If this assert fails, either the compiler is padding to an unexpected size,
* or the interface has been updated and this should be updated to match and
* the code using this interface should be updated to handle the old version.
*/
SDL_COMPILE_TIME_ASSERT(SDL_StorageInterface_SIZE,
(sizeof(void *) == 4 && sizeof(SDL_StorageInterface) == 48) ||
(sizeof(void *) == 8 && sizeof(SDL_StorageInterface) == 96));
/**
* An abstract interface for filesystem access.
*
@@ -176,8 +192,11 @@ extern SDL_DECLSPEC SDL_Storage * SDLCALL SDL_OpenFileStorage(const char *path);
* should use the built-in implementations in SDL, like SDL_OpenTitleStorage()
* or SDL_OpenUserStorage().
*
* \param iface the function table to be used by this container.
* \param userdata the pointer that will be passed to the store interface.
* This function makes a copy of `iface` and the caller does not need to keep
* it around after this call.
*
* \param iface the interface that implements this storage, initialized using SDL_INIT_INTERFACE().
* \param userdata the pointer that will be passed to the interface functions.
* \returns a storage container on success or NULL on failure; call
* SDL_GetError() for more information.
*
@@ -186,6 +205,7 @@ extern SDL_DECLSPEC SDL_Storage * SDLCALL SDL_OpenFileStorage(const char *path);
* \sa SDL_CloseStorage
* \sa SDL_GetStorageFileSize
* \sa SDL_GetStorageSpaceRemaining
* \sa SDL_INIT_INTERFACE
* \sa SDL_ReadStorageFile
* \sa SDL_StorageReady
* \sa SDL_WriteStorageFile