blob: b404eaacb544a2d64224b591177453e07e2bfb44 [file] [log] [blame] [edit]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import '../code_generator.dart';
import '../visitor/ast.dart';
import 'writer.dart';
/// Represents a pointer.
class PointerType extends Type {
final Type child;
PointerType._(this.child);
factory PointerType(Type child) {
if (child == objCObjectType) {
return ObjCObjectPointer();
} else if (child == objCBlockType) {
return ObjCBlockPointer();
}
return PointerType._(child);
}
@override
Type get baseType => child.baseType;
@override
String getCType(Writer w) =>
'${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
@override
String getNativeType({String varName = ''}) =>
'${child.getNativeType()}* $varName';
// Both the C type and the FFI Dart type are 'Pointer<$cType>'.
@override
bool get sameFfiDartAndCType => true;
@override
String toString() => '$child*';
@override
String cacheKey() => '${child.cacheKey()}*';
@override
void visitChildren(Visitor visitor) {
super.visitChildren(visitor);
visitor.visit(child);
}
@override
void visit(Visitation visitation) => visitation.visitPointerType(this);
@override
bool isSupertypeOf(Type other) {
other = other.typealiasType;
if (other is PointerType) {
return child.isSupertypeOf(other.child);
}
return false;
}
}
/// Represents a constant array, which has a fixed size.
class ConstantArray extends PointerType {
final int length;
final bool useArrayType;
ConstantArray(this.length, Type child, {required this.useArrayType})
: super._(child);
@override
Type get baseArrayType => child.baseArrayType;
@override
bool get isIncompleteCompound => baseArrayType.isIncompleteCompound;
@override
String getNativeType({String varName = ''}) =>
'${child.getNativeType()} $varName[$length]';
@override
String toString() => '$child[$length]';
@override
String cacheKey() => '${child.cacheKey()}[$length]';
@override
String getCType(Writer w) {
if (useArrayType) {
return '${w.ffiLibraryPrefix}.Array<${child.getCType(w)}>';
}
return super.getCType(w);
}
}
/// Represents an incomplete array, which has an unknown size.
class IncompleteArray extends PointerType {
IncompleteArray(super.child) : super._();
@override
Type get baseArrayType => child.baseArrayType;
@override
String getNativeType({String varName = ''}) =>
'${child.getNativeType()}* $varName';
@override
String toString() => '$child[]';
@override
String cacheKey() => '${child.cacheKey()}[]';
}
/// A pointer to an Objective C object.
class ObjCObjectPointer extends PointerType {
factory ObjCObjectPointer() => _inst;
static final _inst = ObjCObjectPointer._();
ObjCObjectPointer.__(super.child) : super._();
ObjCObjectPointer._() : super._(objCObjectType);
@override
String getDartType(Writer w) => '${w.objcPkgPrefix}.ObjCObjectBase';
@override
String getNativeType({String varName = ''}) => 'id $varName';
@override
bool get sameDartAndCType => false;
@override
bool get sameDartAndFfiDartType => false;
@override
String convertDartTypeToFfiDartType(
Writer w,
String value, {
required bool objCRetain,
required bool objCAutorelease,
}) => ObjCInterface.generateGetId(value, objCRetain, objCAutorelease);
@override
String convertFfiDartTypeToDartType(
Writer w,
String value, {
required bool objCRetain,
String? objCEnclosingClass,
}) => '${getDartType(w)}($value, retain: $objCRetain, release: true)';
@override
String? generateRetain(String value) =>
'(__bridge id)(__bridge_retained void*)($value)';
@override
bool isSupertypeOf(Type other) {
other = other.typealiasType;
// id/Object* is a supertype of all ObjC objects and blocks.
return other is ObjCObjectPointer ||
other is ObjCInterface ||
other is ObjCBlock;
}
}
/// A pointer to an Objective C block.
class ObjCBlockPointer extends ObjCObjectPointer {
factory ObjCBlockPointer() => _inst;
static final _inst = ObjCBlockPointer._();
ObjCBlockPointer._() : super.__(objCBlockType);
@override
String getDartType(Writer w) => '${w.objcPkgPrefix}.ObjCBlockBase';
@override
String? generateRetain(String value) => 'objc_retainBlock($value)';
@override
bool isSupertypeOf(Type other) {
other = other.typealiasType;
return other is ObjCBlockPointer || other is ObjCBlock;
}
}
/// A pointer to an Objective C object with protocols.
class ObjCObjectPointerWithProtocols extends ObjCObjectPointer {
List<ObjCProtocol> protocols;
ObjCObjectPointerWithProtocols(this.protocols)
: assert(protocols.isNotEmpty),
super._();
@override
String getDartType(Writer w) => protocols.first.getDartType(w);
@override
bool isSupertypeOf(Type other) {
other = other.typealiasType;
if (other is ObjCObjectPointerWithProtocols) {
// The "correct" logic would be to return true if each of our protocols
// was a supertype of one of the other's protocols. But this method is
// designed to reflect the subtyping rules of the *Dart bindings*, not the
// ObjC types. So since the codegen just uses the first protocol, we do
// the same here.
return protocols.first.isSupertypeOf(other.protocols.first);
}
return false;
}
@override
String toString() => 'id<${protocols.join(', ')}>';
@override
String cacheKey() => 'id<${protocols.map((p) => p.cacheKey()).join(', ')}>';
@override
String convertFfiDartTypeToDartType(
Writer w,
String value, {
required bool objCRetain,
String? objCEnclosingClass,
}) => protocols.first.convertFfiDartTypeToDartType(
w,
value,
objCRetain: objCRetain,
objCEnclosingClass: objCEnclosingClass,
);
@override
void visitChildren(Visitor visitor) {
super.visitChildren(visitor);
visitor.visitAll(protocols);
}
}