Skip to content
Open
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
5 changes: 5 additions & 0 deletions Sources/Runtime/Metadata/ClassMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ struct AnyClassMetadata {
pointer = unsafeBitCast(type, to: UnsafeMutablePointer<AnyClassMetadataLayout>.self)
}

@_disfavoredOverload
init<T: ~Copyable>(type: T.Type) {
pointer = unsafeBitCast(type, to: UnsafeMutablePointer<AnyClassMetadataLayout>.self)
}

func asClassMetadata() -> ClassMetadata? {
guard pointer.pointee.isSwiftClass else {
return nil
Expand Down
5 changes: 5 additions & 0 deletions Sources/Runtime/Metadata/Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

@_disfavoredOverload
func metadataPointer<T: ~Copyable>(type: T.Type) -> UnsafeMutablePointer<Int> {
return unsafeBitCast(type, to: UnsafeMutablePointer<Int>.self)
}

func metadataPointer(type: Any.Type) -> UnsafeMutablePointer<Int> {
return unsafeBitCast(type, to: UnsafeMutablePointer<Int>.self)
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/Runtime/Metadata/MetadataType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ protocol MetadataInfo {
var stride: Int { get }

init(type: Any.Type)

@_disfavoredOverload
init<T: ~Copyable>(type: T.Type)
}

protocol MetadataType: MetadataInfo, TypeInfoConvertible {
Expand All @@ -45,6 +48,11 @@ extension MetadataType {
self = Self(pointer: unsafeBitCast(type, to: UnsafeMutablePointer<Layout>.self))
}

@_disfavoredOverload
init<T: ~Copyable>(type: T.Type) {
self = Self(pointer: unsafeBitCast(type, to: UnsafeMutablePointer<Layout>.self))
}

var type: Any.Type {
return unsafeBitCast(pointer, to: Any.Type.self)
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Runtime/Models/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ enum RuntimeError: Error {
case noPropertyNamed(name: String)
case unableToBuildType(type: Any.Type)
case errorGettingValue(name: String, type: Any.Type)
case unsupportedNoncopyableType
}
6 changes: 6 additions & 0 deletions Sources/Runtime/Models/Kind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ public enum Kind {
self.init(flag: pointer.pointee)
}

@_disfavoredOverload
init<T: ~Copyable>(type: T.Type) {
let pointer = metadataPointer(type: type)
self.init(flag: pointer.pointee)
}

struct Flags {
static let kindIsNonHeap = 0x200
static let kindIsRuntimePrivate = 0x100
Expand Down
15 changes: 15 additions & 0 deletions Sources/Runtime/Models/TypeInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ public struct TypeInfo {
}
}

@_disfavoredOverload
public func typeInfo<T: ~Copyable>(of type: T.Type) throws -> TypeInfo {
let kind = Kind(type: type)
var typeInfoConvertible: TypeInfoConvertible
switch kind {
case .struct:
typeInfoConvertible = StructMetadata(type: type)
case .enum, .optional:
typeInfoConvertible = EnumMetadata(type: type)
default:
throw RuntimeError.unsupportedNoncopyableType
}
return typeInfoConvertible.toTypeInfo()
}

public func typeInfo(of type: Any.Type) throws -> TypeInfo {
let kind = Kind(type: type)

Expand Down
37 changes: 37 additions & 0 deletions Tests/RuntimeTests/MetadataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,33 @@ class MetadataTests: XCTestCase {
XCTAssert(info.cases[0].name == "some")
XCTAssert(info.cases[1].name == "none")
}

func testNonCopyableStruct() throws {
let info = try typeInfo(of: NoncopyableCountry.self)
let name = try info.property(named: "name")
XCTAssert(name.name == "name")
XCTAssert(name.type == String.self)
let population = try info.property(named: "population")
XCTAssert(population.name == "population")
XCTAssert(population.type == Int.self)
XCTAssert(info.properties.count == 2)
}

func testNonCopyableEnum() throws {
let info = try typeInfo(of: NoncopyableColor.self)
XCTAssert(info.cases[0].name == "red")
XCTAssert(info.cases[1].name == "blue")
XCTAssert(info.cases.count == 2)
}

func testNonCopyableOptionals() throws {
let info1 = try typeInfo(of: NoncopyableCountry?.self)
XCTAssert(info1.cases[0].name == "some")
XCTAssert(info1.cases[1].name == "none")
let info2 = try typeInfo(of: NoncopyableColor?.self)
XCTAssert(info2.cases[0].name == "some")
XCTAssert(info2.cases[1].name == "none")
}
}

fileprivate enum MyEnum<T>: Int {
Expand Down Expand Up @@ -278,3 +305,13 @@ fileprivate struct MyStruct<T> {
var c: String
var d: T
}

fileprivate enum NoncopyableColor: ~Copyable {
case red
case blue
}

fileprivate struct NoncopyableCountry: ~Copyable {
var name: String
var population: Int
}