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)
    let helloWorld = buf.getString(at: 0, length: 11)
    
    buf.setInteger(17 as Int, at: 11)
    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
  • 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
  • SocketOption allows users to specify configuration settings that are directly applied to the underlying socket file descriptor.

    Valid options are typically found in the various man pages like man 4 tcp.

    See more

    Declaration

    Swift

    public struct SocketOption : ChannelOption, Equatable
  • AllocatorOption allows to specify the ByteBufferAllocator to use.

    See more

    Declaration

    Swift

    public struct AllocatorOption : ChannelOption
  • RecvAllocatorOption allows users to specify the RecvByteBufferAllocator to use.

    See more

    Declaration

    Swift

    public struct RecvAllocatorOption : ChannelOption
  • AutoReadOption allows users to configure if a Channel should automatically call Channel.read again once all data was read from the transport or if the user is responsible to call Channel.read manually.

    See more

    Declaration

    Swift

    public struct AutoReadOption : ChannelOption
  • WriteSpinOption allows users to configure the number of repetitions of a only partially successful write call before considering the Channel not writable. Setting this option to 0 means that we only issue one write call and if that call does not write all the bytes, we consider the Channel not writable.

    See more

    Declaration

    Swift

    public struct WriteSpinOption : ChannelOption
  • MaxMessagesPerReadOption allows users to configure the maximum number of read calls to the underlying transport are performed before wait again until there is more to read and be notified.

    See more

    Declaration

    Swift

    public struct MaxMessagesPerReadOption : ChannelOption
  • BacklogOption allows users to configure the backlog value as specified in man 2 listen. This is only useful for ServerSocketChannels.

    See more

    Declaration

    Swift

    public struct BacklogOption : ChannelOption
  • DatagramVectorReadMessageCountOption allows users to configure the number of messages to attempt to read in a single syscall on a datagram Channel.

    Some datagram Channels have extremely high datagram throughput. This can occur when the single datagram socket is encapsulating many logical connections (e.g. with QUIC) or when the datagram socket is simply serving an enormous number of consumers (e.g. with a public-facing DNS server). In this case the overhead of one syscall per datagram is profoundly limiting. Using this ChannelOption allows the Channel to read multiple datagrams at once.

    Note that simply increasing this number will not necessarily bring performance gains and may in fact cause data loss. Any increase to this should be matched by increasing the size of the buffers allocated by the Channel RecvByteBufferAllocator (as set by ChannelOption.recvAllocator) proportionally. For example, to receive 10 messages at a time, set the size of the buffers allocated by the RecvByteBufferAllocator to at least 10x the size of the maximum datagram size you wish to receive.

    Naturally, this option is only valid on datagram channels.

    This option only works on the following platforms:

    • Linux
    • FreeBSD
    • Android

    On all other platforms, setting it has no effect.

    Set this option to 0 to disable vector reads and to use serial reads instead.

    See more

    Declaration

    Swift

    public struct DatagramVectorReadMessageCountOption : ChannelOption
  • The watermark used to detect when Channel.isWritable returns true or false.

    See more

    Declaration

    Swift

    public struct WriteBufferWaterMark
  • WriteBufferWaterMarkOption allows users to configure when a Channel should be marked as writable or not. Once the amount of bytes queued in a Channels outbound buffer is larger than WriteBufferWaterMark.high the channel will be marked as non-writable and so Channel.isWritable will return false. Once we were able to write some data out of the outbound buffer and the amount of bytes queued falls below WriteBufferWaterMark.low the Channel will become writable again. Once this happens Channel.writable will return true again. These writability changes are also propagated through the ChannelPipeline and so can be intercepted via ChannelInboundHandler.channelWritabilityChanged.

    See more

    Declaration

    Swift

    public struct WriteBufferWaterMarkOption : ChannelOption
  • ConnectTimeoutOption allows users to configure the TimeAmount after which a connect will fail if it was not established in the meantime. May be nil, in which case the connection attempt will never time out.

    See more

    Declaration

    Swift

    public struct ConnectTimeoutOption : ChannelOption
  • AllowRemoteHalfClosureOption allows users to configure whether the Channel will close itself when its remote peer shuts down its send stream, or whether it will remain open. If set to false (the default), the Channel will be closed automatically if the remote peer shuts down its send stream. If set to true, the Channel will not be closed: instead, a ChannelEvent.inboundClosed user event will be sent on the ChannelPipeline, and no more data will be received.

    See more

    Declaration

    Swift

    public struct AllowRemoteHalfClosureOption : ChannelOption
  • Provides ChannelOptions to be used with a Channel, Bootstrap or ServerBootstrap.

    See more

    Declaration

    Swift

    public struct ChannelOptions
  • 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).then {
            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