//
//  VZVirtioQueueElement.h
//  Virtualization
//
//  Copyright © 2020-2026 Apple Inc. All rights reserved.
//

#import <Virtualization/VZDefines.h>

NS_ASSUME_NONNULL_BEGIN

/**
 A unit of work on a Virtio queue, also known as a descriptor chain.

 A `VZVirtioQueueElement` represents a unit of work from a ``VZVirtioQueue`` with which it's associated, facilitating device
 operations specified by the ``VZCustomVirtioDevice`` that the `VZVirtioQueue` belongs to. It exposes the scatter-gather memory to the
 guest's dynamic random access memory (DRAM) that the Virtio queue references as read buffers and write buffers; this allows for read-only and
 write-only access, respectively, to this memory on the host. It's strongly recommended to access the read buffers and write buffers only _once_
 using the ``VZVirtioQueueElement/readBytesWithExactLength:error:``,
 ``VZVirtioQueueElement/readBytesIntoBuffer:exactLength:error:``,
 ``VZVirtioQueueElement/writeData:error:``, and ``VZVirtioQueueElement/writeBuffer:exactLength:error:`` methods.
 Those methods enforce that you only access the memory once and changes the value of ``readBuffersAvailableByteCount`` and
 ``writeBuffersAvailableByteCount`` accordingly. The
 ``VZVirtioQueueElement/peekIntoReadBuffersWithExactLength:error:`` method allows for multiple read accesses
 if absolutely necessary and doesn't change the value of ``readBuffersAvailableByteCount``.

 > Important: Accessing this memory multiple times can introduce time-of-check time-of-use (TOCTOU) bugs which are prone to security attacks. Since the
 guest is free to modify its memory at any time, two consecutive reads may return different results, and malicious guests can take advantage of
 this to perform various attacks.

 Don't instantiate `VZVirtioQueueElement` objects directly, the framework provides them through
 the ``VZVirtioQueue/nextElement`` method when you handle any elements in the Virtio queue. When
 you are done with processing the element, you need to call ``VZVirtioQueueElement/returnToQueue`` to return the element back to the guest.

 ## See Also

 - ``VZCustomVirtioDevice``
 - ``VZVirtioQueue``

 */
VZ_EXPORT API_AVAILABLE(macos(27.0))
@interface VZVirtioQueueElement : NSObject

+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;

/**
 The total size of the read buffers memory (in bytes) exposed by the Virtio queue element.
 */
@property (readonly) NSUInteger readBuffersByteCount;

/**
 The size of the read buffers memory (in bytes) exposed by the Virtio queue element that's currently available for reading.

 This value is initially equal to ``readBuffersByteCount``. This value decreases as you read memory from the read buffers.
 */
@property (readonly) NSUInteger readBuffersAvailableByteCount;

/**
 The total size of the write buffers memory (in bytes) exposed by the Virtio queue element.
 */
@property (readonly) NSUInteger writeBuffersByteCount;

/**
 The size of the write buffers memory (in bytes) exposed by the Virtio queue element that's currently available for writing.

 This value is initially equal to `writeBuffersByteCount`. This value decreases as you write memory to the write buffers.
 */
@property (readonly) NSUInteger writeBuffersAvailableByteCount;

/**
 The size of the write buffers memory exposed (in bytes) by the Virtio queue element that has already been written to.

 This value increases as you write memory to the write buffers. This value is initially equal to 0.
 */
@property (readonly) NSUInteger writtenByteCount;

/**
 Gets the remaining read buffers memory represented as an array of data.

 This method gets the remaining read buffers memory, after calling this method, ``readBuffersAvailableByteCount`` will be zero,
 behaving as if you have read all of the read buffers available in the ``VZVirtioQueueElement``.

 Here, the memory is represented as scatter-gather buffers directly referencing guest memory without any extra copy.

 > Important: It's strongly recommended to access the underlying memory only once. Accessing this memory multiple times can
 introduce time-of-check, time-of-use (TOCTOU) bugs which are prone to security attacks. Since the guest is free to modify its
 memory at any time, two consecutive reads may return different results, and malicious guests can take advantage of this to
 perform various attacks.

 - Returns: An array of <doc://com.apple.documentation/documentation/foundation/nsdata> object that represents the remaining read buffers memory.
 */
- (NSArray<NSData *> *)readBuffers;

/**
  Peeks into the read buffers and copy exactLength bytes from the read buffer into the data object it returns.

 This method allows you to peek into the read buffers without consuming any of the memory, ``readBuffersAvailableByteCount``
 does not change after this call.

 - Parameters:
    - exactLength: Number of bytes to copy from the read buffers.
    - error: If not nil, assigned with the error if the peek failed.

 - Returns: An <doc://com.apple.documentation/documentation/foundation/nsdata> object filled with the memory that the framework copied, or `nil` if the peek failed.
 */
- (nullable NSData *)peekIntoReadBuffersWithExactLength:(NSUInteger)exactLength error:(NSError **)error;

/**
 Reads the number of bytes you specify from the read buffers and return result as a data object.

    Memory is copied into the newly allocated buffer represented by the returned NSData object.

 - Parameters:
    - exactLength: Number of bytes to read from the read buffers.
    - error: If not `nil`, assigned with the error if the read failed.

 - Returns: An <doc://com.apple.documentation/documentation/foundation/nsdata> object filled with the memory that the framework read, or `nil` if the read failed.
 */
- (nullable NSData *)readBytesWithExactLength:(NSUInteger)exactLength error:(NSError **)error;

/**
Reads the number of bytes you specify from the read buffers into the memory pointed to by the pointer to the buffer you provide.

 - Parameters:
    - buffer: Pointer to where the framework reads the read buffer's memory to.
    - exactLength: Number of bytes to read from the read buffers.
    - error: If not `nil`, assigned with the error if the read failed.

 - Returns: `YES` if the read was successful, `NO` otherwise.
 */
- (BOOL)readBytesIntoBuffer:(void*)buffer exactLength:(NSUInteger)exactLength error:(NSError **)error;

/**
 Writes the memory represented by the data object you provide into the write buffers.

 - Parameters:
    - data: The <doc://com.apple.documentation/documentation/foundation/nsdata> object that represents the memory the framework uses to the write buffers.
    - error: If not `nil`, assigned with the error if the write failed.

 - Returns: `YES` if the write was successful, `NO` otherwise.
 */
- (BOOL)writeData:(NSData *)data error:(NSError **)error;

/**
Writes to the memory represented by the pointer to the buffer you provide to the write buffers.

 - Parameters:
    - buffer: A pointer to the memory containing the data to write to the write buffers.
    - exactLength: The number of bytes the framework should write to the write buffers.
    - error: If not `nil`, assigned with the error if the write failed.

 - Returns: `YES` if the write was successful, `NO` otherwise.
 */
- (BOOL)writeBuffer:(void*)buffer exactLength:(NSUInteger)exactLength error:(NSError **)error;

/**
Returns this element back to the guest.

 Use this method when you are done processing this element and return it to the guest.

 Use this method together with the ``VZVirtioQueue/nextElement`` method to process the elements in the queue.

 The element you pass to this method must be one that you obtained from calling the ``VZVirtioQueue/nextElement`` method.
 Attempts to call this method more than once with the same element results in the framework raising an exception.
 */
- (void)returnToQueue;

@end

NS_ASSUME_NONNULL_END
