Preserve references for full-transfer object parameters
This commit is contained in:
parent
2422737865
commit
14072c5df6
7 changed files with 153 additions and 22 deletions
|
|
@ -25,6 +25,24 @@ struct RendererCallableTests {
|
|||
let registry = TypeRegistry(repositories: ["GObject": gobject])
|
||||
return MapContext(registry: registry, currentModule: "GObject", currentNamespace: "GObject")
|
||||
}
|
||||
/// Builds a context with an ordinary GObject and a non-GObject
|
||||
/// fundamental class that declares its own ref function.
|
||||
func makeTransferContext() -> MapContext {
|
||||
let gobject = Repository(namespaces: [
|
||||
Namespace(
|
||||
name: "GObject", version: "2.0",
|
||||
classes: [
|
||||
Class(name: "Object", cType: "GObject", parent: nil,
|
||||
getTypeFunction: "g_object_get_type"),
|
||||
Class(name: "Expr", cType: "GExpr", parent: nil,
|
||||
getTypeFunction: "g_expr_get_type",
|
||||
refFunc: "g_expr_ref", unrefFunc: "g_expr_unref"),
|
||||
]
|
||||
)
|
||||
])
|
||||
let registry = TypeRegistry(repositories: ["GObject": gobject])
|
||||
return MapContext(registry: registry, currentModule: "GObject", currentNamespace: "GObject")
|
||||
}
|
||||
|
||||
func renderCallable(_ plan: CallablePlan) -> String {
|
||||
let module = ModulePlan(
|
||||
|
|
@ -88,6 +106,64 @@ struct RendererCallableTests {
|
|||
#expect(!body.contains("@_spi(SGTKInternal) public func getDefaultObject"))
|
||||
}
|
||||
|
||||
// MARK: - transfer-ownership="full" object in-parameters
|
||||
|
||||
@Test("transfer-full object in-param refs before the call; transfer-none does not")
|
||||
func transferFullObjectParamAddsRef() throws {
|
||||
let ctx = makeTransferContext()
|
||||
let borrowed = GlobalFunction(
|
||||
name: "set_thing", cIdentifier: "g_set_thing",
|
||||
parameters: [Parameter(name: "thing", type: .typeRef("Object", namespace: "GObject"),
|
||||
cType: "GObject*", transferOwnership: .none)],
|
||||
returnValue: ReturnValue(type: .void))
|
||||
let consumed = GlobalFunction(
|
||||
name: "take_thing", cIdentifier: "g_take_thing",
|
||||
parameters: [Parameter(name: "thing", type: .typeRef("Object", namespace: "GObject"),
|
||||
cType: "GObject*", transferOwnership: .full)],
|
||||
returnValue: ReturnValue(type: .void))
|
||||
guard case .success(let borrowedPlan) = planFunction(borrowed, context: ctx),
|
||||
case .success(let consumedPlan) = planFunction(consumed, context: ctx) else {
|
||||
Issue.record("expected both functions to plan successfully")
|
||||
return
|
||||
}
|
||||
#expect(renderCallable(borrowedPlan).contains(
|
||||
"g_set_thing(_instancePointer(thing.pointer))"))
|
||||
#expect(renderCallable(consumedPlan).contains(
|
||||
"g_take_thing(_instancePointer(_rawPointer(g_object_ref(_instancePointer(thing.pointer)))))"))
|
||||
}
|
||||
|
||||
@Test("transfer-full nullable object in-param refs inside the map closure")
|
||||
func transferFullNullableObjectParamRefsInsideMap() throws {
|
||||
let fn = GlobalFunction(
|
||||
name: "take_maybe", cIdentifier: "g_take_maybe",
|
||||
parameters: [Parameter(name: "thing", type: .typeRef("Object", namespace: "GObject"),
|
||||
cType: "GObject*", isNullable: true, transferOwnership: .full)],
|
||||
returnValue: ReturnValue(type: .void))
|
||||
guard case .success(let plan) = planFunction(fn, context: makeTransferContext()) else {
|
||||
Issue.record("expected g_take_maybe to plan successfully")
|
||||
return
|
||||
}
|
||||
#expect(renderCallable(plan).contains(
|
||||
"thing.map { _instancePointer(_rawPointer(g_object_ref(_instancePointer($0.pointer)))) }"))
|
||||
}
|
||||
|
||||
@Test("transfer-full param of a non-GObject fundamental uses its own ref function")
|
||||
func transferFullFundamentalUsesOwnRefFunction() throws {
|
||||
let fn = GlobalFunction(
|
||||
name: "take_expr", cIdentifier: "g_take_expr",
|
||||
parameters: [Parameter(name: "expr", type: .typeRef("Expr", namespace: "GObject"),
|
||||
cType: "GExpr*", transferOwnership: .full)],
|
||||
returnValue: ReturnValue(type: .void))
|
||||
guard case .success(let plan) = planFunction(fn, context: makeTransferContext()) else {
|
||||
Issue.record("expected g_take_expr to plan successfully")
|
||||
return
|
||||
}
|
||||
let body = renderCallable(plan)
|
||||
#expect(body.contains(
|
||||
"g_take_expr(_instancePointer(_rawPointer(g_expr_ref(_instancePointer(expr.pointer)))))"))
|
||||
#expect(!body.contains("g_object_ref"))
|
||||
}
|
||||
|
||||
// MARK: - C3: Out-param tuples
|
||||
|
||||
@Test("Single out-param with no Swift return becomes the out-param's type")
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ struct TypeMapperTests {
|
|||
nullable: false, transfer: .none, context: ctx)
|
||||
#expect(mapping.swiftType == "Object")
|
||||
#expect(mapping.cSwiftType == "UnsafeMutableRawPointer?")
|
||||
#expect(mapping.marshalIn == .objectPointer)
|
||||
#expect(mapping.marshalIn == .objectPointer(consumingRefFunction: nil))
|
||||
#expect(mapping.marshalOut == .objectRetain)
|
||||
}
|
||||
|
||||
|
|
@ -314,6 +314,7 @@ struct TypeMapperTests {
|
|||
let ctx = makeContext()
|
||||
let mapping = try map(.typeRef("Object", namespace: "GObject"),
|
||||
nullable: false, transfer: .full, context: ctx)
|
||||
#expect(mapping.marshalIn == .objectPointer(consumingRefFunction: "g_object_ref"))
|
||||
#expect(mapping.marshalOut == .objectWrap(sink: false))
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +332,7 @@ struct TypeMapperTests {
|
|||
let mapping = try map(.typeRef("TypePlugin", namespace: "GObject"),
|
||||
nullable: false, transfer: .none, context: ctx)
|
||||
#expect(mapping.swiftType == "TypePlugin")
|
||||
#expect(mapping.marshalIn == .interfacePointer)
|
||||
#expect(mapping.marshalIn == .interfacePointer(consumingRefFunction: nil))
|
||||
#expect(mapping.marshalOut == .interfaceWrap(adopt: false))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue