Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions Sources/NIOCore/NIOLoopBound.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ public struct NIOLoopBound<Value>: @unchecked Sendable {
self._value = value
}

/// Initialise a ``NIOLoopBound`` to `value` with the assertion that the code is running on `eventLoop`.
///
/// - Note: This is an unchecked variant of ``init(_:eventLoop:)`` that only asserts in debug mode.
@inlinable
public init(uncheckedOnEventLoop value: Value, eventLoop: EventLoop) {
eventLoop.assertInEventLoop()
self.eventLoop = eventLoop
self._value = value
}

/// Access the `value` with the precondition that the code is running on `eventLoop`.
///
/// - Note: ``NIOLoopBound`` itself is value-typed, so any writes will only affect the current value.
Expand All @@ -58,6 +68,22 @@ public struct NIOLoopBound<Value>: @unchecked Sendable {
yield &self._value
}
}

/// Access the `value` with the assertion that the code is running on `eventLoop`.
///
/// - Note: ``NIOLoopBound`` itself is value-typed, so any writes will only affect the current value.
/// - Note: This is an unchecked variant of ``value`` that only asserts in debug mode.
@inlinable
public var uncheckedUnsafeValue: Value {
get {
self.eventLoop.assertInEventLoop()
return self._value
}
_modify {
self.eventLoop.assertInEventLoop()
yield &self._value
}
}
}

/// ``NIOLoopBoundBox`` is an always-`Sendable`, reference-typed container allowing you access to ``value`` if and
Expand Down Expand Up @@ -104,6 +130,15 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
self.init(_value: value, uncheckedEventLoop: eventLoop)
}

/// Initialise a ``NIOLoopBoundBox`` to `value` with the assertion that the code is running on `eventLoop`.
///
/// - Note: This is an unchecked variant of ``init(_:eventLoop:)`` that only asserts in debug mode.
@inlinable
public convenience init(uncheckedOnEventLoop value: Value, eventLoop: EventLoop) {
eventLoop.assertInEventLoop()
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,
Expand Down Expand Up @@ -174,6 +209,22 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
}
}

/// Access the `value` with the assertion that the code is running on `eventLoop`.
///
/// - Note: ``NIOLoopBoundBox`` itself is reference-typed, so any writes will affect anybody sharing this reference.
/// - Note: This is an unchecked variant of ``value`` that only asserts in debug mode.
@inlinable
public var uncheckedUnsafeValue: Value {
get {
self.eventLoop.assertInEventLoop()
return self._value
}
_modify {
self.eventLoop.assertInEventLoop()
yield &self._value
}
}

/// Safely access and potentially modify the contained value with a closure.
///
/// This method provides a way to perform operations on the contained value while ensuring
Expand All @@ -193,4 +244,25 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
self.eventLoop.preconditionInEventLoop()
return try handler(&self._value)
}

/// Safely access and potentially modify the contained value with a closure.
///
/// This method provides a way to perform operations on the contained value while ensuring
/// thread safety through EventLoop verification. The closure receives an `inout` parameter
/// allowing both read and write access to the value.
///
/// - Parameter handler: A closure that receives an `inout` reference to the contained value.
/// The closure can read from and write to this value. Any modifications made within the
/// closure will be reflected in the box after the closure completes, even if the closure throws.
/// - Returns: The value returned by the `handler` closure.
/// - Note: This method is particularly useful when you need to perform read and write operations
/// on the value because it reduces the on EventLoop checks.
/// - Note: This is an unchecked variant of ``withValue(_:)`` that only asserts in debug mode.
@inlinable
public func withUncheckedUnsafeValue<Success, Failure: Error>(
_ handler: (inout Value) throws(Failure) -> Success
) throws(Failure) -> Success {
self.eventLoop.assertInEventLoop()
return try handler(&self._value)
}
}