Skip to content
Draft
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions Runtimes/Core/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ add_library(swiftCore
BidirectionalCollection.swift
Bitset.swift
Bool.swift
Box.swift
BridgeObjectiveC.swift
BridgeStorage.swift
BridgingBuffer.swift
Expand Down
111 changes: 111 additions & 0 deletions stdlib/public/core/Box.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 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
//
//===----------------------------------------------------------------------===//

/// A smart pointer type that uniquely owns an instance of `Value` on the heap.
@available(SwiftStdlib 6.4, *)
@frozen
@safe
public struct Box<Value: ~Copyable>: ~Copyable {
@usableFromInline
let pointer: UnsafeMutablePointer<Value>

/// Initializes a value of this box with the given initial value.
///
/// - Parameter initialValue: The initial value to initialize the box with.
@available(SwiftStdlib 6.4, *)
@_alwaysEmitIntoClient
@_transparent
public init(_ initialValue: consuming Value) {
unsafe pointer = UnsafeMutablePointer<Value>.allocate(capacity: 1)
unsafe pointer.initialize(to: initialValue)
}

@_alwaysEmitIntoClient
@_transparent
deinit {
unsafe pointer.deinitialize(count: 1)
unsafe pointer.deallocate()
}
}

@available(SwiftStdlib 6.4, *)
extension Box: Sendable where Value: Sendable & ~Copyable {}

@available(SwiftStdlib 6.4, *)
extension Box where Value: ~Copyable {
/// Dereferences the box allowing for in-place reads and writes to the stored
/// `Value`.
@available(SwiftStdlib 6.4, *)
@_alwaysEmitIntoClient
public var value: Value {
@_transparent
@_unsafeSelfDependentResult
borrow {
unsafe pointer.pointee
}

@_transparent
@_unsafeSelfDependentResult
mutate {
&(unsafe pointer).pointee
}
}

/// Consumes the box and returns the instance of `Value` that was within the
/// box.
@available(SwiftStdlib 6.4, *)
@_alwaysEmitIntoClient
@_transparent
public consuming func consume() -> Value {
let result = unsafe pointer.move()
unsafe pointer.deallocate()
discard self
return result
}
}

@available(SwiftStdlib 6.4, *)
extension Box where Value: ~Copyable {
/// Returns a single element span reference to the instance of `Value` stored
/// within this box.
@available(SwiftStdlib 6.4, *)
@_alwaysEmitIntoClient
public var span: Span<Value> {
@lifetime(borrow self)
@_transparent
get {
unsafe Span(_unsafeStart: pointer, count: 1)
}
}

/// Returns a single element mutable span reference to the instance of `Value`
/// stored within this box.
@available(SwiftStdlib 6.4, *)
@_alwaysEmitIntoClient
public var mutableSpan: MutableSpan<Value> {
@lifetime(&self)
@_transparent
mutating get {
unsafe MutableSpan(_unsafeStart: pointer, count: 1)
}
}
}

@available(SwiftStdlib 6.4, *)
extension Box where Value: Copyable {
/// Copies the value within the box and returns it in a new box instance.
@available(SwiftStdlib 6.4, *)
@_alwaysEmitIntoClient
public func clone() -> Box<Value> {
Box(value)
}
}
2 changes: 2 additions & 0 deletions stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ split_embedded_sources(
EMBEDDED BidirectionalCollection.swift
EMBEDDED Bitset.swift
EMBEDDED Bool.swift
EMBEDDED Box.swift
NORMAL BridgeObjectiveC.swift
EMBEDDED BridgeStorage.swift
NORMAL BridgingBuffer.swift
Expand Down Expand Up @@ -340,6 +341,7 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "ValueGene
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AddressableParameters")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AddressableTypes")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AllowUnsafeAttribute")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BorrowAndMutateAccessors")
list(APPEND swift_stdlib_compile_flags "-strict-memory-safety")

if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "")
Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/core/GroupInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@
"EmbeddedStubs.swift",
"EmbeddedPrint.swift",
"InlineArray.swift",
"_InlineArray.swift"
"_InlineArray.swift",
"Box.swift"
],
"Result": [
"Result.swift"
Expand Down
107 changes: 107 additions & 0 deletions test/stdlib/Noncopyables/Box.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// RUN: %empty-directory(%t)
// RUN: %target-run-simple-swift | %FileCheck %s
// REQUIRES: executable_test

// CHECK: Start
print("Start")

struct Foo: ~Copyable {
func idk() -> String {
"idk"
}

deinit {
print("foo")
}
}

@available(SwiftStdlib 6.4, *)
func basic() {
var intBox = Box(123)

// CHECK: 123
print(intBox.value)

intBox.value += 321

// CHECK: 444
print(intBox.value)
}

@available(SwiftStdlib 6.4, *)
func noncopyable() {
let fooBox = Box(Foo())

// CHECK: bar
print("bar")

// CHECK: foo
}

@available(SwiftStdlib 6.4, *)
func consume() {
func help() -> Foo {
let fooBox = Box(Foo())

let foo = fooBox.consume()

// CHECK: bar
print("bar")

return foo
}

_ = help()

// CHECK: foo
}

@available(SwiftStdlib 6.4, *)
func span() {
let fooBox = Box(Foo())

let fooSpan = fooBox.span

// CHECK: 1
print(fooSpan.count)

// CHECK: idk
print(fooSpan[0].idk())
}

@available(SwiftStdlib 6.4, *)
func mutableSpan() {
var intBox = Box(123)

let intSpan = intBox.mutableSpan

// CHECK: 1
print(intSpan.count)

// CHECK: 123
print(intSpan[0])
}

@available(SwiftStdlib 6.4, *)
func clone() {
var intBox = Box(8)
var cloneIntBox = intBox.clone()

intBox.value += 8
cloneIntBox.value -= 8

// CHECK: 16
print(intBox.value)

// CHECK: 0
print(cloneIntBox.value)
}

if #available(SwiftStdlib 6.4, *) {
basic()
noncopyable()
consume()
span()
mutableSpan()
clone()
}