//===--- OutputSpanTests.swift --------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // RUN: %target-run-stdlib-swift // REQUIRES: executable_test import StdlibUnittest var suite = TestSuite("OutputSpan Tests") defer { runAllTests() } @available(SwiftStdlib 6.2, *) struct Allocation: ~Copyable { let allocation: UnsafeMutableBufferPointer var count: Int? = nil init(of count: Int = 1, _ t: T.Type) { precondition(count >= 0) allocation = .allocate(capacity: count) } var isEmpty: Bool { (count ?? 0) == 0 } mutating func initialize( _ body: (inout OutputSpan) throws(E) -> Void ) throws(E) { if count != nil { fatalError() } var allocation = allocation if allocation.count == 0 { allocation = .init(start: nil, count: 0) } var outputBuffer = OutputSpan(buffer: allocation, initializedCount: 0) do { try body(&outputBuffer) let initialized = outputBuffer.finalize(for: allocation) count = initialized } catch { outputBuffer.removeAll() let initialized = outputBuffer.finalize(for: allocation) assert(initialized == 0) throw error } } borrowing func withSpan( _ body: (borrowing Span) throws(E) -> R ) throws(E) -> R { try body(Span(_unsafeElements: allocation[0...allocate(capacity: c) defer { allocation.deallocate() } let ob = unsafe OutputSpan(buffer: allocation, initializedCount: 0) let initialized = ob.finalize(for: allocation) expectEqual(initialized, 0) } suite.test("deinit without relinquishing memory") .require(.stdlib_6_2).code { guard #available(SwiftStdlib 6.2, *) else { return } let c = 48 let allocation = UnsafeMutableBufferPointer.allocate(capacity: c) defer { allocation.deallocate() } var ob = unsafe OutputSpan(buffer: allocation, initializedCount: 0) // OutputSpan(buffer: Slice(base: allocation, bounds: 0...allocate(capacity: capacity) defer { b.deallocate() } _ = b.initialize(fromContentsOf: 0...allocate(capacity: capacity) defer { b.deallocate() } _ = b.initialize(fromContentsOf: 0.. 0) throw MyTestError.error } } catch MyTestError.error { expectEqual(a.isEmpty, true) } catch { expectTrue(false) } a = Allocation(of: 0, Int.self) do { try a.initialize { expectEqual($0.freeCapacity, 0) throw MyTestError.error } } catch MyTestError.error { expectEqual(a.isEmpty, true) } catch { expectTrue(false) } } suite.test("InlineArray initialization") .require(.stdlib_6_2).code { guard #available(SwiftStdlib 6.2, *) else { return } let i = InlineArray<10, Int> { (o: inout OutputSpan) in expectEqual(o.count, 0) for i in 0.. { $0.append(1) } } suite.test("InlineArray initialization throws") .require(.stdlib_6_2).code { guard #available(SwiftStdlib 6.2, *) else { return } enum LocalError: Error { case error } class I { static var count = 0 init() { Self.count += 1 } deinit { Self.count -= 1 } } let a: InlineArray<4, I> do throws(LocalError) { a = try InlineArray { o throws(LocalError) in o.append(I()) o.append(I()) o.append(I()) o.append(I()) expectEqual(I.count, 4) throw LocalError.error } _ = a } catch { expectEqual(I.count, 0) } }