Structures

The following structures are available globally.

  • A data structure for processing addressed datagrams, such as those used by UDP.

    The AddressedEnvelope is used extensively on DatagramChannels in order to keep track of source or destination address metadata: that is, where some data came from or where it is going.

    See more

    Declaration

    Swift

    public struct AddressedEnvelope<DataType>
  • ByteBuffer stores contiguously allocated raw bytes. It is a random and sequential accessible sequence of zero or more bytes (octets).

    Allocation

    Use allocator.buffer(capacity: desiredCapacity) to allocate a new ByteBuffer.

    Supported types

    A variety of types can be read/written from/to a ByteBuffer. Using Swift’s extension mechanism you can easily create ByteBuffer support for your own data types. Out of the box, ByteBuffer supports for example the following types (non-exhaustive list):

    • String/StaticString
    • Swift’s various (unsigned) integer types
    • Foundation‘s Data
    • [UInt8] and generally any Collection of UInt8

    Random Access

    For every supported type ByteBuffer usually contains two methods for random access:

    1. get<Type>(at: Int, length: Int) where <type> is for example String, Data, Bytes (for [UInt8])
    2. set<Type>(at: Int)

    Example:

    var buf = ...
    buf.setString("Hello World", at: 0)
    buf.moveWriterIndex(to: 11)
    let helloWorld = buf.getString(at: 0, length: 11)
    
    let written = buf.setInteger(17 as Int, at: 11)
    buf.moveWriterIndex(forwardBy: written)
    let seventeen: Int? = buf.getInteger(at: 11)
    

    If needed, ByteBuffer will automatically resize its storage to accommodate your set request.

    Sequential Access

    ByteBuffer provides two properties which are indices into the ByteBuffer to support sequential access:

    • readerIndex, the index of the next readable byte
    • writerIndex, the index of the next byte to write

    For every supported type ByteBuffer usually contains two methods for sequential access:

    1. read<Type>(length: Int) to read length bytes from the current readerIndex (and then advance the reader index by length bytes)
    2. write<Type>(Type) to write, advancing the writerIndex by the appropriate amount

    Example:

     var buf = ...
     buf.writeString("Hello World")
     buf.writeInteger(17 as Int)
     let helloWorld = buf.readString(length: 11)
     let seventeen: Int = buf.readInteger()
    

    Layout

    +-------------------+------------------+------------------+
    | discardable bytes |  readable bytes  |  writable bytes  |
    |                   |     (CONTENT)    |                  |
    +-------------------+------------------+------------------+
    |                   |                  |                  |
    0      <=      readerIndex   <=   writerIndex    <=    capacity
    

    The 'discardable bytes’ are usually bytes that have already been read, they can however still be accessed using the random access methods. ‘Readable bytes’ are the bytes currently available to be read using the sequential access interface (read<Type>/write<Type>). Getting writableBytes (bytes beyond the writer index) is undefined behaviour and might yield arbitrary bytes (not 0 initialised).

    Slicing

    ByteBuffer supports slicing a ByteBuffer without copying the underlying storage.

    Example:

    var buf = ...
    let dataBytes: [UInt8] = [0xca, 0xfe, 0xba, 0xbe]
    let dataBytesLength = UInt32(dataBytes.count)
    buf.writeInteger(dataBytesLength) /* the header */
    buf.writeBytes(dataBytes) /* the data */
    let bufDataBytesOnly = buf.getSlice(at: 4, length: dataBytes.count)
    /* `bufDataByteOnly` and `buf` will share their storage */
    

    Notes

    All ByteBuffer methods that don’t contain the word ‘unsafe’ will only allow you to access the ‘readable bytes’.

    See more

    Declaration

    Swift

    public struct ByteBuffer
  • The preferred allocator for ByteBuffer values. The allocation strategy is opaque but is currently libc’s malloc, realloc and free.

    Note

    ByteBufferAllocator is thread-safe.
    See more

    Declaration

    Swift

    public struct ByteBufferAllocator
  • A read-only view into a portion of a ByteBuffer.

    A ByteBufferView is useful whenever a Collection where Element == UInt8 representing a portion of a ByteBuffer is needed.

    See more

    Declaration

    Swift

    public struct ByteBufferView : RandomAccessCollection
  • NIOFailedToSetSocketNonBlockingError indicates that NIO was unable to set a socket to non-blocking mode, either when connecting a socket as a client or when accepting a socket as a server.

    This error should never happen because a socket should always be able to be set to non-blocking mode. Unfortunately, we have seen this happen on Darwin.

    Declaration

    Swift

    public struct NIOFailedToSetSocketNonBlockingError : Error
  • The removal of a ChannelHandler using ChannelPipeline.removeHandler has been attempted more than once.

    Declaration

    Swift

    public struct NIOAttemptedToRemoveHandlerMultipleTimesError : Error
  • A Channel user event that is sent when the Channel has been asked to quiesce.

    The action(s) that should be taken after receiving this event are both application and protocol dependent. If the protocol supports a notion of requests and responses, it might make sense to stop accepting new requests but finish processing the request currently in flight.

    See more

    Declaration

    Swift

    public struct ChannelShouldQuiesceEvent
  • An automatically expanding ring buffer implementation backed by a ContiguousArray. Even though this implementation will automatically expand if more elements than initialCapacity are stored, it’s advantageous to prevent expansions from happening frequently. Expansions will always force an allocation and a copy to happen.

    See more

    Declaration

    Swift

    public struct CircularBuffer<Element> : CustomStringConvertible
  • Returned once a task was scheduled on the EventLoop for later execution.

    A Scheduled allows the user to either cancel() the execution of the scheduled task (if possible) or obtain a reference to the EventLoopFuture that will be notified once the execution is complete.

    See more

    Declaration

    Swift

    public struct Scheduled<T>
  • An iterator over the EventLoops forming an EventLoopGroup.

    Usually returned by an EventLoopGroup‘s makeIterator() method.

    let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
    group.makeIterator().forEach { loop in
        // Do something with each loop
    }
    
    See more

    Declaration

    Swift

    public struct EventLoopIterator : Sequence, IteratorProtocol
  • Represents a time interval.

    Note

    TimeAmount should not be used to represent a point in time.
    See more

    Declaration

    Swift

    public struct TimeAmount : Equatable
  • Represents a point in time.

    Stores the time in nanoseconds as returned by DispatchTime.now().uptimeNanoseconds

    NIODeadline allow chaining multiple tasks with the same deadline without needing to compute new timeouts for each step

    func doSomething(deadline: NIODeadline) -> EventLoopFuture<Void> {
        return step1(deadline: deadline).flatMap {
            step2(deadline: deadline)
        }
    }
    doSomething(deadline: .now() + .seconds(5))
    

    Note

    NIODeadline should not be used to represent a time interval
    See more

    Declaration

    Swift

    public struct NIODeadline : Equatable, Hashable
  • A promise to provide a result later.

    This is the provider API for EventLoopFuture<Value>. If you want to return an unfulfilled EventLoopFuture<Value> – presumably because you are interfacing to some asynchronous service that will return a real result later, follow this pattern:

    func someAsyncOperation(args) -> EventLoopFuture<ResultType> {
        let promise = eventLoop.makePromise(of: ResultType.self)
        someAsyncOperationWithACallback(args) { result -> Void in
            // when finished...
            promise.succeed(result)
            // if error...
            promise.fail(error)
        }
        return promise.futureResult
    }
    

    Note that the future result is returned before the async process has provided a value.

    It’s actually not very common to use this directly. Usually, you really want one of the following:

  • If you have an EventLoopFuture and want to do something else after it completes, use .flatMap()
  • If you already have a value and need an EventLoopFuture<> object to plug into some other API, create an already-resolved object with eventLoop.makeSucceededFuture(result) or eventLoop.newFailedFuture(error:).

  • Note

    EventLoopPromise has reference semantics.

    See more

    Declaration

    Swift

    public struct EventLoopPromise<Value>
  • A FileRegion represent a readable portion usually created to be sent over the network.

    Usually a FileRegion will allow the underlying transport to use sendfile to transfer its content and so allows transferring the file content without copying it into user-space at all. If the actual transport implementation really can make use of sendfile or if it will need to copy the content to user-space first and use write / writev is an implementation detail. That said using FileRegion is the recommended way to transfer file content if possible.

    One important note, depending your ChannelPipeline setup it may not be possible to use a FileRegion as a ChannelHandler may need access to the bytes (in a ByteBuffer) to transform these.

    Note

    It is important to manually manage the lifetime of the NIOFileHandle used to create a FileRegion.
    See more

    Declaration

    Swift

    public struct FileRegion
  • A circular buffer that allows one object at a time to be marked and easily identified and retrieved later.

    This object is used extensively within SwiftNIO to handle flushable buffers. It can be used to store buffered writes and mark how far through the buffer the user has flushed, and therefore how far through the buffer is safe to write.

    See more

    Declaration

    Swift

    public struct MarkedCircularBuffer<Element> : CustomStringConvertible
  • NIOAny is an opaque container for values of any type, similar to Swift’s builtin Any type. Contrary to Any the overhead of NIOAny depends on the the type of the wrapped value. Certain types that are important for the performance of a SwiftNIO application like ByteBuffer, FileRegion and AddressEnvelope<ByteBuffer> can be expected to be wrapped almost without overhead. All others will have similar performance as if they were passed as an Any as NIOAny just like Any will contain them within an existential container.

    The most important use-cases for NIOAny are values travelling through the ChannelPipeline whose type can’t be calculated at compile time. For example:

    The abstraction that delivers a NIOAny to user code must provide a mechanism to unwrap a NIOAny as a certain type known at run-time. Canonical example:

    class SandwichHandler: ChannelInboundHandler {
        typealias InboundIn = Bacon /* we expected to be delivered `Bacon` ... */
        typealias InboundOut = Sandwich /* ... and we will make and deliver a `Sandwich` from that */
    
        func channelRead(context: ChannelHandlerContext, data: NIOAny) {
             /* we receive the `Bacon` as a `NIOAny` as at compile-time the exact configuration of the channel
                pipeline can't be computed. The pipeline can't be computed at compile time as it can change
                dynamically at run-time. Yet, we assert that in any configuration the channel handler before
                `SandwichHandler` does actually send us a stream of `Bacon`.
             */
             let bacon = self.unwrapInboundIn(data) /* `Bacon` or crash */
             let sandwich = makeSandwich(bacon)
             context.fireChannelRead(self.wrapInboundOut(sandwich)) /* as promised we deliver a wrapped `Sandwich` */
        }
    }
    
    See more

    Declaration

    Swift

    public struct NIOAny
  • NonBlockingFileIO is a helper that allows you to read files without blocking the calling thread.

    It is worth noting that kqueue, epoll or poll returning claiming a file is readable does not mean that the data is already available in the kernel’s memory. In other words, a read from a file can still block even if reported as readable. This behaviour is also documented behaviour:

    • poll: Regular files shall always poll TRUE for reading and writing.
    • epoll: epoll is simply a faster poll(2), and can be used wherever the latter is used since it shares the same semantics.
    • kqueue: Returns when the file pointer is not at the end of file.

    NonBlockingFileIO helps to work around this issue by maintaining its own thread pool that is used to read the data from the files into memory. It will then hand the (in-memory) data back which makes it available without the possibility of blocking.

    See more

    Declaration

    Swift

    public struct NonBlockingFileIO