Skip to main content

sdl3_sys/generated/
asyncio.rs

1//! SDL offers a way to perform I/O asynchronously. This allows an app to read
2//! or write files without waiting for data to actually transfer; the functions
3//! that request I/O never block while the request is fulfilled.
4//!
5//! Instead, the data moves in the background and the app can check for results
6//! at their leisure.
7//!
8//! This is more complicated than just reading and writing files in a
9//! synchronous way, but it can allow for more efficiency, and never having
10//! framerate drops as the hard drive catches up, etc.
11//!
12//! The general usage pattern for async I/O is:
13//!
14//! - Create one or more [`SDL_AsyncIOQueue`] objects.
15//! - Open files with [`SDL_AsyncIOFromFile`].
16//! - Start I/O tasks to the files with [`SDL_ReadAsyncIO`] or [`SDL_WriteAsyncIO`],
17//!   putting those tasks into one of the queues.
18//! - Later on, use [`SDL_GetAsyncIOResult`] on a queue to see if any task is
19//!   finished without blocking. Tasks might finish in any order with success
20//!   or failure.
21//! - When all your tasks are done, close the file with [`SDL_CloseAsyncIO`]. This
22//!   also generates a task, since it might flush data to disk!
23//!
24//! This all works, without blocking, in a single thread, but one can also wait
25//! on a queue in a background thread, sleeping until new results have arrived:
26//!
27//! - Call [`SDL_WaitAsyncIOResult`] from one or more threads to efficiently block
28//!   until new tasks complete.
29//! - When shutting down, call [`SDL_SignalAsyncIOQueue`] to unblock any sleeping
30//!   threads despite there being no new tasks completed.
31//!
32//! And, of course, to match the synchronous [`SDL_LoadFile`], we offer
33//! [`SDL_LoadFileAsync`] as a convenience function. This will handle allocating a
34//! buffer, slurping in the file data, and null-terminating it; you still check
35//! for results later.
36//!
37//! Behind the scenes, SDL will use newer, efficient APIs on platforms that
38//! support them: Linux's io_uring and Windows 11's IoRing, for example. If
39//! those technologies aren't available, SDL will offload the work to a thread
40//! pool that will manage otherwise-synchronous loads without blocking the app.
41//!
42//! ## Best Practices
43//!
44//! Simple non-blocking I/O--for an app that just wants to pick up data
45//! whenever it's ready without losing framerate waiting on disks to spin--can
46//! use whatever pattern works well for the program. In this case, simply call
47//! [`SDL_ReadAsyncIO`], or maybe [`SDL_LoadFileAsync`], as needed. Once a frame, call
48//! [`SDL_GetAsyncIOResult`] to check for any completed tasks and deal with the
49//! data as it arrives.
50//!
51//! If two separate pieces of the same program need their own I/O, it is legal
52//! for each to create their own queue. This will prevent either piece from
53//! accidentally consuming the other's completed tasks. Each queue does require
54//! some amount of resources, but it is not an overwhelming cost. Do not make a
55//! queue for each task, however. It is better to put many tasks into a single
56//! queue. They will be reported in order of completion, not in the order they
57//! were submitted, so it doesn't generally matter what order tasks are
58//! started.
59//!
60//! One async I/O queue can be shared by multiple threads, or one thread can
61//! have more than one queue, but the most efficient way--if ruthless
62//! efficiency is the goal--is to have one queue per thread, with multiple
63//! threads working in parallel, and attempt to keep each queue loaded with
64//! tasks that are both started by and consumed by the same thread. On modern
65//! platforms that can use newer interfaces, this can keep data flowing as
66//! efficiently as possible all the way from storage hardware to the app, with
67//! no contention between threads for access to the same queue.
68//!
69//! Written data is not guaranteed to make it to physical media by the time a
70//! closing task is completed, unless [`SDL_CloseAsyncIO`] is called with its
71//! `flush` parameter set to true, which is to say that a successful result
72//! here can still result in lost data during an unfortunately-timed power
73//! outage if not flushed. However, flushing will take longer and may be
74//! unnecessary, depending on the app's needs.
75
76use super::stdinc::*;
77
78/// Types of asynchronous I/O tasks.
79///
80/// ## Availability
81/// This enum is available since SDL 3.2.0.
82///
83/// ## Known values (`sdl3-sys`)
84/// | Associated constant | Global constant | Description |
85/// | ------------------- | --------------- | ----------- |
86/// | [`READ`](SDL_AsyncIOTaskType::READ) | [`SDL_ASYNCIO_TASK_READ`] | A read operation. |
87/// | [`WRITE`](SDL_AsyncIOTaskType::WRITE) | [`SDL_ASYNCIO_TASK_WRITE`] | A write operation. |
88/// | [`CLOSE`](SDL_AsyncIOTaskType::CLOSE) | [`SDL_ASYNCIO_TASK_CLOSE`] | A close operation. |
89#[repr(transparent)]
90#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
91pub struct SDL_AsyncIOTaskType(pub ::core::ffi::c_int);
92
93impl ::core::cmp::PartialEq<::core::ffi::c_int> for SDL_AsyncIOTaskType {
94    #[inline(always)]
95    fn eq(&self, other: &::core::ffi::c_int) -> bool {
96        &self.0 == other
97    }
98}
99
100impl ::core::cmp::PartialEq<SDL_AsyncIOTaskType> for ::core::ffi::c_int {
101    #[inline(always)]
102    fn eq(&self, other: &SDL_AsyncIOTaskType) -> bool {
103        self == &other.0
104    }
105}
106
107impl From<SDL_AsyncIOTaskType> for ::core::ffi::c_int {
108    #[inline(always)]
109    fn from(value: SDL_AsyncIOTaskType) -> Self {
110        value.0
111    }
112}
113
114#[cfg(feature = "debug-impls")]
115impl ::core::fmt::Debug for SDL_AsyncIOTaskType {
116    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
117        #[allow(unreachable_patterns)]
118        f.write_str(match *self {
119            Self::READ => "SDL_ASYNCIO_TASK_READ",
120            Self::WRITE => "SDL_ASYNCIO_TASK_WRITE",
121            Self::CLOSE => "SDL_ASYNCIO_TASK_CLOSE",
122
123            _ => return write!(f, "SDL_AsyncIOTaskType({})", self.0),
124        })
125    }
126}
127
128impl SDL_AsyncIOTaskType {
129    /// A read operation.
130    pub const READ: Self = Self((0 as ::core::ffi::c_int));
131    /// A write operation.
132    pub const WRITE: Self = Self((1 as ::core::ffi::c_int));
133    /// A close operation.
134    pub const CLOSE: Self = Self((2 as ::core::ffi::c_int));
135}
136
137/// A read operation.
138pub const SDL_ASYNCIO_TASK_READ: SDL_AsyncIOTaskType = SDL_AsyncIOTaskType::READ;
139/// A write operation.
140pub const SDL_ASYNCIO_TASK_WRITE: SDL_AsyncIOTaskType = SDL_AsyncIOTaskType::WRITE;
141/// A close operation.
142pub const SDL_ASYNCIO_TASK_CLOSE: SDL_AsyncIOTaskType = SDL_AsyncIOTaskType::CLOSE;
143
144impl SDL_AsyncIOTaskType {
145    /// Initialize a `SDL_AsyncIOTaskType` from a raw value.
146    #[inline(always)]
147    pub const fn new(value: ::core::ffi::c_int) -> Self {
148        Self(value)
149    }
150}
151
152impl SDL_AsyncIOTaskType {
153    /// Get a copy of the inner raw value.
154    #[inline(always)]
155    pub const fn value(&self) -> ::core::ffi::c_int {
156        self.0
157    }
158}
159
160#[cfg(feature = "metadata")]
161impl sdl3_sys::metadata::GroupMetadata for SDL_AsyncIOTaskType {
162    const GROUP_METADATA: &'static sdl3_sys::metadata::Group =
163        &crate::metadata::asyncio::METADATA_SDL_AsyncIOTaskType;
164}
165
166/// Possible outcomes of an asynchronous I/O task.
167///
168/// ## Availability
169/// This enum is available since SDL 3.2.0.
170///
171/// ## Known values (`sdl3-sys`)
172/// | Associated constant | Global constant | Description |
173/// | ------------------- | --------------- | ----------- |
174/// | [`COMPLETE`](SDL_AsyncIOResult::COMPLETE) | [`SDL_ASYNCIO_COMPLETE`] | request was completed without error |
175/// | [`FAILURE`](SDL_AsyncIOResult::FAILURE) | [`SDL_ASYNCIO_FAILURE`] | request failed for some reason; check [`SDL_GetError()`]! |
176/// | [`CANCELED`](SDL_AsyncIOResult::CANCELED) | [`SDL_ASYNCIO_CANCELED`] | request was canceled before completing. |
177#[repr(transparent)]
178#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
179pub struct SDL_AsyncIOResult(pub ::core::ffi::c_int);
180
181impl ::core::cmp::PartialEq<::core::ffi::c_int> for SDL_AsyncIOResult {
182    #[inline(always)]
183    fn eq(&self, other: &::core::ffi::c_int) -> bool {
184        &self.0 == other
185    }
186}
187
188impl ::core::cmp::PartialEq<SDL_AsyncIOResult> for ::core::ffi::c_int {
189    #[inline(always)]
190    fn eq(&self, other: &SDL_AsyncIOResult) -> bool {
191        self == &other.0
192    }
193}
194
195impl From<SDL_AsyncIOResult> for ::core::ffi::c_int {
196    #[inline(always)]
197    fn from(value: SDL_AsyncIOResult) -> Self {
198        value.0
199    }
200}
201
202#[cfg(feature = "debug-impls")]
203impl ::core::fmt::Debug for SDL_AsyncIOResult {
204    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
205        #[allow(unreachable_patterns)]
206        f.write_str(match *self {
207            Self::COMPLETE => "SDL_ASYNCIO_COMPLETE",
208            Self::FAILURE => "SDL_ASYNCIO_FAILURE",
209            Self::CANCELED => "SDL_ASYNCIO_CANCELED",
210
211            _ => return write!(f, "SDL_AsyncIOResult({})", self.0),
212        })
213    }
214}
215
216impl SDL_AsyncIOResult {
217    /// request was completed without error
218    pub const COMPLETE: Self = Self((0 as ::core::ffi::c_int));
219    /// request failed for some reason; check [`SDL_GetError()`]!
220    pub const FAILURE: Self = Self((1 as ::core::ffi::c_int));
221    /// request was canceled before completing.
222    pub const CANCELED: Self = Self((2 as ::core::ffi::c_int));
223}
224
225/// request was completed without error
226pub const SDL_ASYNCIO_COMPLETE: SDL_AsyncIOResult = SDL_AsyncIOResult::COMPLETE;
227/// request failed for some reason; check [`SDL_GetError()`]!
228pub const SDL_ASYNCIO_FAILURE: SDL_AsyncIOResult = SDL_AsyncIOResult::FAILURE;
229/// request was canceled before completing.
230pub const SDL_ASYNCIO_CANCELED: SDL_AsyncIOResult = SDL_AsyncIOResult::CANCELED;
231
232impl SDL_AsyncIOResult {
233    /// Initialize a `SDL_AsyncIOResult` from a raw value.
234    #[inline(always)]
235    pub const fn new(value: ::core::ffi::c_int) -> Self {
236        Self(value)
237    }
238}
239
240impl SDL_AsyncIOResult {
241    /// Get a copy of the inner raw value.
242    #[inline(always)]
243    pub const fn value(&self) -> ::core::ffi::c_int {
244        self.0
245    }
246}
247
248#[cfg(feature = "metadata")]
249impl sdl3_sys::metadata::GroupMetadata for SDL_AsyncIOResult {
250    const GROUP_METADATA: &'static sdl3_sys::metadata::Group =
251        &crate::metadata::asyncio::METADATA_SDL_AsyncIOResult;
252}
253
254/// Information about a completed asynchronous I/O request.
255///
256/// ## Availability
257/// This struct is available since SDL 3.2.0.
258#[repr(C)]
259#[cfg_attr(feature = "debug-impls", derive(Debug))]
260pub struct SDL_AsyncIOOutcome {
261    /// what generated this task. This pointer will be invalid if it was closed!
262    pub asyncio: *mut SDL_AsyncIO,
263    /// What sort of task was this? Read, write, etc?
264    pub r#type: SDL_AsyncIOTaskType,
265    /// the result of the work (success, failure, cancellation).
266    pub result: SDL_AsyncIOResult,
267    /// buffer where data was read/written.
268    pub buffer: *mut ::core::ffi::c_void,
269    /// offset in the [`SDL_AsyncIO`] where data was read/written.
270    pub offset: Uint64,
271    /// number of bytes the task was to read/write.
272    pub bytes_requested: Uint64,
273    /// actual number of bytes that were read/written.
274    pub bytes_transferred: Uint64,
275    /// pointer provided by the app when starting the task
276    pub userdata: *mut ::core::ffi::c_void,
277}
278
279impl ::core::default::Default for SDL_AsyncIOOutcome {
280    /// Initialize all fields to zero
281    #[inline(always)]
282    fn default() -> Self {
283        unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() }
284    }
285}
286
287unsafe extern "C" {
288    /// Use this function to create a new [`SDL_AsyncIO`] object for reading from
289    /// and/or writing to a named file.
290    ///
291    /// The `mode` string understands the following values:
292    ///
293    /// - "r": Open a file for reading only. It must exist.
294    /// - "w": Open a file for writing only. It will create missing files or
295    ///   truncate existing ones.
296    /// - "r+": Open a file for update both reading and writing. The file must
297    ///   exist.
298    /// - "w+": Create an empty file for both reading and writing. If a file with
299    ///   the same name already exists its content is erased and the file is
300    ///   treated as a new empty file.
301    ///
302    /// There is no "b" mode, as there is only "binary" style I/O, and no "a" mode
303    /// for appending, since you specify the position when starting a task.
304    ///
305    /// This function supports Unicode filenames, but they must be encoded in UTF-8
306    /// format, regardless of the underlying operating system.
307    ///
308    /// This call is _not_ asynchronous; it will open the file before returning,
309    /// under the assumption that doing so is generally a fast operation. Future
310    /// reads and writes to the opened file will be async, however.
311    ///
312    /// ## Parameters
313    /// - `file`: a UTF-8 string representing the filename to open.
314    /// - `mode`: an ASCII string representing the mode to be used for opening
315    ///   the file.
316    ///
317    /// ## Return value
318    /// Returns a pointer to the [`SDL_AsyncIO`] structure that is created or NULL on
319    ///   failure; call [`SDL_GetError()`] for more information.
320    ///
321    /// ## Thread safety
322    /// It is safe to call this function from any thread.
323    ///
324    /// ## Availability
325    /// This function is available since SDL 3.2.0.
326    ///
327    /// ## See also
328    /// - [`SDL_CloseAsyncIO`]
329    /// - [`SDL_ReadAsyncIO`]
330    /// - [`SDL_WriteAsyncIO`]
331    pub fn SDL_AsyncIOFromFile(
332        file: *const ::core::ffi::c_char,
333        mode: *const ::core::ffi::c_char,
334    ) -> *mut SDL_AsyncIO;
335}
336
337unsafe extern "C" {
338    /// Use this function to get the size of the data stream in an [`SDL_AsyncIO`].
339    ///
340    /// This call is _not_ asynchronous; it assumes that obtaining this info is a
341    /// non-blocking operation in most reasonable cases.
342    ///
343    /// ## Parameters
344    /// - `asyncio`: the [`SDL_AsyncIO`] to get the size of the data stream from.
345    ///
346    /// ## Return value
347    /// Returns the size of the data stream in the [`SDL_IOStream`] on success or a
348    ///   negative error code on failure; call [`SDL_GetError()`] for more
349    ///   information.
350    ///
351    /// ## Thread safety
352    /// It is safe to call this function from any thread.
353    ///
354    /// ## Availability
355    /// This function is available since SDL 3.2.0.
356    pub fn SDL_GetAsyncIOSize(asyncio: *mut SDL_AsyncIO) -> Sint64;
357}
358
359unsafe extern "C" {
360    /// Start an async read.
361    ///
362    /// This function reads up to `size` bytes from `offset` position in the data
363    /// source to the area pointed at by `ptr`. This function may read less bytes
364    /// than requested.
365    ///
366    /// This function returns as quickly as possible; it does not wait for the read
367    /// to complete. On a successful return, this work will continue in the
368    /// background. If the work begins, even failure is asynchronous: a failing
369    /// return value from this function only means the work couldn't start at all.
370    ///
371    /// `ptr` must remain available until the work is done, and may be accessed by
372    /// the system at any time until then. Do not allocate it on the stack, as this
373    /// might take longer than the life of the calling function to complete!
374    ///
375    /// An [`SDL_AsyncIOQueue`] must be specified. The newly-created task will be added
376    /// to it when it completes its work.
377    ///
378    /// ## Parameters
379    /// - `asyncio`: a pointer to an [`SDL_AsyncIO`] structure.
380    /// - `ptr`: a pointer to a buffer to read data into.
381    /// - `offset`: the position to start reading in the data source.
382    /// - `size`: the number of bytes to read from the data source.
383    /// - `queue`: a queue to add the new [`SDL_AsyncIO`] to.
384    /// - `userdata`: an app-defined pointer that will be provided with the task
385    ///   results.
386    ///
387    /// ## Return value
388    /// Returns true on success or false on failure; call [`SDL_GetError()`] for more
389    ///   information.
390    ///
391    /// ## Thread safety
392    /// It is safe to call this function from any thread.
393    ///
394    /// ## Availability
395    /// This function is available since SDL 3.2.0.
396    ///
397    /// ## See also
398    /// - [`SDL_WriteAsyncIO`]
399    /// - [`SDL_CreateAsyncIOQueue`]
400    pub fn SDL_ReadAsyncIO(
401        asyncio: *mut SDL_AsyncIO,
402        ptr: *mut ::core::ffi::c_void,
403        offset: Uint64,
404        size: Uint64,
405        queue: *mut SDL_AsyncIOQueue,
406        userdata: *mut ::core::ffi::c_void,
407    ) -> ::core::primitive::bool;
408}
409
410unsafe extern "C" {
411    /// Start an async write.
412    ///
413    /// This function writes `size` bytes from `offset` position in the data source
414    /// to the area pointed at by `ptr`.
415    ///
416    /// This function returns as quickly as possible; it does not wait for the
417    /// write to complete. On a successful return, this work will continue in the
418    /// background. If the work begins, even failure is asynchronous: a failing
419    /// return value from this function only means the work couldn't start at all.
420    ///
421    /// `ptr` must remain available until the work is done, and may be accessed by
422    /// the system at any time until then. Do not allocate it on the stack, as this
423    /// might take longer than the life of the calling function to complete!
424    ///
425    /// An [`SDL_AsyncIOQueue`] must be specified. The newly-created task will be added
426    /// to it when it completes its work.
427    ///
428    /// ## Parameters
429    /// - `asyncio`: a pointer to an [`SDL_AsyncIO`] structure.
430    /// - `ptr`: a pointer to a buffer to write data from.
431    /// - `offset`: the position to start writing to the data source.
432    /// - `size`: the number of bytes to write to the data source.
433    /// - `queue`: a queue to add the new [`SDL_AsyncIO`] to.
434    /// - `userdata`: an app-defined pointer that will be provided with the task
435    ///   results.
436    ///
437    /// ## Return value
438    /// Returns true on success or false on failure; call [`SDL_GetError()`] for more
439    ///   information.
440    ///
441    /// ## Thread safety
442    /// It is safe to call this function from any thread.
443    ///
444    /// ## Availability
445    /// This function is available since SDL 3.2.0.
446    ///
447    /// ## See also
448    /// - [`SDL_ReadAsyncIO`]
449    /// - [`SDL_CreateAsyncIOQueue`]
450    pub fn SDL_WriteAsyncIO(
451        asyncio: *mut SDL_AsyncIO,
452        ptr: *mut ::core::ffi::c_void,
453        offset: Uint64,
454        size: Uint64,
455        queue: *mut SDL_AsyncIOQueue,
456        userdata: *mut ::core::ffi::c_void,
457    ) -> ::core::primitive::bool;
458}
459
460unsafe extern "C" {
461    /// Close and free any allocated resources for an async I/O object.
462    ///
463    /// Closing a file is _also_ an asynchronous task! If a write failure were to
464    /// happen during the closing process, for example, the task results will
465    /// report it as usual.
466    ///
467    /// Closing a file that has been written to does not guarantee the data has
468    /// made it to physical media; it may remain in the operating system's file
469    /// cache, for later writing to disk. This means that a successfully-closed
470    /// file can be lost if the system crashes or loses power in this small window.
471    /// To prevent this, call this function with the `flush` parameter set to true.
472    /// This will make the operation take longer, and perhaps increase system load
473    /// in general, but a successful result guarantees that the data has made it to
474    /// physical storage. Don't use this for temporary files, caches, and
475    /// unimportant data, and definitely use it for crucial irreplaceable files,
476    /// like game saves.
477    ///
478    /// This function guarantees that the close will happen after any other pending
479    /// tasks to `asyncio`, so it's safe to open a file, start several operations,
480    /// close the file immediately, then check for all results later. This function
481    /// will not block until the tasks have completed.
482    ///
483    /// Once this function returns true, `asyncio` is no longer valid, regardless
484    /// of any future outcomes. Any completed tasks might still contain this
485    /// pointer in their [`SDL_AsyncIOOutcome`] data, in case the app was using this
486    /// value to track information, but it should not be used again.
487    ///
488    /// If this function returns false, the close wasn't started at all, and it's
489    /// safe to attempt to close again later.
490    ///
491    /// An [`SDL_AsyncIOQueue`] must be specified. The newly-created task will be added
492    /// to it when it completes its work.
493    ///
494    /// ## Parameters
495    /// - `asyncio`: a pointer to an [`SDL_AsyncIO`] structure to close.
496    /// - `flush`: true if data should sync to disk before the task completes.
497    /// - `queue`: a queue to add the new [`SDL_AsyncIO`] to.
498    /// - `userdata`: an app-defined pointer that will be provided with the task
499    ///   results.
500    ///
501    /// ## Return value
502    /// Returns true on success or false on failure; call [`SDL_GetError()`] for more
503    ///   information.
504    ///
505    /// ## Thread safety
506    /// It is safe to call this function from any thread, but two
507    ///   threads should not attempt to close the same object.
508    ///
509    /// ## Availability
510    /// This function is available since SDL 3.2.0.
511    pub fn SDL_CloseAsyncIO(
512        asyncio: *mut SDL_AsyncIO,
513        flush: ::core::primitive::bool,
514        queue: *mut SDL_AsyncIOQueue,
515        userdata: *mut ::core::ffi::c_void,
516    ) -> ::core::primitive::bool;
517}
518
519unsafe extern "C" {
520    /// Create a task queue for tracking multiple I/O operations.
521    ///
522    /// Async I/O operations are assigned to a queue when started. The queue can be
523    /// checked for completed tasks thereafter.
524    ///
525    /// ## Return value
526    /// Returns a new task queue object or NULL if there was an error; call
527    ///   [`SDL_GetError()`] for more information.
528    ///
529    /// ## Thread safety
530    /// It is safe to call this function from any thread.
531    ///
532    /// ## Availability
533    /// This function is available since SDL 3.2.0.
534    ///
535    /// ## See also
536    /// - [`SDL_DestroyAsyncIOQueue`]
537    /// - [`SDL_GetAsyncIOResult`]
538    /// - [`SDL_WaitAsyncIOResult`]
539    pub fn SDL_CreateAsyncIOQueue() -> *mut SDL_AsyncIOQueue;
540}
541
542unsafe extern "C" {
543    /// Destroy a previously-created async I/O task queue.
544    ///
545    /// If there are still tasks pending for this queue, this call will block until
546    /// those tasks are finished. All those tasks will be deallocated. Their
547    /// results will be lost to the app.
548    ///
549    /// Any pending reads from [`SDL_LoadFileAsync()`] that are still in this queue
550    /// will have their buffers deallocated by this function, to prevent a memory
551    /// leak.
552    ///
553    /// Once this function is called, the queue is no longer valid and should not
554    /// be used, including by other threads that might access it while destruction
555    /// is blocking on pending tasks.
556    ///
557    /// Do not destroy a queue that still has threads waiting on it through
558    /// [`SDL_WaitAsyncIOResult()`]. You can call [`SDL_SignalAsyncIOQueue()`] first to
559    /// unblock those threads, and take measures (such as [`SDL_WaitThread()`]) to make
560    /// sure they have finished their wait and won't wait on the queue again.
561    ///
562    /// ## Parameters
563    /// - `queue`: the task queue to destroy.
564    ///
565    /// ## Thread safety
566    /// It is safe to call this function from any thread, so long as
567    ///   no other thread is waiting on the queue with
568    ///   [`SDL_WaitAsyncIOResult`].
569    ///
570    /// ## Availability
571    /// This function is available since SDL 3.2.0.
572    pub fn SDL_DestroyAsyncIOQueue(queue: *mut SDL_AsyncIOQueue);
573}
574
575unsafe extern "C" {
576    /// Query an async I/O task queue for completed tasks.
577    ///
578    /// If a task assigned to this queue has finished, this will return true and
579    /// fill in `outcome` with the details of the task. If no task in the queue has
580    /// finished, this function will return false. This function does not block.
581    ///
582    /// If a task has completed, this function will free its resources and the task
583    /// pointer will no longer be valid. The task will be removed from the queue.
584    ///
585    /// It is safe for multiple threads to call this function on the same queue at
586    /// once; a completed task will only go to one of the threads.
587    ///
588    /// ## Parameters
589    /// - `queue`: the async I/O task queue to query.
590    /// - `outcome`: details of a finished task will be written here. May not be
591    ///   NULL.
592    ///
593    /// ## Return value
594    /// Returns true if a task has completed, false otherwise.
595    ///
596    /// ## Thread safety
597    /// It is safe to call this function from any thread.
598    ///
599    /// ## Availability
600    /// This function is available since SDL 3.2.0.
601    ///
602    /// ## See also
603    /// - [`SDL_WaitAsyncIOResult`]
604    pub fn SDL_GetAsyncIOResult(
605        queue: *mut SDL_AsyncIOQueue,
606        outcome: *mut SDL_AsyncIOOutcome,
607    ) -> ::core::primitive::bool;
608}
609
610unsafe extern "C" {
611    /// Block until an async I/O task queue has a completed task.
612    ///
613    /// This function puts the calling thread to sleep until there a task assigned
614    /// to the queue that has finished.
615    ///
616    /// If a task assigned to the queue has finished, this will return true and
617    /// fill in `outcome` with the details of the task. If no task in the queue has
618    /// finished, this function will return false.
619    ///
620    /// If a task has completed, this function will free its resources and the task
621    /// pointer will no longer be valid. The task will be removed from the queue.
622    ///
623    /// It is safe for multiple threads to call this function on the same queue at
624    /// once; a completed task will only go to one of the threads.
625    ///
626    /// Note that by the nature of various platforms, more than one waiting thread
627    /// may wake to handle a single task, but only one will obtain it, so
628    /// `timeoutMS` is a _maximum_ wait time, and this function may return false
629    /// sooner.
630    ///
631    /// This function may return false if there was a system error, the OS
632    /// inadvertently awoke multiple threads, or if [`SDL_SignalAsyncIOQueue()`] was
633    /// called to wake up all waiting threads without a finished task.
634    ///
635    /// A timeout can be used to specify a maximum wait time, but rather than
636    /// polling, it is possible to have a timeout of -1 to wait forever, and use
637    /// [`SDL_SignalAsyncIOQueue()`] to wake up the waiting threads later.
638    ///
639    /// ## Parameters
640    /// - `queue`: the async I/O task queue to wait on.
641    /// - `outcome`: details of a finished task will be written here. May not be
642    ///   NULL.
643    /// - `timeoutMS`: the maximum time to wait, in milliseconds, or -1 to wait
644    ///   indefinitely.
645    ///
646    /// ## Return value
647    /// Returns true if task has completed, false otherwise.
648    ///
649    /// ## Thread safety
650    /// It is safe to call this function from any thread.
651    ///
652    /// ## Availability
653    /// This function is available since SDL 3.2.0.
654    ///
655    /// ## See also
656    /// - [`SDL_SignalAsyncIOQueue`]
657    pub fn SDL_WaitAsyncIOResult(
658        queue: *mut SDL_AsyncIOQueue,
659        outcome: *mut SDL_AsyncIOOutcome,
660        timeoutMS: Sint32,
661    ) -> ::core::primitive::bool;
662}
663
664unsafe extern "C" {
665    /// Wake up any threads that are blocking in [`SDL_WaitAsyncIOResult()`].
666    ///
667    /// This will unblock any threads that are sleeping in a call to
668    /// [`SDL_WaitAsyncIOResult`] for the specified queue, and cause them to return
669    /// from that function.
670    ///
671    /// This can be useful when destroying a queue to make sure nothing is touching
672    /// it indefinitely. In this case, once this call completes, the caller should
673    /// take measures to make sure any previously-blocked threads have returned
674    /// from their wait and will not touch the queue again (perhaps by setting a
675    /// flag to tell the threads to terminate and then using [`SDL_WaitThread()`] to
676    /// make sure they've done so).
677    ///
678    /// ## Parameters
679    /// - `queue`: the async I/O task queue to signal.
680    ///
681    /// ## Thread safety
682    /// It is safe to call this function from any thread.
683    ///
684    /// ## Availability
685    /// This function is available since SDL 3.2.0.
686    ///
687    /// ## See also
688    /// - [`SDL_WaitAsyncIOResult`]
689    pub fn SDL_SignalAsyncIOQueue(queue: *mut SDL_AsyncIOQueue);
690}
691
692unsafe extern "C" {
693    /// Load all the data from a file path, asynchronously.
694    ///
695    /// This function returns as quickly as possible; it does not wait for the read
696    /// to complete. On a successful return, this work will continue in the
697    /// background. If the work begins, even failure is asynchronous: a failing
698    /// return value from this function only means the work couldn't start at all.
699    ///
700    /// The data is allocated with a zero byte at the end (null terminated) for
701    /// convenience. This extra byte is not included in SDL_AsyncIOOutcome's
702    /// bytes_transferred value.
703    ///
704    /// This function will allocate the buffer to contain the file. It must be
705    /// deallocated by calling [`SDL_free()`] on SDL_AsyncIOOutcome's buffer field
706    /// after completion.
707    ///
708    /// An [`SDL_AsyncIOQueue`] must be specified. The newly-created task will be added
709    /// to it when it completes its work.
710    ///
711    /// ## Parameters
712    /// - `file`: the path to read all available data from.
713    /// - `queue`: a queue to add the new [`SDL_AsyncIO`] to.
714    /// - `userdata`: an app-defined pointer that will be provided with the task
715    ///   results.
716    ///
717    /// ## Return value
718    /// Returns true on success or false on failure; call [`SDL_GetError()`] for more
719    ///   information.
720    ///
721    /// ## Thread safety
722    /// It is safe to call this function from any thread.
723    ///
724    /// ## Availability
725    /// This function is available since SDL 3.2.0.
726    ///
727    /// ## See also
728    /// - [`SDL_LoadFile_IO`]
729    pub fn SDL_LoadFileAsync(
730        file: *const ::core::ffi::c_char,
731        queue: *mut SDL_AsyncIOQueue,
732        userdata: *mut ::core::ffi::c_void,
733    ) -> ::core::primitive::bool;
734}
735
736/// The asynchronous I/O operation structure.
737///
738/// This operates as an opaque handle. One can then request read or write
739/// operations on it.
740///
741/// ## Availability
742/// This struct is available since SDL 3.2.0.
743///
744/// ## See also
745/// - [`SDL_AsyncIOFromFile`]
746#[repr(C)]
747pub struct SDL_AsyncIO {
748    _opaque: [::core::primitive::u8; 0],
749}
750
751/// A queue of completed asynchronous I/O tasks.
752///
753/// When starting an asynchronous operation, you specify a queue for the new
754/// task. A queue can be asked later if any tasks in it have completed,
755/// allowing an app to manage multiple pending tasks in one place, in whatever
756/// order they complete.
757///
758/// ## Availability
759/// This struct is available since SDL 3.2.0.
760///
761/// ## See also
762/// - [`SDL_CreateAsyncIOQueue`]
763/// - [`SDL_ReadAsyncIO`]
764/// - [`SDL_WriteAsyncIO`]
765/// - [`SDL_GetAsyncIOResult`]
766/// - [`SDL_WaitAsyncIOResult`]
767#[repr(C)]
768pub struct SDL_AsyncIOQueue {
769    _opaque: [::core::primitive::u8; 0],
770}
771
772#[cfg(doc)]
773use crate::everything::*;