File tree Expand file tree Collapse file tree 2 files changed +47
-0
lines changed Expand file tree Collapse file tree 2 files changed +47
-0
lines changed Original file line number Diff line number Diff line change @@ -175,4 +175,23 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
175175 yield & self . _value
176176 }
177177 }
178+
179+ /// Safely access and potentially modify the contained value with a closure.
180+ ///
181+ /// This method provides a way to perform operations on the contained value while ensuring
182+ /// thread safety through EventLoop verification. The closure receives an `inout` parameter
183+ /// allowing both read and write access to the value.
184+ ///
185+ /// - Parameter handler: A closure that receives an `inout` reference to the contained value.
186+ /// The closure can read from and write to this value. Any modifications made within the
187+ /// closure will be reflected in the box after the closure completes, even if the closure throws.
188+ /// - Returns: The value returned by the `handler` closure.
189+ /// - Note: This method is particularly useful when you need to perform read and write operations
190+ /// on the value because it reduces the on EventLoop checks.
191+ public func withValue< T, E: Error > ( _ handler: ( inout Value ) throws ( E ) -> T ) throws ( E) -> T {
192+ self . eventLoop. preconditionInEventLoop ( )
193+ var value = self . _value
194+ defer { self . _value = value }
195+ return try handler ( & value)
196+ }
178197}
Original file line number Diff line number Diff line change @@ -116,6 +116,34 @@ final class NIOLoopBoundTests: XCTestCase {
116116 XCTAssertTrue ( loopBoundBox. value. mutateInPlace ( ) )
117117 }
118118
119+ func testWithValue( ) {
120+ var expectedValue = 0
121+ let loopBound = NIOLoopBoundBox ( expectedValue, eventLoop: loop)
122+ for value in 1 ... 100 {
123+ loopBound. withValue { boundValue in
124+ XCTAssertEqual ( boundValue, expectedValue)
125+ boundValue = value
126+ expectedValue = value
127+ }
128+ }
129+ XCTAssertEqual ( 100 , loopBound. value)
130+ }
131+
132+ func testWithValueRethrows( ) {
133+ struct TestError : Error { }
134+
135+ let loopBound = NIOLoopBoundBox ( 0 , eventLoop: loop)
136+ XCTAssertThrowsError (
137+ try loopBound. withValue { boundValue in
138+ XCTAssertEqual ( 0 , boundValue)
139+ boundValue = 10
140+ throw TestError ( )
141+ }
142+ )
143+
144+ XCTAssertEqual ( 10 , loopBound. value, " Ensure value is set even if we throw " )
145+ }
146+
119147 // MARK: - Helpers
120148 func sendableBlackhole< S: Sendable > ( _ sendableThing: S ) { }
121149
You can’t perform that action at this time.
0 commit comments