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