Commit 3edad97c authored by Andrew Twyman's avatar Andrew Twyman Committed by GitHub

Merge pull request #254 from konovalov-aleks/cpp_wide_strings_support

Cpp wide strings support
parents 2a896c73 3f9151c6
......@@ -145,7 +145,7 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
}
def base(m: Meta): String = m match {
case p: MPrimitive => p.cName
case MString => "std::string"
case MString => if (spec.cppUseWideStrings) "std::wstring" else "std::string"
case MDate => "std::chrono::system_clock::time_point"
case MBinary => "std::vector<uint8_t>"
case MOptional => spec.cppOptionalTemplate
......
......@@ -98,7 +98,7 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) {
}
case MOptional => "Optional"
case MBinary => "Binary"
case MString => "String"
case MString => if (spec.cppUseWideStrings) "WString" else "String"
case MDate => "Date"
case MList => "List"
case MSet => "Set"
......
......@@ -35,6 +35,7 @@ object Main {
var cppNnHeader: Option[String] = None
var cppNnType: Option[String] = None
var cppNnCheckExpression: Option[String] = None
var cppUseWideStrings: Boolean = false
var javaOutFolder: Option[File] = None
var javaPackage: Option[String] = None
var javaCppException: Option[String] = None
......@@ -133,6 +134,8 @@ object Main {
.text("The type to use for non-nullable pointers (as a substitute for std::shared_ptr)")
opt[String]("cpp-nn-check-expression").valueName("<header>").foreach(x => cppNnCheckExpression = Some(x))
.text("The expression to use for building non-nullable pointers")
opt[Boolean]( "cpp-use-wide-strings").valueName("<true/false>").foreach(x => cppUseWideStrings = x)
.text("Use wide strings in C++ code (default: false)")
note("")
opt[File]("jni-out").valueName("<out-folder>").foreach(x => jniOutFolder = Some(x))
.text("The folder for the JNI C++ output files (Generator disabled if unspecified).")
......@@ -293,6 +296,7 @@ object Main {
cppNnHeader,
cppNnType,
cppNnCheckExpression,
cppUseWideStrings,
jniOutFolder,
jniHeaderOutFolder,
jniIncludePrefix,
......
......@@ -79,7 +79,7 @@ class ObjcppMarshal(spec: Spec) extends Marshal(spec) {
case MOptional => "Optional"
case MBinary => "Binary"
case MDate => "Date"
case MString => "String"
case MString => if (spec.cppUseWideStrings) "WString" else "String"
case MList => "List"
case MSet => "Set"
case MMap => "Map"
......
......@@ -49,6 +49,7 @@ package object generatorTools {
cppNnHeader: Option[String],
cppNnType: Option[String],
cppNnCheckExpression: Option[String],
cppUseWideStrings: Boolean,
jniOutFolder: Option[File],
jniHeaderOutFolder: Option[File],
jniIncludePrefix: String,
......
......@@ -178,6 +178,25 @@ namespace djinni
}
};
struct WString
{
using CppType = std::wstring;
using JniType = jstring;
using Boxed = WString;
static CppType toCpp(JNIEnv* jniEnv, JniType j)
{
assert(j != nullptr);
return jniWStringFromString(jniEnv, j);
}
static LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c)
{
return {jniEnv, jniStringFromWString(jniEnv, c)};
}
};
struct Binary
{
using CppType = std::vector<uint8_t>;
......
......@@ -371,6 +371,43 @@ jstring jniStringFromUTF8(JNIEnv * env, const std::string & str) {
return res;
}
template<int wcharTypeSize>
static std::u16string implWStringToUTF16(const std::wstring & str)
{
static_assert(wcharTypeSize == 2 || wcharTypeSize == 4, "wchar_t must be represented by UTF-16 or UTF-32 encoding");
}
template<>
inline std::u16string implWStringToUTF16<2>(const std::wstring & str) {
// case when wchar_t is represented by utf-16 encoding
return std::u16string(str.begin(), str.end());
}
template<>
inline std::u16string implWStringToUTF16<4>(const std::wstring & str) {
// case when wchar_t is represented by utf-32 encoding
std::u16string utf16;
utf16.reserve(str.length());
for (size_t i = 0; i < str.length(); ++i)
utf16_encode(static_cast<char32_t>(str[i]), utf16);
return utf16;
}
inline std::u16string wstringToUTF16(const std::wstring & str) {
// hide "defined but not used" warnings
(void)implWStringToUTF16<2>;
(void)implWStringToUTF16<4>;
return implWStringToUTF16<sizeof(wchar_t)>(str);
}
jstring jniStringFromWString(JNIEnv * env, const std::wstring & str) {
std::u16string utf16 = wstringToUTF16(str);
jstring res = env->NewString(
reinterpret_cast<const jchar *>(utf16.data()), utf16.length());
DJINNI_ASSERT(res, env);
return res;
}
// UTF-16 decode helpers.
static inline bool is_high_surrogate(char16_t c) { return (c >= 0xD800) && (c < 0xDC00); }
static inline bool is_low_surrogate(char16_t c) { return (c >= 0xDC00) && (c < 0xE000); }
......@@ -378,7 +415,7 @@ static inline bool is_low_surrogate(char16_t c) { return (c >= 0xDC00) && (c <
/*
* Like utf8_decode_check, but for UTF-16.
*/
static offset_pt utf16_decode_check(const std::u16string & str, std::u16string::size_type i) {
static offset_pt utf16_decode_check(const char16_t * str, std::u16string::size_type i) {
if (is_high_surrogate(str[i]) && is_low_surrogate(str[i+1])) {
// High surrogate followed by low surrogate
char32_t pt = (((str[i] - 0xD800) << 10) | (str[i+1] - 0xDC00)) + 0x10000;
......@@ -391,7 +428,7 @@ static offset_pt utf16_decode_check(const std::u16string & str, std::u16string::
}
}
static char32_t utf16_decode(const std::u16string & str, std::u16string::size_type & i) {
static char32_t utf16_decode(const char16_t * str, std::u16string::size_type & i) {
offset_pt res = utf16_decode_check(str, i);
if (res.offset < 0) {
i += 1;
......@@ -437,10 +474,51 @@ std::string jniUTF8FromString(JNIEnv * env, const jstring jstr) {
std::string out;
out.reserve(str.length() * 3 / 2); // estimate
for (std::u16string::size_type i = 0; i < str.length(); )
utf8_encode(utf16_decode(str, i), out);
utf8_encode(utf16_decode(str.data(), i), out);
return out;
}
template<int wcharTypeSize>
static std::wstring implUTF16ToWString(const char16_t * data, size_t length)
{
static_assert(wcharTypeSize == 2 || wcharTypeSize == 4, "wchar_t must be represented by UTF-16 or UTF-32 encoding");
}
template<>
inline std::wstring implUTF16ToWString<2>(const char16_t * data, size_t length) {
// case when wchar_t is represented by utf-16 encoding
return std::wstring(data, data + length);
}
template<>
inline std::wstring implUTF16ToWString<4>(const char16_t * data, size_t length) {
// case when wchar_t is represented by utf-32 encoding
std::wstring result;
result.reserve(length);
for (size_t i = 0; i < length; )
result += static_cast<wchar_t>(utf16_decode(data, i));
return result;
}
inline std::wstring UTF16ToWString(const char16_t * data, size_t length) {
// hide "defined but not used" warnings
(void)implUTF16ToWString<2>;
(void)implUTF16ToWString<4>;
return implUTF16ToWString<sizeof(wchar_t)>(data, length);
}
std::wstring jniWStringFromString(JNIEnv * env, const jstring jstr) {
DJINNI_ASSERT(jstr, env);
const jsize length = env->GetStringLength(jstr);
jniExceptionCheck(env);
const auto deleter = [env, jstr] (const jchar * c) { env->ReleaseStringChars(jstr, c); };
std::unique_ptr<const jchar, decltype(deleter)> ptr(env->GetStringChars(jstr, nullptr),
deleter);
const char16_t * data = reinterpret_cast<const char16_t *>(ptr.get());
return UTF16ToWString(data, length);
}
DJINNI_WEAK_DEFINITION
void jniSetPendingFromCurrent(JNIEnv * env, const char * ctx) noexcept {
jniDefaultSetPendingFromCurrent(env, ctx);
......
......@@ -543,6 +543,9 @@ private:
jstring jniStringFromUTF8(JNIEnv * env, const std::string & str);
std::string jniUTF8FromString(JNIEnv * env, const jstring jstr);
jstring jniStringFromWString(JNIEnv * env, const std::wstring & str);
std::wstring jniWStringFromString(JNIEnv * env, const jstring jstr);
class JniEnum {
public:
/*
......
......@@ -118,6 +118,53 @@ struct String {
}
};
template<int wcharTypeSize>
static CFStringEncoding getWCharEncoding()
{
static_assert(wcharTypeSize == 2 || wcharTypeSize == 4, "wchar_t must be represented by UTF-16 or UTF-32 encoding");
}
template<>
inline CFStringEncoding getWCharEncoding<2>() {
// case when wchar_t is represented by utf-16 encoding
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return NSUTF16BigEndianStringEncoding;
#else
return NSUTF16LittleEndianStringEncoding;
#endif
}
template<>
inline CFStringEncoding getWCharEncoding<4>() {
// case when wchar_t is represented by utf-32 encoding
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return NSUTF32BigEndianStringEncoding;
#else
return NSUTF32LittleEndianStringEncoding;
#endif
}
struct WString {
using CppType = std::wstring;
using ObjcType = NSString*;
using Boxed = WString;
static CppType toCpp(ObjcType string) {
assert(string);
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(getWCharEncoding<sizeof(wchar_t)>());
NSData* data = [string dataUsingEncoding:encoding];
return std::wstring((wchar_t*)[data bytes], [data length] / sizeof (wchar_t));
}
static ObjcType fromCpp(const CppType& string) {
assert(string.size() <= std::numeric_limits<NSUInteger>::max());
return [[NSString alloc] initWithBytes:string.data()
length:string.size() * sizeof(wchar_t)
encoding:getWCharEncoding<sizeof(wchar_t)>()];
}
};
struct Date {
using CppType = std::chrono::system_clock::time_point;
using ObjcType = NSDate*;
......
wchar_test_rec = record {
s: string;
}
wchar_test_helpers = interface +c {
static get_record() : wchar_test_rec;
static get_string() : string;
static check_string(str: string) : bool;
static check_record(rec: wchar_test_rec) : bool;
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#pragma once
#include <string>
namespace testsuite {
struct WcharTestRec;
class WcharTestHelpers {
public:
virtual ~WcharTestHelpers() {}
static WcharTestRec get_record();
static std::wstring get_string();
static bool check_string(const std::wstring & str);
static bool check_record(const WcharTestRec & rec);
};
} // namespace testsuite
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#pragma once
#include <string>
#include <utility>
namespace testsuite {
struct WcharTestRec final {
std::wstring s;
WcharTestRec(std::wstring s_)
: s(std::move(s_))
{}
};
} // namespace testsuite
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
package com.dropbox.djinni.test;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public abstract class WcharTestHelpers {
@Nonnull
public static native WcharTestRec getRecord();
@Nonnull
public static native String getString();
public static native boolean checkString(@Nonnull String str);
public static native boolean checkRecord(@Nonnull WcharTestRec rec);
private static final class CppProxy extends WcharTestHelpers
{
private final long nativeRef;
private final AtomicBoolean destroyed = new AtomicBoolean(false);
private CppProxy(long nativeRef)
{
if (nativeRef == 0) throw new RuntimeException("nativeRef is zero");
this.nativeRef = nativeRef;
}
private native void nativeDestroy(long nativeRef);
public void destroy()
{
boolean destroyed = this.destroyed.getAndSet(true);
if (!destroyed) nativeDestroy(this.nativeRef);
}
protected void finalize() throws java.lang.Throwable
{
destroy();
super.finalize();
}
}
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
package com.dropbox.djinni.test;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public class WcharTestRec {
/*package*/ final String mS;
public WcharTestRec(
@Nonnull String s) {
this.mS = s;
}
@Nonnull
public String getS() {
return mS;
}
@Override
public String toString() {
return "WcharTestRec{" +
"mS=" + mS +
"}";
}
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#include "NativeWcharTestHelpers.hpp" // my header
#include "Marshal.hpp"
#include "NativeWcharTestRec.hpp"
namespace djinni_generated {
NativeWcharTestHelpers::NativeWcharTestHelpers() : ::djinni::JniInterface<::testsuite::WcharTestHelpers, NativeWcharTestHelpers>("com/dropbox/djinni/test/WcharTestHelpers$CppProxy") {}
NativeWcharTestHelpers::~NativeWcharTestHelpers() = default;
CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_WcharTestHelpers_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
delete reinterpret_cast<::djinni::CppProxyHandle<::testsuite::WcharTestHelpers>*>(nativeRef);
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_WcharTestHelpers_getRecord(JNIEnv* jniEnv, jobject /*this*/)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::WcharTestHelpers::get_record();
return ::djinni::release(::djinni_generated::NativeWcharTestRec::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jstring JNICALL Java_com_dropbox_djinni_test_WcharTestHelpers_getString(JNIEnv* jniEnv, jobject /*this*/)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::WcharTestHelpers::get_string();
return ::djinni::release(::djinni::WString::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jboolean JNICALL Java_com_dropbox_djinni_test_WcharTestHelpers_checkString(JNIEnv* jniEnv, jobject /*this*/, jstring j_str)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::WcharTestHelpers::check_string(::djinni::WString::toCpp(jniEnv, j_str));
return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jboolean JNICALL Java_com_dropbox_djinni_test_WcharTestHelpers_checkRecord(JNIEnv* jniEnv, jobject /*this*/, jobject j_rec)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::WcharTestHelpers::check_record(::djinni_generated::NativeWcharTestRec::toCpp(jniEnv, j_rec));
return ::djinni::release(::djinni::Bool::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#pragma once
#include "djinni_support.hpp"
#include "wchar_test_helpers.hpp"
namespace djinni_generated {
class NativeWcharTestHelpers final : ::djinni::JniInterface<::testsuite::WcharTestHelpers, NativeWcharTestHelpers> {
public:
using CppType = std::shared_ptr<::testsuite::WcharTestHelpers>;
using CppOptType = std::shared_ptr<::testsuite::WcharTestHelpers>;
using JniType = jobject;
using Boxed = NativeWcharTestHelpers;
~NativeWcharTestHelpers();
static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeWcharTestHelpers>::get()._fromJava(jniEnv, j); }
static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeWcharTestHelpers>::get()._toJava(jniEnv, c)}; }
static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }
private:
NativeWcharTestHelpers();
friend ::djinni::JniClass<NativeWcharTestHelpers>;
friend ::djinni::JniInterface<::testsuite::WcharTestHelpers, NativeWcharTestHelpers>;
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#include "NativeWcharTestRec.hpp" // my header
#include "Marshal.hpp"
namespace djinni_generated {
NativeWcharTestRec::NativeWcharTestRec() = default;
NativeWcharTestRec::~NativeWcharTestRec() = default;
auto NativeWcharTestRec::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {
const auto& data = ::djinni::JniClass<NativeWcharTestRec>::get();
auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,
::djinni::get(::djinni::WString::fromCpp(jniEnv, c.s)))};
::djinni::jniExceptionCheck(jniEnv);
return r;
}
auto NativeWcharTestRec::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {
::djinni::JniLocalScope jscope(jniEnv, 2);
assert(j != nullptr);
const auto& data = ::djinni::JniClass<NativeWcharTestRec>::get();
return {::djinni::WString::toCpp(jniEnv, (jstring)jniEnv->GetObjectField(j, data.field_mS))};
}
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#pragma once
#include "djinni_support.hpp"
#include "wchar_test_rec.hpp"
namespace djinni_generated {
class NativeWcharTestRec final {
public:
using CppType = ::testsuite::WcharTestRec;
using JniType = jobject;
using Boxed = NativeWcharTestRec;
~NativeWcharTestRec();
static CppType toCpp(JNIEnv* jniEnv, JniType j);
static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);
private:
NativeWcharTestRec();
friend ::djinni::JniClass<NativeWcharTestRec>;
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/djinni/test/WcharTestRec") };
const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;)V") };
const jfieldID field_mS { ::djinni::jniGetFieldID(clazz.get(), "mS", "Ljava/lang/String;") };
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#include "wchar_test_helpers.hpp"
#include <memory>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@class DBWcharTestHelpers;
namespace djinni_generated {
class WcharTestHelpers
{
public:
using CppType = std::shared_ptr<::testsuite::WcharTestHelpers>;
using CppOptType = std::shared_ptr<::testsuite::WcharTestHelpers>;
using ObjcType = DBWcharTestHelpers*;
using Boxed = WcharTestHelpers;
static CppType toCpp(ObjcType objc);
static ObjcType fromCppOpt(const CppOptType& cpp);
static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); }
private:
class ObjcProxy;
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#import "DBWcharTestHelpers+Private.h"
#import "DBWcharTestHelpers.h"
#import "DBWcharTestRec+Private.h"
#import "DJICppWrapperCache+Private.h"
#import "DJIError.h"
#import "DJIMarshal+Private.h"
#include <exception>
#include <utility>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface DBWcharTestHelpers ()
- (id)initWithCpp:(const std::shared_ptr<::testsuite::WcharTestHelpers>&)cppRef;
@end
@implementation DBWcharTestHelpers {
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::WcharTestHelpers>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::WcharTestHelpers>&)cppRef
{
if (self = [super init]) {
_cppRefHandle.assign(cppRef);
}
return self;
}
+ (nonnull DBWcharTestRec *)getRecord {
try {
auto r = ::testsuite::WcharTestHelpers::get_record();
return ::djinni_generated::WcharTestRec::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nonnull NSString *)getString {
try {
auto r = ::testsuite::WcharTestHelpers::get_string();
return ::djinni::WString::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (BOOL)checkString:(nonnull NSString *)str {
try {
auto r = ::testsuite::WcharTestHelpers::check_string(::djinni::WString::toCpp(str));
return ::djinni::Bool::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (BOOL)checkRecord:(nonnull DBWcharTestRec *)rec {
try {
auto r = ::testsuite::WcharTestHelpers::check_record(::djinni_generated::WcharTestRec::toCpp(rec));
return ::djinni::Bool::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
namespace djinni_generated {
auto WcharTestHelpers::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return objc->_cppRefHandle.get();
}
auto WcharTestHelpers::fromCppOpt(const CppOptType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return ::djinni::get_cpp_proxy<DBWcharTestHelpers>(cpp);
}
} // namespace djinni_generated
@end
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#import "DBWcharTestRec.h"
#import <Foundation/Foundation.h>
@interface DBWcharTestHelpers : NSObject
+ (nonnull DBWcharTestRec *)getRecord;
+ (nonnull NSString *)getString;
+ (BOOL)checkString:(nonnull NSString *)str;
+ (BOOL)checkRecord:(nonnull DBWcharTestRec *)rec;
@end
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#import "DBWcharTestRec.h"
#include "wchar_test_rec.hpp"
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@class DBWcharTestRec;
namespace djinni_generated {
struct WcharTestRec
{
using CppType = ::testsuite::WcharTestRec;
using ObjcType = DBWcharTestRec*;
using Boxed = WcharTestRec;
static CppType toCpp(ObjcType objc);
static ObjcType fromCpp(const CppType& cpp);
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#import "DBWcharTestRec+Private.h"
#import "DJIMarshal+Private.h"
#include <cassert>
namespace djinni_generated {
auto WcharTestRec::toCpp(ObjcType obj) -> CppType
{
assert(obj);
return {::djinni::WString::toCpp(obj.s)};
}
auto WcharTestRec::fromCpp(const CppType& cpp) -> ObjcType
{
return [[DBWcharTestRec alloc] initWithS:(::djinni::WString::fromCpp(cpp.s))];
}
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#import <Foundation/Foundation.h>
@interface DBWcharTestRec : NSObject
- (nonnull instancetype)initWithS:(nonnull NSString *)s;
+ (nonnull instancetype)wcharTestRecWithS:(nonnull NSString *)s;
@property (nonatomic, readonly, nonnull) NSString * s;
@end
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from wchar_test.djinni
#import "DBWcharTestRec.h"
@implementation DBWcharTestRec
- (nonnull instancetype)initWithS:(nonnull NSString *)s
{
if (self = [super init]) {
_s = [s copy];
}
return self;
}
+ (nonnull instancetype)wcharTestRecWithS:(nonnull NSString *)s
{
return [[self alloc] initWithS:s];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@ %p s:%@>", self.class, (void *)self, self.s];
}
@end
#include "wchar_test_helpers.hpp"
#include "wchar_test_rec.hpp"
namespace testsuite {
static const wchar_t s1[] = L"some string with unicode \u0000, \u263A, \U0001F4A9 symbols";
static const std::wstring str1(s1, sizeof(s1) / sizeof(*s1) - 1);
static const std::wstring str2 = L"another string with unicode \u263B, \U0001F4A8 symbols";
WcharTestRec WcharTestHelpers::get_record()
{
return WcharTestRec(str1);
}
std::wstring WcharTestHelpers::get_string()
{
return str2;
}
bool WcharTestHelpers::check_string(const std::wstring & s)
{
return s == str2;
}
bool WcharTestHelpers::check_record(const WcharTestRec & r)
{
return r.s == str1;
}
} // namespace testsuite
......@@ -22,6 +22,7 @@ public class AllTests extends TestSuite {
mySuite.addTestSuite(TokenTest.class);
mySuite.addTestSuite(DurationTest.class);
mySuite.addTestSuite(MockRecordTest.class);
mySuite.addTestSuite(WcharTest.class);
return mySuite;
}
......
package com.dropbox.djinni.test;
import junit.framework.TestCase;
public class WcharTest extends TestCase {
private static final String STR1 = "some string with unicode \u0000, \u263A, \uD83D\uDCA9 symbols";
private static final String STR2 = "another string with unicode \u263B, \uD83D\uDCA8 symbols";
public void test() {
assertEquals(WcharTestHelpers.getRecord().getS(), STR1);
assertEquals(WcharTestHelpers.getString(), STR2);
assertEquals(WcharTestHelpers.checkString(STR2), true);
assertEquals(WcharTestHelpers.checkRecord(new WcharTestRec(STR1)), true);
}
}
#import <Foundation/Foundation.h>
#import "DBWcharTestHelpers.h"
#import "DBWcharTestRec.h"
#import <XCTest/XCTest.h>
@interface DBWcharTests : XCTestCase
@end
@implementation DBWcharTests
- (void)setUp
{
[super setUp];
}
- (void)tearDown
{
[super tearDown];
}
- (void)test
{
NSString *str1 = @"some string with unicode \0, \u263A, \U0001F4A9 symbols";
NSString *str2 = @"another string with unicode \u263B, \U0001F4A8 symbols";
XCTAssertEqualObjects([[DBWcharTestHelpers getRecord] s], str1);
XCTAssertEqualObjects([DBWcharTestHelpers getString], str2);
XCTAssertTrue([DBWcharTestHelpers checkString:str2]);
XCTAssertTrue([DBWcharTestHelpers checkRecord:[[DBWcharTestRec alloc] initWithS:str1]]);
}
@end
......@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
5AEA68151D38F4A40083D770 /* DBWcharTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 728E11201D37DE27005A554D /* DBWcharTests.m */; };
650CA05A1C2AB48E007ADDDB /* DBListenerCaller+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = 650CA0571C2AB48E007ADDDB /* DBListenerCaller+Private.mm */; };
650CA05E1C2AB5AB007ADDDB /* ListenerCaller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 650CA05D1C2AB5AB007ADDDB /* ListenerCaller.cpp */; };
650CA0601C2AB6DB007ADDDB /* DBMultipleInheritanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 650CA05B1C2AB524007ADDDB /* DBMultipleInheritanceTests.m */; };
......@@ -31,6 +32,10 @@
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 */; };
728E111B1D37DE0B005A554D /* DBWcharTestHelpers+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = 728E11161D37DE0B005A554D /* DBWcharTestHelpers+Private.mm */; };
728E111C1D37DE0B005A554D /* DBWcharTestRec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 728E11181D37DE0B005A554D /* DBWcharTestRec.mm */; };
728E111D1D37DE0B005A554D /* DBWcharTestRec+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = 728E111A1D37DE0B005A554D /* DBWcharTestRec+Private.mm */; };
728E111F1D37DE1C005A554D /* wchar_test_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 728E111E1D37DE1C005A554D /* wchar_test_helpers.cpp */; };
A20094101B06982F00EF8D9B /* DBTokenTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = A200940E1B0697D300EF8D9B /* DBTokenTests.mm */; };
A209B5791BBA2A0A0070C310 /* DBOptColorRecord.mm in Sources */ = {isa = PBXBuildFile; fileRef = A209B5761BBA2A0A0070C310 /* DBOptColorRecord.mm */; };
A209B57A1BBA2A0A0070C310 /* DBOptColorRecord+Private.mm in Sources */ = {isa = PBXBuildFile; fileRef = A209B5781BBA2A0A0070C310 /* DBOptColorRecord+Private.mm */; };
......@@ -185,6 +190,17 @@
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>"; };
728E11121D37DDFB005A554D /* wchar_test_helpers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = wchar_test_helpers.hpp; sourceTree = "<group>"; };
728E11131D37DDFB005A554D /* wchar_test_rec.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = wchar_test_rec.hpp; sourceTree = "<group>"; };
728E11141D37DE0B005A554D /* DBWcharTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBWcharTestHelpers.h; sourceTree = "<group>"; };
728E11151D37DE0B005A554D /* DBWcharTestHelpers+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DBWcharTestHelpers+Private.h"; sourceTree = "<group>"; };
728E11161D37DE0B005A554D /* DBWcharTestHelpers+Private.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "DBWcharTestHelpers+Private.mm"; sourceTree = "<group>"; };
728E11171D37DE0B005A554D /* DBWcharTestRec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBWcharTestRec.h; sourceTree = "<group>"; };
728E11181D37DE0B005A554D /* DBWcharTestRec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBWcharTestRec.mm; sourceTree = "<group>"; };
728E11191D37DE0B005A554D /* DBWcharTestRec+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DBWcharTestRec+Private.h"; sourceTree = "<group>"; };
728E111A1D37DE0B005A554D /* DBWcharTestRec+Private.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "DBWcharTestRec+Private.mm"; sourceTree = "<group>"; };
728E111E1D37DE1C005A554D /* wchar_test_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wchar_test_helpers.cpp; sourceTree = "<group>"; };
728E11201D37DE27005A554D /* DBWcharTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBWcharTests.m; sourceTree = "<group>"; };
A200940E1B0697D300EF8D9B /* DBTokenTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBTokenTests.mm; sourceTree = "<group>"; };
A209B5751BBA2A0A0070C310 /* DBOptColorRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBOptColorRecord.h; sourceTree = "<group>"; };
A209B5761BBA2A0A0070C310 /* DBOptColorRecord.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DBOptColorRecord.mm; sourceTree = "<group>"; };
......@@ -393,6 +409,7 @@
6536CD7519A6C98800DD7715 /* handwritten-cpp */ = {
isa = PBXGroup;
children = (
728E111E1D37DE1C005A554D /* wchar_test_helpers.cpp */,
B5E9C9391C1F9D9D0073C123 /* reverse_client_interface_impl.cpp */,
B5E9C93A1C1F9D9D0073C123 /* reverse_client_interface_impl.hpp */,
6536CD7619A6C98800DD7715 /* cpp_exception_impl.cpp */,
......@@ -411,6 +428,7 @@
6536CD7919A6C99800DD7715 /* Tests */ = {
isa = PBXGroup;
children = (
728E11201D37DE27005A554D /* DBWcharTests.m */,
6536CD7A19A6C99800DD7715 /* DBClientInterfaceTests.mm */,
6D66A8A81A3B09F000B312E8 /* DBConstantTests.mm */,
6536CD7B19A6C99800DD7715 /* DBCppExceptionTests.mm */,
......@@ -468,6 +486,13 @@
A24249181AF192E0003BF8F0 /* generated-objc */ = {
isa = PBXGroup;
children = (
728E11141D37DE0B005A554D /* DBWcharTestHelpers.h */,
728E11151D37DE0B005A554D /* DBWcharTestHelpers+Private.h */,
728E11161D37DE0B005A554D /* DBWcharTestHelpers+Private.mm */,
728E11171D37DE0B005A554D /* DBWcharTestRec.h */,
728E11181D37DE0B005A554D /* DBWcharTestRec.mm */,
728E11191D37DE0B005A554D /* DBWcharTestRec+Private.h */,
728E111A1D37DE0B005A554D /* DBWcharTestRec+Private.mm */,
B5F06AA81D499379005BE736 /* DBUsesSingleLanguageListeners+Private.mm */,
B5F06AA91D499379005BE736 /* DBUsesSingleLanguageListeners+Private.h */,
B5F06AAA1D499379005BE736 /* DBUsesSingleLanguageListeners.h */,
......@@ -597,6 +622,8 @@
A242495D1AF192FC003BF8F0 /* generated-cpp */ = {
isa = PBXGroup;
children = (
728E11121D37DDFB005A554D /* wchar_test_helpers.hpp */,
728E11131D37DDFB005A554D /* wchar_test_rec.hpp */,
B5F06AB41D49950C005BE736 /* uses_single_language_listeners.hpp */,
B5F06AB51D49950C005BE736 /* objc_only_listener.hpp */,
B5F06AB61D49950C005BE736 /* java_only_listener.hpp */,
......@@ -727,6 +754,7 @@
buildActionMask = 2147483647;
files = (
A238CA981AF84B7100CDDCE5 /* DBMapRecord+Private.mm in Sources */,
728E111B1D37DE0B005A554D /* DBWcharTestHelpers+Private.mm in Sources */,
CFC5D9E81B1513E800BF2DF8 /* DBExternInterface1+Private.mm in Sources */,
B5D8FC361C23E2F40045ADCF /* DBConstantRecord.mm in Sources */,
A24850311AF96EBC00AFE907 /* DBSetRecord.mm in Sources */,
......@@ -774,6 +802,8 @@
A24249761AF192FC003BF8F0 /* record_with_nested_derivings.cpp in Sources */,
CFC5DA081B1532F600BF2DF8 /* DBRecordWithDurationAndDerivings.mm in Sources */,
A248502D1AF96EBC00AFE907 /* DBNestedCollection.mm in Sources */,
728E111D1D37DE0B005A554D /* DBWcharTestRec+Private.mm in Sources */,
728E111C1D37DE0B005A554D /* DBWcharTestRec.mm in Sources */,
B5E9C93B1C1F9D9D0073C123 /* reverse_client_interface_impl.cpp in Sources */,
CFC5D9D81B15106400BF2DF8 /* DBExternRecordWithDerivings+Private.mm in Sources */,
A238CAA21AF84B7100CDDCE5 /* DBSetRecord+Private.mm in Sources */,
......@@ -793,6 +823,7 @@
A248502E1AF96EBC00AFE907 /* DBPrimitiveList.mm in Sources */,
A209B57A1BBA2A0A0070C310 /* DBOptColorRecord+Private.mm in Sources */,
B5D8FC371C23E2F40045ADCF /* DBConstantRecord+Private.mm in Sources */,
728E111F1D37DE1C005A554D /* wchar_test_helpers.cpp in Sources */,
A238CAA01AF84B7100CDDCE5 /* DBRecordWithNestedDerivings+Private.mm in Sources */,
CFC5DA0A1B1532F600BF2DF8 /* DBRecordWithDurationAndDerivings+Private.mm in Sources */,
);
......@@ -802,6 +833,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5AEA68151D38F4A40083D770 /* DBWcharTests.m in Sources */,
CFC5D9D11B15105100BF2DF8 /* extern_record_with_derivings.cpp in Sources */,
6D66A8A91A3B09F000B312E8 /* DBConstantTests.mm in Sources */,
6536CD9219A6C9A800DD7715 /* DBRecordWithDerivingsCppTests.mm in Sources */,
......
......@@ -17,12 +17,14 @@ base_dir=$(cd "`dirname "$loc"`" && pwd)
temp_out="$base_dir/djinni-output-temp"
in="$base_dir/djinni/all.djinni"
wchar_in="$base_dir/djinni/wchar_test.djinni"
# Relative version of in and temp_out are used for Djinni call below so that
# generated lists of infiles/outfiles are not machine-dependent. This
# is an artifact of the test suite, where we want the genereated files
# to be in git for examination.
in_relative="djinni/all.djinni"
wchar_in_relative="djinni/wchar_test.djinni"
temp_out_relative="djinni-output-temp"
cpp_out="$base_dir/generated-src/cpp"
......@@ -59,6 +61,35 @@ fi
"$base_dir/../src/build"
[ ! -e "$temp_out" ] || rm -r "$temp_out"
(cd "$base_dir" && \
"$base_dir/../src/run-assume-built" \
--java-out "$temp_out_relative/java" \
--java-package $java_package \
--java-nullable-annotation "javax.annotation.CheckForNull" \
--java-nonnull-annotation "javax.annotation.Nonnull" \
--java-use-final-for-record false \
--ident-java-field mFooBar \
\
--cpp-out "$temp_out_relative/cpp" \
--cpp-namespace testsuite \
--ident-cpp-enum-type foo_bar \
--cpp-optional-template "std::experimental::optional" \
--cpp-optional-header "<experimental/optional>" \
--cpp-extended-record-include-prefix "../../handwritten-src/cpp/" \
--cpp-use-wide-strings true \
\
--jni-out "$temp_out_relative/jni" \
--ident-jni-class NativeFooBar \
--ident-jni-file NativeFooBar \
\
--objc-out "$temp_out_relative/objc" \
--objcpp-out "$temp_out_relative/objc" \
--objc-type-prefix DB \
\
--yaml-out "$temp_out_relative/yaml" \
--yaml-out-file "yaml-test.yaml" \
--yaml-prefix "test_" \
\
--idl "$wchar_in_relative" && \
"$base_dir/../src/run-assume-built" \
--java-out "$temp_out_relative/java" \
--java-package $java_package \
......
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