Skip to content

Commit

Permalink
Clean up and regression check the docs. (#2400)
Browse files Browse the repository at this point in the history
Motivation:

Up until recently, it has not been possible to regression check our
documentation. However, in recent releases of the DocC plugin it has
become possible to make warnings into errors, making it possible for us
to CI our docs.

This patch adds support for doing that, and also cleans up our
documentation so that it successfully passes the check.

Along the way I accidentally wrote an `index.md` for `NIOCore` so I
figure we may as well keep it.

Modifications:

- Structure the documentation for NIOCore
- Fix up DocC issues
- Add `check-docs.sh` script to check the docs cleanly build
- Wire things up to our docker-compose scripts.

Result:

We can CI our docs.

Co-authored-by: George Barnett <[email protected]>
  • Loading branch information
Lukasa and glbrntt authored Apr 11, 2023
1 parent e7e83d6 commit a7c36a7
Show file tree
Hide file tree
Showing 16 changed files with 246 additions and 35 deletions.
22 changes: 11 additions & 11 deletions Sources/NIO/Docs.docc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SwiftNIO is a cross-platform asynchronous event-driven network application frame

It's like Netty, but written for Swift.

## Repository organization
### Repository organization

The SwiftNIO project is split across multiple repositories:

Expand All @@ -21,7 +21,7 @@ Repo | Usage
[swift-nio-transport-services][repo-nio-transport-services] | First-class support for macOS, iOS, tvOS, and watchOS
[swift-nio-ssh][repo-nio-ssh] | SSH support

## Modules
### Modules

SwiftNIO has a number of products that provide different functionality. This package includes the following products:

Expand All @@ -36,7 +36,7 @@ SwiftNIO has a number of products that provide different functionality. This pac
- [NIOWebSocket][module-websocket]. This provides a low-level WebSocket protocol implementation.
- [NIOTestUtils][module-test-utilities]. This provides a number of helpers for testing projects that use SwiftNIO.

## Conceptual Overview
### Conceptual Overview

SwiftNIO is fundamentally a low-level tool for building high-performance networking applications in Swift. It particularly targets those use-cases where using a "thread-per-connection" model of concurrency is inefficient or untenable. This is a common limitation when building servers that use a large number of relatively low-utilization connections, such as HTTP servers.

Expand All @@ -46,7 +46,7 @@ SwiftNIO does not aim to provide high-level solutions like, for example, web fra

The following sections will describe the low-level tools that SwiftNIO provides, and provide a quick overview of how to work with them. If you feel comfortable with these concepts, then you can skip right ahead to the other sections of this document.

### Basic Architecture
#### Basic Architecture

The basic building blocks of SwiftNIO are the following 8 types of objects:

Expand All @@ -61,7 +61,7 @@ The basic building blocks of SwiftNIO are the following 8 types of objects:

All SwiftNIO applications are ultimately constructed of these various components.

#### EventLoops and EventLoopGroups
##### EventLoops and EventLoopGroups

The basic I/O primitive of SwiftNIO is the event loop. The event loop is an object that waits for events (usually I/O related events, such as "data received") to happen and then fires some kind of callback when they do. In almost all SwiftNIO applications there will be relatively few event loops: usually only one or two per CPU core the application wants to use. Generally speaking event loops run for the entire lifetime of your application, spinning in an endless loop dispatching events.

Expand All @@ -71,7 +71,7 @@ In SwiftNIO today there is one [`EventLoopGroup`][elg] implementation, and two [

[`EventLoop`][el]s have a number of important properties. Most vitally, they are the way all work gets done in SwiftNIO applications. In order to ensure thread-safety, any work that wants to be done on almost any of the other objects in SwiftNIO must be dispatched via an [`EventLoop`][el]. [`EventLoop`][el] objects own almost all the other objects in a SwiftNIO application, and understanding their execution model is critical for building high-performance SwiftNIO applications.

#### Channels, Channel Handlers, Channel Pipelines, and Channel Contexts
##### Channels, Channel Handlers, Channel Pipelines, and Channel Contexts

While [`EventLoop`][el]s are critical to the way SwiftNIO works, most users will not interact with them substantially beyond asking them to create [`EventLoopPromise`][elp]s and to schedule work. The parts of a SwiftNIO application most users will spend the most time interacting with are [`Channel`][c]s and [`ChannelHandler`][ch]s.

Expand All @@ -93,23 +93,23 @@ SwiftNIO ships with many [`ChannelHandler`][ch]s built in that provide useful fu

Additionally, SwiftNIO ships with a few [`Channel`][c] implementations. In particular, it ships with `ServerSocketChannel`, a [`Channel`][c] for sockets that accept inbound connections; `SocketChannel`, a [`Channel`][c] for TCP connections; and `DatagramChannel`, a [`Channel`][c] for UDP sockets. All of these are provided by the [NIOPosix][module-posix] module. It also provides[`EmbeddedChannel`][ec], a [`Channel`][c] primarily used for testing, provided by the [NIOEmbedded][module-embedded] module.

##### A Note on Blocking
###### A Note on Blocking

One of the important notes about [`ChannelPipeline`][cp]s is that they are thread-safe. This is very important for writing SwiftNIO applications, as it allows you to write much simpler [`ChannelHandler`][ch]s in the knowledge that they will not require synchronization.

However, this is achieved by dispatching all code on the [`ChannelPipeline`][cp] on the same thread as the [`EventLoop`][el]. This means that, as a general rule, [`ChannelHandler`][ch]s **must not** call blocking code without dispatching it to a background thread. If a [`ChannelHandler`][ch] blocks for any reason, all [`Channel`][c]s attached to the parent [`EventLoop`][el] will be unable to progress until the blocking call completes.

This is a common concern while writing SwiftNIO applications. If it is useful to write code in a blocking style, it is highly recommended that you dispatch work to a different thread when you're done with it in your pipeline.

#### Bootstrap
##### Bootstrap

While it is possible to configure and register [`Channel`][c]s with [`EventLoop`][el]s directly, it is generally more useful to have a higher-level abstraction to handle this work.

For this reason, SwiftNIO ships a number of `Bootstrap` objects whose purpose is to streamline the creation of channels. Some `Bootstrap` objects also provide other functionality, such as support for Happy Eyeballs for making TCP connection attempts.

Currently SwiftNIO ships with three `Bootstrap` objects in the [NIOPosix][module-posix] module: [`ServerBootstrap`][sb], for bootstrapping listening channels; [`ClientBootstrap`][cb], for bootstrapping client TCP channels; and [`DatagramBootstrap`][db] for bootstrapping UDP channels.

#### ByteBuffer
##### ByteBuffer

The majority of the work in a SwiftNIO application involves shuffling buffers of bytes around. At the very least, data is sent and received to and from the network in the form of buffers of bytes. For this reason it's very important to have a high-performance data structure that is optimized for the kind of work SwiftNIO applications perform.

Expand All @@ -121,7 +121,7 @@ In general, it is highly recommended that you use the [`ByteBuffer`][bb] in its

For more details on the API of [`ByteBuffer`][bb], please see our API documentation, linked below.

#### Promises and Futures
##### Promises and Futures

One major difference between writing concurrent code and writing synchronous code is that not all actions will complete immediately. For example, when you write data on a channel, it is possible that the event loop will not be able to immediately flush that write out to the network. For this reason, SwiftNIO provides [`EventLoopPromise<T>`][elp] and [`EventLoopFuture<T>`][elf] to manage operations that complete *asynchronously*. These types are provided by the [NIOCore][module-core] module.

Expand All @@ -133,7 +133,7 @@ Another important topic for consideration is the difference between how the prom

There are several functions for applying callbacks to [`EventLoopFuture<T>`][elf], depending on how and when you want them to execute. Details of these functions is left to the API documentation.

### Design Philosophy
#### Design Philosophy

SwiftNIO is designed to be a powerful tool for building networked applications and frameworks, but it is not intended to be the perfect solution for all levels of abstraction. SwiftNIO is tightly focused on providing the basic I/O primitives and protocol implementations at low levels of abstraction, leaving more expressive but slower abstractions to the wider community to build. The intention is that SwiftNIO will be a building block for server-side applications, not necessarily the framework those applications will use directly.

Expand Down
4 changes: 2 additions & 2 deletions Sources/NIOCore/AsyncAwaitSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ extension AsyncSequence where Element: RandomAccessCollection, Element.Element =

@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension AsyncSequence where Element == ByteBuffer {
/// Accumulates an ``Swift/AsyncSequence`` of ``ByteBuffer``s into a single `accumulationBuffer`.
/// Accumulates an `AsyncSequence` of ``ByteBuffer``s into a single `accumulationBuffer`.
/// - Parameters:
/// - accumulationBuffer: buffer to write all the elements of `self` into
/// - maxBytes: The maximum number of bytes this method is allowed to write into `accumulationBuffer`
Expand All @@ -285,7 +285,7 @@ extension AsyncSequence where Element == ByteBuffer {
}
}

/// Accumulates an ``Swift/AsyncSequence`` of ``ByteBuffer``s into a single ``ByteBuffer``.
/// Accumulates an `AsyncSequence` of ``ByteBuffer``s into a single ``ByteBuffer``.
/// - Parameters:
/// - maxBytes: The maximum number of bytes this method is allowed to accumulate
/// - Throws: `NIOTooManyBytesError` if the the sequence contains more than `maxBytes`.
Expand Down
6 changes: 3 additions & 3 deletions Sources/NIOCore/AsyncSequences/NIOAsyncSequenceProducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public protocol NIOAsyncSequenceProducerDelegate: Sendable {
func didTerminate()
}

/// This is an ``Swift/AsyncSequence`` that supports a unicast ``Swift/AsyncIterator``.
/// This is an `AsyncSequence` that supports a unicast `AsyncIterator`.
///
/// The goal of this sequence is to produce a stream of elements from the _synchronous_ world
/// (e.g. elements from a ``Channel`` pipeline) and vend it to the _asynchronous_ world for consumption.
Expand All @@ -103,7 +103,7 @@ public struct NIOAsyncSequenceProducer<
/// This struct contains two properties:
/// 1. The ``source`` which should be retained by the producer and is used
/// to yield new elements to the sequence.
/// 2. The ``sequence`` which is the actual ``Swift/AsyncSequence`` and
/// 2. The ``sequence`` which is the actual `AsyncSequence` and
/// should be passed to the consumer.
public struct NewSequence {
/// The source of the ``NIOAsyncSequenceProducer`` used to yield and finish.
Expand Down Expand Up @@ -254,7 +254,7 @@ extension NIOAsyncSequenceProducer {
/// The result of a call to ``NIOAsyncSequenceProducer/Source/yield(_:)``.
public enum YieldResult: Hashable {
/// Indicates that the caller should produce more elements for now. The delegate's ``NIOAsyncSequenceProducerDelegate/produceMore()``
/// will **NOT** get called, since the demand was already signalled through this ``YieldResult``
/// will **NOT** get called, since the demand was already signalled through this ``NIOAsyncSequenceProducer/Source/YieldResult``.
case produceMore
/// Indicates that the caller should stop producing elements. The delegate's ``NIOAsyncSequenceProducerDelegate/produceMore()``
/// will get called once production should be resumed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import DequeModule
import NIOConcurrencyHelpers

/// This is an ``Swift/AsyncSequence`` that supports a unicast ``Swift/AsyncIterator``.
/// This is an `AsyncSequence` that supports a unicast `AsyncIterator`.
///
/// The goal of this sequence is to produce a stream of elements from the _synchronous_ world
/// (e.g. elements from a ``Channel`` pipeline) and vend it to the _asynchronous_ world for consumption.
Expand All @@ -40,7 +40,7 @@ public struct NIOThrowingAsyncSequenceProducer<
/// This struct contains two properties:
/// 1. The ``source`` which should be retained by the producer and is used
/// to yield new elements to the sequence.
/// 2. The ``sequence`` which is the actual ``Swift/AsyncSequence`` and
/// 2. The ``sequence`` which is the actual `AsyncSequence` and
/// should be passed to the consumer.
public struct NewSequence {
/// The source of the ``NIOThrowingAsyncSequenceProducer`` used to yield and finish.
Expand Down
2 changes: 1 addition & 1 deletion Sources/NIOCore/ByteBuffer-views.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ extension ByteBufferView: RangeReplaceableCollection {
/// Reserves enough space in the underlying `ByteBuffer` such that this view can
/// store the specified number of bytes without reallocation.
///
/// See the documentation for ``ByteBuffer.reserveCapacity(_:)`` for more details.
/// See the documentation for ``ByteBuffer/reserveCapacity(_:)`` for more details.
@inlinable
public mutating func reserveCapacity(_ minimumCapacity: Int) {
let additionalCapacity = minimumCapacity - self.count
Expand Down
169 changes: 169 additions & 0 deletions Sources/NIOCore/Docs.docc/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# ``NIOCore``

The core abstractions that make up SwiftNIO.

## Overview

``NIOCore`` contains the fundamental abstractions that are used in all SwiftNIO programs. The goal of this module is to
be platform-independent, and to be the most-common building block used for NIO protocol implementations.

More specialized modules provide concrete implementations of many of the abstractions defined in NIOCore.

## Topics

### Event Loops and Event Loop Groups

- ``EventLoopGroup``
- ``EventLoop``
- ``NIOEventLoopGroupProvider``
- ``EventLoopIterator``
- ``Scheduled``
- ``RepeatedTask``
- ``NIOLoopBound``
- ``NIOLoopBoundBox``

### Channels and Channel Handlers

- ``Channel``
- ``MulticastChannel``
- ``ChannelHandler``
- ``ChannelOutboundHandler``
- ``ChannelInboundHandler``
- ``ChannelDuplexHandler``
- ``ChannelHandlerContext``
- ``ChannelPipeline``
- ``RemovableChannelHandler``
- ``NIOAny``
- ``ChannelEvent``
- ``CloseMode``
- ``ChannelShouldQuiesceEvent``

### Buffers and Files

- ``ByteBuffer``
- ``ByteBufferView``
- ``ByteBufferAllocator``
- ``Endianness``
- ``NIOFileHandle``
- ``FileDescriptor``
- ``FileRegion``
- ``NIOPOSIXFileMode``
- ``IOData``

### Futures and Promises

- ``EventLoopFuture``
- ``EventLoopPromise``

### Configuring Channels

- ``ChannelOption``
- ``NIOSynchronousChannelOptions``
- ``ChannelOptions``
- ``SocketOptionProvider``
- ``RecvByteBufferAllocator``
- ``AdaptiveRecvByteBufferAllocator``
- ``FixedSizeRecvByteBufferAllocator``
- ``AllocatorOption``
- ``AllowRemoteHalfClosureOption``
- ``AutoReadOption``
- ``BacklogOption``
- ``ConnectTimeoutOption``
- ``DatagramVectorReadMessageCountOption``
- ``MaxMessagesPerReadOption``
- ``RecvAllocatorOption``
- ``SocketOption``
- ``SocketOptionLevel``
- ``SocketOptionName``
- ``SocketOptionValue``
- ``WriteBufferWaterMarkOption``
- ``WriteBufferWaterMark``
- ``WriteSpinOption``

### Message Oriented Protocol Helpers

- ``AddressedEnvelope``
- ``NIOPacketInfo``
- ``NIOExplicitCongestionNotificationState``

### Generic Bootstraps

- ``NIOClientTCPBootstrap``
- ``NIOClientTCPBootstrapProtocol``
- ``NIOClientTLSProvider``
- ``NIOInsecureNoTLS``

### Simple Message Handling

- ``ByteToMessageDecoder``
- ``WriteObservingByteToMessageDecoder``
- ``DecodingState``
- ``ByteToMessageHandler``
- ``NIOSingleStepByteToMessageDecoder``
- ``NIOSingleStepByteToMessageProcessor``
- ``MessageToByteEncoder``
- ``MessageToByteHandler``

### Core Channel Handlers

- ``AcceptBackoffHandler``
- ``BackPressureHandler``
- ``NIOCloseOnErrorHandler``
- ``IdleStateHandler``

### Async Sequences

- ``NIOAsyncSequenceProducer``
- ``NIOThrowingAsyncSequenceProducer``
- ``NIOAsyncSequenceProducerBackPressureStrategy``
- ``NIOAsyncSequenceProducerBackPressureStrategies``
- ``NIOAsyncSequenceProducerDelegate``
- ``NIOAsyncWriter``
- ``NIOAsyncWriterSinkDelegate``

### Time

- ``TimeAmount``
- ``NIODeadline``

### Circular Buffers

- ``CircularBuffer``
- ``MarkedCircularBuffer``

### Operating System State

- ``System``
- ``NIONetworkDevice``
- ``NIONetworkInterface``
- ``SocketAddress``
- ``NIOBSDSocket``
- ``NIOIPProtocol``

### Implementing Core Abstractions

- ``ChannelCore``
- ``ChannelInvoker``
- ``ChannelInboundInvoker``
- ``ChannelOutboundInvoker``

### Sendable Helpers

- ``NIOSendable``
- ``NIOPreconcurrencySendable``

### Error Types

- ``ByteToMessageDecoderError``
- ``ChannelError``
- ``ChannelPipelineError``
- ``DatagramChannelError``
- ``EventLoopError``
- ``IOError``
- ``NIOAsyncWriterError``
- ``NIOAttemptedToRemoveHandlerMultipleTimesError``
- ``NIOMulticastNotImplementedError``
- ``NIOMulticastNotSupportedError``
- ``NIOTooManyBytesError``
- ``SocketAddressError``

2 changes: 1 addition & 1 deletion Sources/NIOCore/EventLoopFuture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ extension EventLoopFuture {
/// threads: it is primarily useful for testing, or for building interfaces between blocking
/// and non-blocking code.
///
/// This is also forbidden in async contexts: prefer ``EventLoopFuture/get``.
/// This is also forbidden in async contexts: prefer ``EventLoopFuture/get()``.
///
/// - returns: The value of the `EventLoopFuture` when it completes.
/// - throws: The error value of the `EventLoopFuture` if it errors.
Expand Down
Loading

0 comments on commit a7c36a7

Please sign in to comment.