Commit f0aec36d authored by Jacob Potter's avatar Jacob Potter

Allow interface objects to be implemented in both ObjC and C++.

parent 64fb18b8
......@@ -22,23 +22,6 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
namespace djinni_generated {
auto SortItems::toCpp(ObjcType objc) -> CppType
{
return objc ? objc.cppRef.get() : nullptr;
}
auto SortItems::fromCpp(const CppType& cpp) -> ObjcType
{
return !cpp ? nil : ::djinni::DbxCppWrapperCache<::textsort::SortItems>::getInstance()->get(cpp, [] (const CppType& p)
{
return [[TXSSortItems alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
@implementation TXSSortItems
- (id)initWithCpp:(const std::shared_ptr<::textsort::SortItems>&)cppRef
......@@ -65,3 +48,25 @@ auto SortItems::fromCpp(const CppType& cpp) -> ObjcType
}
@end
namespace djinni_generated {
auto SortItems::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return objc.cppRef.get();
}
auto SortItems::fromCpp(const CppType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::textsort::SortItems>::getInstance()->get(cpp, [] (const CppType& p) {
return [[TXSSortItems alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
......@@ -24,15 +24,24 @@ public:
}
};
} // namespace djinni_generated
namespace djinni_generated {
auto TextboxListener::toCpp(ObjcType objc) -> CppType
{
return objc ? ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc) : nullptr;
if (!objc) {
return nullptr;
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
}
auto TextboxListener::fromCpp(const CppType& cpp) -> ObjcType
{
assert(!cpp || dynamic_cast<ObjcProxy*>(cpp.get()));
return cpp ? static_cast<ObjcProxy&>(*cpp).Handle::get() : nil;
if (!cpp) {
return nil;
}
return dynamic_cast<ObjcProxy&>(*cpp).Handle::get();
}
} // namespace djinni_generated
......@@ -147,7 +147,7 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
w.wl(s";")
}
w.wl
if (i.ext.cpp) w.wl(s"@interface $self : NSObject") else w.wl(s"@protocol $self")
if (i.ext.objc) w.wl(s"@protocol $self") else w.wl(s"@interface $self : NSObject")
for (m <- i.methods) {
w.wl
writeDoc(w, m.doc)
......
......@@ -50,12 +50,12 @@ class ObjcMarshal(spec: Spec) extends Marshal(spec) {
List(ImportRef(q(spec.objcIncludePrefix + headerName(d.name))))
case DInterface =>
val ext = d.body.asInstanceOf[Interface].ext
if (ext.cpp) {
List(ImportRef("<Foundation/Foundation.h>"), DeclRef(s"@class ${typename(d.name, d.body)};", None))
}
else if (ext.objc) {
if (ext.objc) {
List(ImportRef("<Foundation/Foundation.h>"), DeclRef(s"@protocol ${typename(d.name, d.body)};", None))
}
else if (ext.cpp) {
List(ImportRef("<Foundation/Foundation.h>"), DeclRef(s"@class ${typename(d.name, d.body)};", None))
}
else {
List()
}
......
......@@ -111,11 +111,24 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
refs.body.add("#include <utility>")
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIError.h"))
refs.body.add("#include <exception>")
}
if (i.ext.objc) {
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIObjcWrapperCache+Private.h"))
refs.body.add("!#import " + q(spec.objcppIncludePrefix + objcppMarshal.privateHeaderName(ident.name)))
}
writeObjcFile(privateBodyName(ident.name), origin, refs.body, w => {
arcAssert(w)
writeObjcFile(privateBodyName(ident.name), origin, refs.body, w => {
arcAssert(w)
val objcSelf = if (i.ext.objc && i.ext.cpp) self + "CppProxy" else self
if (i.ext.cpp) {
w.wl
w.wl(s"@interface $self ()")
if (i.ext.objc)
w.wl(s"@interface $objcSelf : NSObject<$self>")
else
w.wl(s"@interface $objcSelf ()")
w.wl
w.wl(s"@property (nonatomic, readonly) ::djinni::DbxCppWrapperCache<$cppSelf>::Handle cppRef;")
w.wl
......@@ -123,21 +136,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl
w.wl("@end")
w.wl
wrapNamespace(w, spec.objcppNamespace, w => {
w.wl(s"auto $helperClass::toCpp(ObjcType objc) -> CppType")
w.braced {
w.wl(s"return objc ? objc.cppRef.get() : nullptr;")
}
w.wl
w.wl(s"auto $helperClass::fromCpp(const CppType& cpp) -> ObjcType")
w.braced {
w.wl(s"return !cpp ? nil : ::djinni::DbxCppWrapperCache<$cppSelf>::getInstance()->get(cpp, [] (const CppType& p)").bracedEnd(");") {
w.wl(s"return [[$self alloc] initWithCpp:p];")
}
}
})
w.wl
w.wl(s"@implementation $self")
w.wl(s"@implementation $objcSelf")
w.wl
w.wl(s"- (id)initWithCpp:(const std::shared_ptr<$cppSelf>&)cppRef")
w.braced {
......@@ -161,16 +160,11 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
}
w.wl
w.wl("@end")
})
}
if (i.ext.objc) {
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIObjcWrapperCache+Private.h"))
refs.body.add("!#import " + q(spec.objcppIncludePrefix + objcppMarshal.privateHeaderName(ident.name)))
}
writeObjcFile(privateBodyName(ident.name), origin, refs.body, w => {
arcAssert(w)
if (i.ext.objc) {
w.wl
val objcExtSelf = objcppMarshal.helperClass("objc_proxy")
wrapNamespace(w, spec.objcppNamespace, w => {
w.wl(s"class $helperClass::ObjcProxy final")
w.wl(s": public $cppSelf")
......@@ -192,20 +186,60 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
}
}
}
w.wl
w.wl(s"auto $helperClass::toCpp(ObjcType objc) -> CppType")
w.braced {
w.wl(s"return objc ? ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc) : nullptr;")
})
}
w.wl
wrapNamespace(w, spec.objcppNamespace, w => {
// ObjC-to-C++ coversion
w.wl(s"auto $helperClass::toCpp(ObjcType objc) -> CppType").braced {
// Handle null
w.w("if (!objc)").braced {
w.wl("return nullptr;")
}
w.wl
w.wl(s"auto $helperClass::fromCpp(const CppType& cpp) -> ObjcType")
w.braced {
w.wl(s"assert(!cpp || dynamic_cast<ObjcProxy*>(cpp.get()));")
w.wl(s"return cpp ? static_cast<ObjcProxy&>(*cpp).Handle::get() : nil;")
if (i.ext.cpp && !i.ext.objc) {
// C++ only. In this case we generate a class instead of a protocol, so
// we don't have to do any casting at all, just access cppRef directly.
w.wl(s"return objc.cppRef.get();")
} else {
// ObjC only, or ObjC and C++.
val objcExtSelf = objcppMarshal.helperClass("objc_proxy")
if (i.ext.cpp) {
// If it could be implemented in C++, we might have to unwrap a proxy object.
w.w(s"if ([(id)objc isKindOfClass:[$objcSelf class]])").braced {
w.wl(s"return (($objcSelf*)objc).cppRef.get();")
}
}
w.wl(s"return ::djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance()->get(objc);")
}
})
}
w.wl
w.wl(s"auto $helperClass::fromCpp(const CppType& cpp) -> ObjcType").braced {
// Handle null
w.w("if (!cpp)").braced {
w.wl("return nil;")
}
if (i.ext.objc && !i.ext.cpp) {
// ObjC only. In this case we *must* unwrap a proxy object - the dynamic_cast will
// throw bad_cast if we gave it something of the wrong type.
val objcExtSelf = objcppMarshal.helperClass("objc_proxy")
w.wl(s"return dynamic_cast<$objcExtSelf&>(*cpp).Handle::get();")
} else {
// C++ only, or C++ and ObjC.
if (i.ext.objc) {
// If it could be implemented in ObjC, we might have to unwrap a proxy object.
val objcExtSelf = objcppMarshal.helperClass("objc_proxy")
w.w(s"if (auto cppPtr = dynamic_cast<${objcExtSelf}*>(cpp.get()))").braced {
w.wl("return cppPtr->Handle::get();")
}
}
w.w(s"return ::djinni::DbxCppWrapperCache<$cppSelf>::getInstance()->get(cpp, [] (const CppType& p)").bracedEnd(");") {
w.wl(s"return [[$objcSelf alloc] initWithCpp:p];")
}
}
}
})
}
})
}
override def generateRecord(origin: String, ident: Ident, doc: Doc, params: Seq[TypeParam], r: Record) {
......
......@@ -25,6 +25,7 @@ test_helpers = interface +c {
static create_cpp_token(): token;
static check_cpp_token(t: token);
static cpp_token_id(t: token): i64;
static check_token_type(t: token, type: string);
static return_none(): optional<i32>;
......
token = interface +c +j {
token = interface +c +j +o {
whoami() : string;
}
......@@ -62,6 +62,8 @@ public:
static int64_t cpp_token_id(const std::shared_ptr<Token> & t);
static void check_token_type(const std::shared_ptr<Token> & t, const std::string & type);
static std::experimental::optional<int32_t> return_none();
/** Ensures that we generate integer translation code */
......
......@@ -3,7 +3,11 @@
#pragma once
#include <string>
class Token {
public:
virtual ~Token() {}
virtual std::string whoami() = 0;
};
......@@ -47,6 +47,8 @@ public abstract class TestHelpers {
public static native long cppTokenId(Token t);
public static native void checkTokenType(Token t, String type);
public static native Integer returnNone();
/** Ensures that we generate integer translation code */
......
......@@ -6,6 +6,7 @@ package com.dropbox.djinni.test;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class Token {
public abstract String whoami();
public static final class CppProxy extends Token
{
......@@ -29,5 +30,13 @@ public abstract class Token {
destroy();
super.finalize();
}
@Override
public String whoami()
{
assert !this.destroyed.get() : "trying to use a destroyed object";
return native_whoami(this.nativeRef);
}
private native String native_whoami(long _nativeRef);
}
}
......@@ -202,6 +202,15 @@ CJNIEXPORT jlong JNICALL Java_com_dropbox_djinni_test_TestHelpers_cppTokenId(JNI
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_TestHelpers_checkTokenType(JNIEnv* jniEnv, jobject /*this*/, jobject j_t, jstring j_type)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
::TestHelpers::check_token_type(::djinni_generated::NativeToken::toCpp(jniEnv, j_t),
::djinni::String::toCpp(jniEnv, j_type));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_TestHelpers_returnNone(JNIEnv* jniEnv, jobject /*this*/)
{
try {
......
......@@ -2,6 +2,7 @@
// This file generated by Djinni from token.djinni
#include "NativeToken.hpp" // my header
#include "Marshal.hpp"
namespace djinni_generated {
......@@ -13,6 +14,14 @@ NativeToken::JavaProxy::JavaProxy(JniType j) : JavaProxyCacheEntry(j) { }
NativeToken::JavaProxy::~JavaProxy() = default;
std::string NativeToken::JavaProxy::whoami() {
auto jniEnv = ::djinni::jniGetThreadEnv();
::djinni::JniLocalScope jscope(jniEnv, 10);
const auto& data = ::djinni::JniClass<::djinni_generated::NativeToken>::get();
auto jret = (jstring)jniEnv->CallObjectMethod(getGlobalRef(), data.method_whoami);
::djinni::jniExceptionCheck(jniEnv);
return ::djinni::String::toCpp(jniEnv, jret);
}
CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_Token_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
......@@ -22,4 +31,14 @@ CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_Token_00024CppProxy_nativeD
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
CJNIEXPORT jstring JNICALL Java_com_dropbox_djinni_test_Token_00024CppProxy_native_1whoami(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
const auto& ref = ::djinni::CppProxyHandle<::Token>::get(nativeRef);
auto r = ref->whoami();
return ::djinni::String::fromCpp(jniEnv, r).release();
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
} // namespace djinni_generated
......@@ -31,6 +31,7 @@ private:
JavaProxy(JniType j);
~JavaProxy();
std::string whoami() override;
private:
using ::djinni::JavaProxyCacheEntry::getGlobalRef;
......@@ -39,6 +40,7 @@ private:
};
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/djinni/test/Token") };
const jmethodID method_whoami { ::djinni::jniGetMethodID(clazz.get(), "whoami", "()Ljava/lang/String;") };
};
} // namespace djinni_generated
......@@ -35,15 +35,24 @@ public:
}
};
} // namespace djinni_generated
namespace djinni_generated {
auto ClientInterface::toCpp(ObjcType objc) -> CppType
{
return objc ? ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc) : nullptr;
if (!objc) {
return nullptr;
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
}
auto ClientInterface::fromCpp(const CppType& cpp) -> ObjcType
{
assert(!cpp || dynamic_cast<ObjcProxy*>(cpp.get()));
return cpp ? static_cast<ObjcProxy&>(*cpp).Handle::get() : nil;
if (!cpp) {
return nil;
}
return dynamic_cast<ObjcProxy&>(*cpp).Handle::get();
}
} // namespace djinni_generated
......@@ -19,23 +19,6 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
namespace djinni_generated {
auto ConstantsInterface::toCpp(ObjcType objc) -> CppType
{
return objc ? objc.cppRef.get() : nullptr;
}
auto ConstantsInterface::fromCpp(const CppType& cpp) -> ObjcType
{
return !cpp ? nil : ::djinni::DbxCppWrapperCache<::ConstantsInterface>::getInstance()->get(cpp, [] (const CppType& p)
{
return [[DBConstantsInterface alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
@implementation DBConstantsInterface
- (id)initWithCpp:(const std::shared_ptr<::ConstantsInterface>&)cppRef
......@@ -53,3 +36,25 @@ auto ConstantsInterface::fromCpp(const CppType& cpp) -> ObjcType
}
@end
namespace djinni_generated {
auto ConstantsInterface::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return objc.cppRef.get();
}
auto ConstantsInterface::fromCpp(const CppType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::ConstantsInterface>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBConstantsInterface alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
......@@ -20,23 +20,6 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
namespace djinni_generated {
auto CppException::toCpp(ObjcType objc) -> CppType
{
return objc ? objc.cppRef.get() : nullptr;
}
auto CppException::fromCpp(const CppType& cpp) -> ObjcType
{
return !cpp ? nil : ::djinni::DbxCppWrapperCache<::CppException>::getInstance()->get(cpp, [] (const CppType& p)
{
return [[DBCppException alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
@implementation DBCppException
- (id)initWithCpp:(const std::shared_ptr<::CppException>&)cppRef
......@@ -62,3 +45,25 @@ auto CppException::fromCpp(const CppType& cpp) -> ObjcType
}
@end
namespace djinni_generated {
auto CppException::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return objc.cppRef.get();
}
auto CppException::fromCpp(const CppType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::CppException>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBCppException alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
......@@ -26,23 +26,6 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
namespace djinni_generated {
auto TestHelpers::toCpp(ObjcType objc) -> CppType
{
return objc ? objc.cppRef.get() : nullptr;
}
auto TestHelpers::fromCpp(const CppType& cpp) -> ObjcType
{
return !cpp ? nil : ::djinni::DbxCppWrapperCache<::TestHelpers>::getInstance()->get(cpp, [] (const CppType& p)
{
return [[DBTestHelpers alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
@implementation DBTestHelpers
- (id)initWithCpp:(const std::shared_ptr<::TestHelpers>&)cppRef
......@@ -161,33 +144,41 @@ auto TestHelpers::fromCpp(const CppType& cpp) -> ObjcType
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nullable DBToken *)tokenId:(nullable DBToken *)t {
+ (nullable id<DBToken>)tokenId:(nullable id<DBToken>)t {
try {
auto r = ::TestHelpers::token_id(::djinni_generated::Token::toCpp(t));
return ::djinni_generated::Token::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nullable DBToken *)createCppToken {
+ (nullable id<DBToken>)createCppToken {
try {
auto r = ::TestHelpers::create_cpp_token();
return ::djinni_generated::Token::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (void)checkCppToken:(nullable DBToken *)t {
+ (void)checkCppToken:(nullable id<DBToken>)t {
try {
::TestHelpers::check_cpp_token(::djinni_generated::Token::toCpp(t));
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (int64_t)cppTokenId:(nullable DBToken *)t {
+ (int64_t)cppTokenId:(nullable id<DBToken>)t {
try {
auto r = ::TestHelpers::cpp_token_id(::djinni_generated::Token::toCpp(t));
return ::djinni::I64::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (void)checkTokenType:(nullable id<DBToken>)t
type:(nonnull NSString *)type {
try {
::TestHelpers::check_token_type(::djinni_generated::Token::toCpp(t),
::djinni::String::toCpp(type));
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nullable NSNumber *)returnNone {
try {
auto r = ::TestHelpers::return_none();
......@@ -203,3 +194,25 @@ auto TestHelpers::fromCpp(const CppType& cpp) -> ObjcType
}
@end
namespace djinni_generated {
auto TestHelpers::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return objc.cppRef.get();
}
auto TestHelpers::fromCpp(const CppType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return ::djinni::DbxCppWrapperCache<::TestHelpers>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBTestHelpers alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
......@@ -8,8 +8,8 @@
#import "DBPrimitiveList.h"
#import "DBSetRecord.h"
#import <Foundation/Foundation.h>
@class DBToken;
@protocol DBClientInterface;
@protocol DBToken;
@interface DBTestHelpers : NSObject
......@@ -46,13 +46,16 @@
+ (void)checkEnum:(DBColor)c;
+ (nullable DBToken *)tokenId:(nullable DBToken *)t;
+ (nullable id<DBToken>)tokenId:(nullable id<DBToken>)t;
+ (nullable DBToken *)createCppToken;
+ (nullable id<DBToken>)createCppToken;
+ (void)checkCppToken:(nullable DBToken *)t;
+ (void)checkCppToken:(nullable id<DBToken>)t;
+ (int64_t)cppTokenId:(nullable DBToken *)t;
+ (int64_t)cppTokenId:(nullable id<DBToken>)t;
+ (void)checkTokenType:(nullable id<DBToken>)t
type:(nonnull NSString *)type;
+ (nullable NSNumber *)returnNone;
......
......@@ -6,7 +6,7 @@
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@class DBToken;
@protocol DBToken;
namespace djinni_generated {
......@@ -14,7 +14,7 @@ class Token
{
public:
using CppType = std::shared_ptr<::Token>;
using ObjcType = DBToken*;
using ObjcType = id<DBToken>;
using Boxed = Token;
......
......@@ -5,12 +5,14 @@
#import "DBToken.h"
#import "DJICppWrapperCache+Private.h"
#import "DJIError.h"
#import "DJIMarshal+Private.h"
#import "DJIObjcWrapperCache+Private.h"
#include <exception>
#include <utility>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface DBToken ()
@interface DBTokenCppProxy : NSObject<DBToken>
@property (nonatomic, readonly) ::djinni::DbxCppWrapperCache<::Token>::Handle cppRef;
......@@ -18,31 +20,68 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
@end
namespace djinni_generated {
@implementation DBTokenCppProxy
auto Token::toCpp(ObjcType objc) -> CppType
- (id)initWithCpp:(const std::shared_ptr<::Token>&)cppRef
{
return objc ? objc.cppRef.get() : nullptr;
if (self = [super init]) {
_cppRef.assign(cppRef);
}
return self;
}
auto Token::fromCpp(const CppType& cpp) -> ObjcType
- (nonnull NSString *)whoami {
try {
auto r = _cppRef.get()->whoami();
return ::djinni::String::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
@end
namespace djinni_generated {
class Token::ObjcProxy final
: public ::Token
, public ::djinni::DbxObjcWrapperCache<ObjcProxy>::Handle
{
return !cpp ? nil : ::djinni::DbxCppWrapperCache<::Token>::getInstance()->get(cpp, [] (const CppType& p)
public:
using Handle::Handle;
std::string whoami() override
{
return [[DBToken alloc] initWithCpp:p];
});
}
@autoreleasepool {
auto r = [Handle::get() whoami];
return ::djinni::String::toCpp(r);
}
}
};
} // namespace djinni_generated
@implementation DBToken
namespace djinni_generated {
- (id)initWithCpp:(const std::shared_ptr<::Token>&)cppRef
auto Token::toCpp(ObjcType objc) -> CppType
{
if (self = [super init]) {
_cppRef.assign(cppRef);
if (!objc) {
return nullptr;
}
return self;
if ([(id)objc isKindOfClass:[DBTokenCppProxy class]]) {
return ((DBTokenCppProxy*)objc).cppRef.get();
}
return ::djinni::DbxObjcWrapperCache<ObjcProxy>::getInstance()->get(objc);
}
@end
auto Token::fromCpp(const CppType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
if (auto cppPtr = dynamic_cast<ObjcProxy*>(cpp.get())) {
return cppPtr->Handle::get();
}
return ::djinni::DbxCppWrapperCache<::Token>::getInstance()->get(cpp, [] (const CppType& p) {
return [[DBTokenCppProxy alloc] initWithCpp:p];
});
}
} // namespace djinni_generated
......@@ -4,6 +4,8 @@
#import <Foundation/Foundation.h>
@interface DBToken : NSObject
@protocol DBToken
- (nonnull NSString *)whoami;
@end
......@@ -90,7 +90,9 @@ std::shared_ptr<Token> TestHelpers::token_id(const std::shared_ptr<Token> & in)
return in;
}
class CppToken : public Token {};
class CppToken : public Token {
std::string whoami() { return "C++"; }
};
std::shared_ptr<Token> TestHelpers::create_cpp_token() {
return std::make_shared<CppToken>();
......@@ -105,6 +107,12 @@ int64_t TestHelpers::cpp_token_id(const std::shared_ptr<Token> & in) {
return reinterpret_cast<int64_t>(in.get());
}
void TestHelpers::check_token_type(const std::shared_ptr<Token> &t, const std::string & type) {
if (t->whoami() != type) {
throw std::invalid_argument("wrong token type");
}
}
std::experimental::optional<int32_t> TestHelpers::return_none() {
return {};
}
......
......@@ -5,6 +5,7 @@ import junit.framework.TestCase;
public class TokenTest extends TestCase {
private class JavaToken extends Token {
public String whoami() { return "Java"; }
}
@Override
......@@ -29,6 +30,25 @@ public class TokenTest extends TestCase {
System.runFinalization();
}
public void testTokenType() {
TestHelpers.checkTokenType(new JavaToken(), "Java");
TestHelpers.checkTokenType(TestHelpers.createCppToken(), "C++");
boolean threw = false;
try {
TestHelpers.checkTokenType(new JavaToken(), "foo");
} catch (RuntimeException e) {
threw = true;
}
assertTrue(threw);
threw = false;
try {
TestHelpers.checkTokenType(TestHelpers.createCppToken(), "foo");
} catch (RuntimeException e) {
threw = true;
}
assertTrue(threw);
}
public void testNotCppToken() {
boolean threw = false;
try {
......
#import "DBTestHelpers.h"
#import "DBToken.h"
#import <XCTest/XCTest.h>
@interface DBTokenTests : XCTestCase
@end
@interface DBObjcToken : NSObject<DBToken>
- (NSString *)whoami;
@end
@implementation DBObjcToken
- (NSString *)whoami {
return @"ObjC";
}
@end
@implementation DBTokenTests
- (void)setUp
{
[super setUp];
}
- (void)tearDown
{
[super tearDown];
}
- (void)testTokens
{
id<DBToken> t = [[DBObjcToken alloc] init];
XCTAssertEqual([DBTestHelpers tokenId:t], t);
}
- (void)testNullToken
{
XCTAssertNil([DBTestHelpers tokenId:nil]);
}
- (void)testTokenType
{
[DBTestHelpers checkTokenType:[[DBObjcToken alloc] init] type:@"ObjC"];
[DBTestHelpers checkTokenType:[DBTestHelpers createCppToken] type:@"C++"];
XCTAssertThrows([DBTestHelpers checkTokenType:[[DBObjcToken alloc] init] type:@"foo"]);
XCTAssertThrows([DBTestHelpers checkTokenType:[DBTestHelpers createCppToken] type:@"foo"]);
}
- (void)testCppToken
{
id<DBToken> ct = [DBTestHelpers createCppToken];
XCTAssertEqual([DBTestHelpers tokenId:ct], ct);
[DBTestHelpers checkCppToken:ct];
ct = nil;
}
- (void)testNotCppToken {
XCTAssertThrows([DBTestHelpers checkCppToken:[[DBObjcToken alloc] init]]);
}
@end
......@@ -24,6 +24,7 @@
65868B5F1989FE4200D60EEE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65868B5E1989FE4200D60EEE /* UIKit.framework */; };
65868B621989FE4200D60EEE /* libDjinniObjcTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 65868B4A1989FE4200D60EEE /* libDjinniObjcTest.a */; };
6D66A8A91A3B09F000B312E8 /* DBConstantTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6D66A8A81A3B09F000B312E8 /* DBConstantTests.mm */; };
A20094101B06982F00EF8D9B /* DBTokenTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = A200940E1B0697D300EF8D9B /* DBTokenTests.mm */; };
A238CA8C1AF84B7100CDDCE5 /* DBAssortedIntegers+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = A238CA741AF84B7100CDDCE5 /* DBAssortedIntegers+Private.mm */; };
A238CA8E1AF84B7100CDDCE5 /* DBClientReturnedRecord+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = A238CA761AF84B7100CDDCE5 /* DBClientReturnedRecord+Private.mm */; };
A238CA901AF84B7100CDDCE5 /* DBConstants+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = A238CA781AF84B7100CDDCE5 /* DBConstants+Private.mm */; };
......@@ -118,6 +119,7 @@
65868B5B1989FE4200D60EEE /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
65868B5E1989FE4200D60EEE /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
6D66A8A81A3B09F000B312E8 /* DBConstantTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBConstantTests.mm; sourceTree = "<group>"; };
A200940E1B0697D300EF8D9B /* DBTokenTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBTokenTests.mm; sourceTree = "<group>"; };
A238CA741AF84B7100CDDCE5 /* DBAssortedIntegers+Private.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "DBAssortedIntegers+Private.mm"; sourceTree = "<group>"; };
A238CA761AF84B7100CDDCE5 /* DBClientReturnedRecord+Private.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "DBClientReturnedRecord+Private.mm"; sourceTree = "<group>"; };
A238CA781AF84B7100CDDCE5 /* DBConstants+Private.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "DBConstants+Private.mm"; sourceTree = "<group>"; };
......@@ -273,6 +275,7 @@
6536CD7919A6C99800DD7715 /* Tests */ = {
isa = PBXGroup;
children = (
A200940E1B0697D300EF8D9B /* DBTokenTests.mm */,
6536CD7A19A6C99800DD7715 /* DBClientInterfaceTests.mm */,
6536CD7B19A6C99800DD7715 /* DBCppExceptionTests.mm */,
6536CD7C19A6C99800DD7715 /* DBMapRecordTests.mm */,
......@@ -568,6 +571,7 @@
CFFD58B21B041BD9001E10B6 /* DBConstantsInterface.mm in Sources */,
6536CD9319A6C9A800DD7715 /* DBRecordWithDerivingsObjcTests.mm in Sources */,
6536CD9019A6C9A800DD7715 /* DBNestedCollectionTests.mm in Sources */,
A20094101B06982F00EF8D9B /* DBTokenTests.mm in Sources */,
6536CD8F19A6C9A800DD7715 /* DBMapRecordTests.mm in Sources */,
6536CD9419A6C9A800DD7715 /* DBSetRecordTests.mm in Sources */,
);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment