Repository: apple/swift-nio
File: Sources/NIOCore/NIOLoopBound.swift (Swift)

Code before:
        // _off_ the ``EventLoop`` and transport it _to_ the ``EventLoop``. That would be illegal.
        eventLoop.preconditionInEventLoop()
        self.init(_value: value, uncheckedEventLoop: eventLoop)
    }

    /// Initialise a ``NIOLoopBoundBox`` that is empty (contains `nil`), this does _not_ require you to be running on `eventLoop`.
    public static func makeEmptyBox<NonOptionalValue>(
        valueType: NonOptionalValue.Type = NonOptionalValue.self,
        eventLoop: EventLoop
    ) -> NIOLoopBoundBox<Value> where Optional<NonOptionalValue> == Value {
        // Here, we -- possibly surprisingly -- do not precondition being on the EventLoop. This is okay for a few
        // reasons:
        // - We write the `Optional.none` value which we know is _not_ a value of the potentially non-Sendable type
        //   `Value`.
        // - Because of Swift's Definitive Initialisation (DI), we know that we did write `self._value` before `init`
        //   returns.
        // - The only way to ever write (or read indeed) `self._value` is by proving to be inside the `EventLoop`.
        return .init(_value: nil, uncheckedEventLoop: eventLoop)
    }

    /// Initialise a ``NIOLoopBoundBox`` by sending a ``Sendable`` value, validly callable off `eventLoop`.
    ///
    /// Contrary to ``init(_:eventLoop:)``, this method can be called off `eventLoop` because we know that `value` is ``Sendable``.
    /// So we don't need to protect `value` itself, we just need to protect the ``NIOLoopBoundBox`` against mutations which we do because the ``value``
    /// accessors are checking that we're on `eventLoop`.
    public static func makeBoxSendingValue(
        _ value: Value,
        as: Value.Type = Value.self,
        eventLoop: EventLoop
    ) -> NIOLoopBoundBox<Value> where Value: Sendable {
        // Here, we -- possibly surprisingly -- do not precondition being on the EventLoop. This is okay for a few
        // reasons:
        // - This function only works with `Sendable` values, so we don't need to worry about somebody
        //   still holding a reference to this.
        // - Because of Swift's Definitive Initialisation (DI), we know that we did write `self._value` before `init`
        //   returns.
        // - The only way to ever write (or read indeed) `self._value` is by proving to be inside the `EventLoop`.
        return .init(_value: value, uncheckedEventLoop: eventLoop)
    }

    /// Access the `value` with the precondition that the code is running on `eventLoop`.
    ///
    /// - note: ``NIOLoopBoundBox`` itself is reference-typed, so any writes will affect anybody sharing this reference.
    @inlinable
    public var value: Value {
        get {
            self._eventLoop.preconditionInEventLoop()
            return self._value
        }
        set {
            self._eventLoop.preconditionInEventLoop()

Review comment (suggestion):
I find it weird to use a factory method here personally. I would prefer using an init here. I also see little value in having this constrained to `Sendable` since `Sendable` types can freely be shared between threads.

I expected a spelling like this

```
init(value: sending Value, eventLoop: any EventLoop) {}
```

This would allow moving an non-Sendable value into an EL's isolation region which is dynamically enforced by the LoopBoundBox. 

Code after:
        // _off_ the ``EventLoop`` and transport it _to_ the ``EventLoop``. That would be illegal.
        eventLoop.preconditionInEventLoop()
        self.init(_value: value, uncheckedEventLoop: eventLoop)
    }

    /// Initialise a ``NIOLoopBoundBox`` that is empty (contains `nil`), this does _not_ require you to be running on `eventLoop`.
    public static func makeEmptyBox<NonOptionalValue>(
        valueType: NonOptionalValue.Type = NonOptionalValue.self,
        eventLoop: EventLoop
    ) -> NIOLoopBoundBox<Value> where Optional<NonOptionalValue> == Value {
        // Here, we -- possibly surprisingly -- do not precondition being on the EventLoop. This is okay for a few
        // reasons:
        // - We write the `Optional.none` value which we know is _not_ a value of the potentially non-Sendable type
        //   `Value`.
        // - Because of Swift's Definitive Initialisation (DI), we know that we did write `self._value` before `init`
        //   returns.
        // - The only way to ever write (or read indeed) `self._value` is by proving to be inside the `EventLoop`.
        return .init(_value: nil, uncheckedEventLoop: eventLoop)
    }

    /// Initialise a ``NIOLoopBoundBox`` by sending a `Sendable` value, validly callable off `eventLoop`.
    ///
    /// Contrary to ``init(_:eventLoop:)``, this method can be called off `eventLoop` because we know that `value` is `Sendable`.
    /// So we don't need to protect `value` itself, we just need to protect the ``NIOLoopBoundBox`` against mutations which we do because the ``value``
    /// accessors are checking that we're on `eventLoop`.
    public static func makeBoxSendingValue(
        _ value: Value,
        as: Value.Type = Value.self,
        eventLoop: EventLoop
    ) -> NIOLoopBoundBox<Value> where Value: Sendable {
        // Here, we -- possibly surprisingly -- do not precondition being on the EventLoop. This is okay for a few
        // reasons:
        // - This function only works with `Sendable` values, so we don't need to worry about somebody
        //   still holding a reference to this.
        // - Because of Swift's Definitive Initialisation (DI), we know that we did write `self._value` before `init`
        //   returns.
        // - The only way to ever write (or read indeed) `self._value` is by proving to be inside the `EventLoop`.
        return .init(_value: value, uncheckedEventLoop: eventLoop)
    }

    /// Access the `value` with the precondition that the code is running on `eventLoop`.
    ///
    /// - note: ``NIOLoopBoundBox`` itself is reference-typed, so any writes will affect anybody sharing this reference.
    @inlinable
    public var value: Value {
        get {
            self._eventLoop.preconditionInEventLoop()
            return self._value
        }
        set {
            self._eventLoop.preconditionInEventLoop()