Commit 2af44158 authored by Alex Choi's avatar Alex Choi Committed by Xianwen Chen

New "flags" archetype for enums oriented towards bitwise flags (#323)

parent a48be3e2
...@@ -24,6 +24,7 @@ Djinni generates code based on interface definitions in an IDL file. An IDL file ...@@ -24,6 +24,7 @@ Djinni generates code based on interface definitions in an IDL file. An IDL file
three kinds of declarations: enums, records, and interfaces. three kinds of declarations: enums, records, and interfaces.
* Enums become C++ enum classes, Java enums, or ObjC `NS_ENUM`s. * Enums become C++ enum classes, Java enums, or ObjC `NS_ENUM`s.
* Flags become C++ enum classes with convenient bit-oriented operators, Java enums with `EnumSet`, or ObjC `NS_OPTIONS`.
* Records are pure-data value objects. * Records are pure-data value objects.
* Interfaces are objects with defined methods to call (in C++, passed by `shared_ptr`). Djinni * Interfaces are objects with defined methods to call (in C++, passed by `shared_ptr`). Djinni
produces code allowing an interface implemented in C++ to be transparently used from ObjC or produces code allowing an interface implemented in C++ to be transparently used from ObjC or
...@@ -40,6 +41,14 @@ Djinni's input is an interface description file. Here's an example: ...@@ -40,6 +41,14 @@ Djinni's input is an interface description file. Here's an example:
option3; option3;
} }
my_flags = flags {
flag1;
flag2;
flag3;
no_flags = none;
all_flags = all;
}
my_record = record { my_record = record {
id: i32; id: i32;
info: string; info: string;
...@@ -125,11 +134,11 @@ For more information, run `run --help` to see all command line arguments availab ...@@ -125,11 +134,11 @@ For more information, run `run --help` to see all command line arguments availab
##### Includes & Build target ##### Includes & Build target
The following headers / code will be generated for each defined type: The following headers / code will be generated for each defined type:
| Type | C++ header | C++ source | Java | JNI header | JNI source | | Type | C++ header | C++ source | Java | JNI header | JNI source |
|-----------|------------------------|----------------------------|---------------------|-----------------------|-----------------------| |------------|------------------------|----------------------------|---------------------|-----------------------|-----------------------|
| Enum | my\_enum.hpp | | MyEnum.java | NativeMyEnum.hpp | NativeMyEnum.cpp | | Enum/Flags | my\_enum.hpp | | MyEnum.java | NativeMyEnum.hpp | NativeMyEnum.cpp |
| Record | my\_record[\_base].hpp | my\_record[\_base].cpp (+) | MyRecord[Base].java | NativeMyRecord.hpp | NativeMyRecord.cpp | | Record | my\_record[\_base].hpp | my\_record[\_base].cpp (+) | MyRecord[Base].java | NativeMyRecord.hpp | NativeMyRecord.cpp |
| Interface | my\_interface.hpp | my\_interface.cpp (+) | MyInterface.java | NativeMyInterface.hpp | NativeMyInterface.cpp | | Interface | my\_interface.hpp | my\_interface.cpp (+) | MyInterface.java | NativeMyInterface.hpp | NativeMyInterface.cpp |
(+) Generated only for types that contain constants. (+) Generated only for types that contain constants.
...@@ -164,13 +173,13 @@ you'll need to add calls to your own `JNI_OnLoad` and `JNI_OnUnload` functions. ...@@ -164,13 +173,13 @@ you'll need to add calls to your own `JNI_OnLoad` and `JNI_OnUnload` functions.
##### Includes & Build Target ##### Includes & Build Target
Generated files for Objective-C / C++ are as follows (assuming prefix is `DB`): Generated files for Objective-C / C++ are as follows (assuming prefix is `DB`):
| Type | C++ header | C++ source | Objective-C files | Objective-C++ files | | Type | C++ header | C++ source | Objective-C files | Objective-C++ files |
|-----------|------------------------|----------------------------|--------------------------|-----------------------------| |------------|------------------------|----------------------------|--------------------------|-----------------------------|
| Enum | my\_enum.hpp | | DBMyEnum.h | | | Enum/Flags | my\_enum.hpp | | DBMyEnum.h | |
| Record | my\_record[\_base].hpp | my\_record[\_base].cpp (+) | DBMyRecord[Base].h | DBMyRecord[Base]+Private.h | | Record | my\_record[\_base].hpp | my\_record[\_base].cpp (+) | DBMyRecord[Base].h | DBMyRecord[Base]+Private.h |
| | | | DBMyRecord[Base].mm (++) | DBMyRecord[Base]+Private.mm | | | | | DBMyRecord[Base].mm (++) | DBMyRecord[Base]+Private.mm |
| Interface | my\_interface.hpp | my\_interface.cpp (+) | DBMyInterface.h | DBMyInterface+Private.h | | Interface | my\_interface.hpp | my\_interface.cpp (+) | DBMyInterface.h | DBMyInterface+Private.h |
| | | | | DBMyInterface+Private.mm | | | | | | DBMyInterface+Private.mm |
(+) Generated only for types that contain constants. (+) Generated only for types that contain constants.
(++) Generated only for types with derived operations and/or constants. These have `.mm` extensions to allow non-trivial constants. (++) Generated only for types with derived operations and/or constants. These have `.mm` extensions to allow non-trivial constants.
...@@ -183,6 +192,28 @@ Note that `+Private` files can only be used with ObjC++ source (other headers ar ...@@ -183,6 +192,28 @@ Note that `+Private` files can only be used with ObjC++ source (other headers ar
Enums are translated to C++ `enum class`es with underlying type `int`, ObjC `NS_ENUM`s with Enums are translated to C++ `enum class`es with underlying type `int`, ObjC `NS_ENUM`s with
underlying type `NSInteger`, and Java enums. underlying type `NSInteger`, and Java enums.
### Flags
Flags are translated to C++ `enum class`es with underlying type `unsigned` and a generated set
of overloaded bitwise operators for convenience, ObjC `NS_OPTIONS` with underlying type
`NSUInteger`, and Java `EnumSet<>`. Contrary to the above enums, the enumerants of flags represent
single bits instead of integral values.
When specifying a `flags` type in your IDL file you can assign special semantics to options:
```
my_flags = flags {
flag1;
flag2;
flag3;
no_flags = none;
all_flags = all;
}
```
In the above example the elements marked with `none` and `all` are given special meaning.
In C++ and ObjC the `no_flags` option is generated with a value that has no bits set (i.e. `0`),
and `all_flags` is generated as a bitwise-or combination of all other values. In Java these
special options are not generated as one can just use `EnumSet.noneOf()` and `EnumSet.allOf()`.
### Record ### Record
Records are data objects. In C++, records contain all their elements by value, including other Records are data objects. In C++, records contain all their elements by value, including other
records (so a record cannot contain itself). records (so a record cannot contain itself).
...@@ -203,7 +234,7 @@ The available data types for a record, argument, or return value are: ...@@ -203,7 +234,7 @@ The available data types for a record, argument, or return value are:
Objective-C. Primitives in a set will be boxed in Java and Objective-C. Objective-C. Primitives in a set will be boxed in Java and Objective-C.
- Map (`map<typeA, typeB>`). This is `unordered_map<K, V>` in C++, `HashMap` in Java, and - Map (`map<typeA, typeB>`). This is `unordered_map<K, V>` in C++, `HashMap` in Java, and
`NSDictionary` in Objective-C. Primitives in a map will be boxed in Java and Objective-C. `NSDictionary` in Objective-C. Primitives in a map will be boxed in Java and Objective-C.
- Enumerations - Enumerations / Flags
- Optionals (`optional<typeA>`). This is `std::experimental::optional<T>` in C++11, object / - Optionals (`optional<typeA>`). This is `std::experimental::optional<T>` in C++11, object /
boxed primitive reference in Java (which can be `null`), and object / NSNumber strong boxed primitive reference in Java (which can be `null`), and object / NSNumber strong
reference in Objective-C (which can be `nil`). reference in Objective-C (which can be `nil`).
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
name: mylib_record1 name: mylib_record1
# Specifies what kind of type this is. # Specifies what kind of type this is.
# Supports the same syntax as is used to declare types in .djinni files. # Supports the same syntax as is used to declare types in .djinni files.
# Examples: 'interface +c', 'record deriving(eq, or)', 'enum', 'interface +j +o' # Examples: 'interface +c', 'record deriving(eq, or)', 'enum', 'flags', 'interface +j +o'
# This determines how Djinni integrates this type into function parameters, fields or return types and operators. # This determines how Djinni integrates this type into function parameters, fields or return types and operators.
typedef: 'record +c deriving(eq, ord)' typedef: 'record +c deriving(eq, ord)'
# The (potentially empty) list of required type parameters. # The (potentially empty) list of required type parameters.
......
...@@ -63,11 +63,33 @@ class CppGenerator(spec: Spec) extends Generator(spec) { ...@@ -63,11 +63,33 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
refs.hpp.add("#include <functional>") // needed for std::hash refs.hpp.add("#include <functional>") // needed for std::hash
} }
val flagsType = "unsigned"
val enumType = "int"
val underlyingType = if(e.flags) flagsType else enumType
writeHppFile(ident, origin, refs.hpp, refs.hppFwds, w => { writeHppFile(ident, origin, refs.hpp, refs.hppFwds, w => {
w.w(s"enum class $self : int").bracedSemi { w.w(s"enum class $self : $underlyingType").bracedSemi {
for (o <- e.options) { writeEnumOptionNone(w, e, idCpp.enum)
writeDoc(w, o.doc) writeEnumOptions(w, e, idCpp.enum)
w.wl(idCpp.enum(o.ident.name) + ",") writeEnumOptionAll(w, e, idCpp.enum)
}
if(e.flags) {
// Define some operators to make working with "enum class" flags actually practical
def binaryOp(op: String) {
w.w(s"constexpr $self operator$op($self lhs, $self rhs) noexcept").braced {
w.wl(s"return static_cast<$self>(static_cast<$flagsType>(lhs) $op static_cast<$flagsType>(rhs));")
}
w.w(s"constexpr $self& operator$op=($self& lhs, $self rhs) noexcept").braced {
w.wl(s"return lhs = lhs $op rhs;") // Ugly, yes, but complies with C++11 restricted constexpr
}
}
binaryOp("|")
binaryOp("&")
binaryOp("^")
w.w(s"constexpr $self operator~($self x) noexcept").braced {
w.wl(s"return static_cast<$self>(~static_cast<$flagsType>(x));")
} }
} }
}, },
...@@ -81,7 +103,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) { ...@@ -81,7 +103,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
w.wl("template <>") w.wl("template <>")
w.w(s"struct hash<$fqSelf>").bracedSemi { w.w(s"struct hash<$fqSelf>").bracedSemi {
w.w(s"size_t operator()($fqSelf type) const").braced { w.w(s"size_t operator()($fqSelf type) const").braced {
w.wl("return std::hash<int>()(static_cast<int>(type));") w.wl(s"return std::hash<$underlyingType>()(static_cast<$underlyingType>(type));")
} }
} }
} }
......
...@@ -73,7 +73,8 @@ class CppMarshal(spec: Spec) extends Marshal(spec) { ...@@ -73,7 +73,8 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
case e: Enum => case e: Enum =>
if (d.name != exclude) { if (d.name != exclude) {
if (forwardDeclareOnly) { if (forwardDeclareOnly) {
List(DeclRef(s"enum class ${typename(d.name, d.body)};", Some(spec.cppNamespace))) val underlyingType = if(e.flags) " : unsigned" else ""
List(DeclRef(s"enum class ${typename(d.name, d.body)}${underlyingType};", Some(spec.cppNamespace)))
} else { } else {
List(ImportRef(include(d.name))) List(ImportRef(include(d.name)))
} }
......
...@@ -64,19 +64,26 @@ class JNIGenerator(spec: Spec) extends Generator(spec) { ...@@ -64,19 +64,26 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
val cppSelf = cppMarshal.fqTypename(ident, e) val cppSelf = cppMarshal.fqTypename(ident, e)
writeJniHppFile(ident, origin, Iterable.concat(refs.jniHpp, refs.jniCpp), Nil, w => { writeJniHppFile(ident, origin, Iterable.concat(refs.jniHpp, refs.jniCpp), Nil, w => {
w.w(s"class $jniHelper final : ::djinni::JniEnum").bracedSemi { val base = if(e.flags) "JniFlags" else "JniEnum"
val count = normalEnumOptions(e).length
w.w(s"class $jniHelper final : ::djinni::$base").bracedSemi {
w.wlOutdent("public:") w.wlOutdent("public:")
w.wl(s"using CppType = $cppSelf;") w.wl(s"using CppType = $cppSelf;")
w.wl(s"using JniType = jobject;") w.wl(s"using JniType = jobject;")
w.wl w.wl
w.wl(s"using Boxed = $jniHelper;") w.wl(s"using Boxed = $jniHelper;")
w.wl w.wl
w.wl(s"static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<$jniHelper>::get().ordinal(jniEnv, j)); }") if(e.flags) {
w.wl(s"static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<$jniHelper>::get().create(jniEnv, static_cast<jint>(c)); }") w.wl(s"static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<$jniHelper>::get().flags(jniEnv, j)); }")
w.wl(s"static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<$jniHelper>::get().create(jniEnv, static_cast<unsigned>(c), $count); }")
} else {
w.wl(s"static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<$jniHelper>::get().ordinal(jniEnv, j)); }")
w.wl(s"static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<$jniHelper>::get().create(jniEnv, static_cast<jint>(c)); }")
}
w.wl w.wl
w.wlOutdent("private:") w.wlOutdent("private:")
val classLookup = q(jniMarshal.undecoratedTypename(ident, e)) val classLookup = q(jniMarshal.undecoratedTypename(ident, e))
w.wl(s"$jniHelper() : JniEnum($classLookup) {}") w.wl(s"$jniHelper() : $base($classLookup) {}")
w.wl(s"friend ::djinni::JniClass<$jniHelper>;") w.wl(s"friend ::djinni::JniClass<$jniHelper>;")
} }
}) })
......
...@@ -76,7 +76,10 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) { ...@@ -76,7 +76,10 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) {
} }
case e: MExtern => e.jni.typeSignature case e: MExtern => e.jni.typeSignature
case MParam(_) => "Ljava/lang/Object;" case MParam(_) => "Ljava/lang/Object;"
case d: MDef => s"L${undecoratedTypename(d.name, d.body)};" case d: MDef => d.body match {
case e: Enum if e.flags => "Ljava/util/EnumSet;"
case _ => s"L${undecoratedTypename(d.name, d.body)};"
}
} }
def javaMethodSignature(params: Iterable[Field], ret: Option[TypeRef]) = { def javaMethodSignature(params: Iterable[Field], ret: Option[TypeRef]) = {
......
...@@ -111,7 +111,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -111,7 +111,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
writeDoc(w, doc) writeDoc(w, doc)
javaAnnotationHeader.foreach(w.wl) javaAnnotationHeader.foreach(w.wl)
w.w(s"${javaClassAccessModifierString}enum ${marshal.typename(ident, e)}").braced { w.w(s"${javaClassAccessModifierString}enum ${marshal.typename(ident, e)}").braced {
for (o <- e.options) { for (o <- normalEnumOptions(e)) {
writeDoc(w, o.doc) writeDoc(w, o.doc)
w.wl(idJava.enum(o.ident) + ",") w.wl(idJava.enum(o.ident) + ",")
} }
...@@ -242,7 +242,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -242,7 +242,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
for (f <- r.fields) { for (f <- r.fields) {
skipFirst { w.wl(",") } skipFirst { w.wl(",") }
marshal.nullityAnnotation(f.ty).map(annotation => w.w(annotation + " ")) marshal.nullityAnnotation(f.ty).map(annotation => w.w(annotation + " "))
w.w(marshal.typename(f.ty) + " " + idJava.local(f.ident)) w.w(marshal.paramType(f.ty) + " " + idJava.local(f.ident))
} }
w.wl(") {") w.wl(") {")
} }
...@@ -258,7 +258,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) { ...@@ -258,7 +258,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
w.wl w.wl
writeDoc(w, f.doc) writeDoc(w, f.doc)
marshal.nullityAnnotation(f.ty).foreach(w.wl) marshal.nullityAnnotation(f.ty).foreach(w.wl)
w.w("public " + marshal.typename(f.ty) + " " + idJava.method("get_" + f.ident.name) + "()").braced { w.w("public " + marshal.returnType(Some(f.ty)) + " " + idJava.method("get_" + f.ident.name) + "()").braced {
w.wl("return " + idJava.field(f.ident) + ";") w.wl("return " + idJava.field(f.ident) + ";")
} }
} }
......
...@@ -15,14 +15,14 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) { ...@@ -15,14 +15,14 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
override def fqTypename(tm: MExpr): String = toJavaType(tm, spec.javaPackage) override def fqTypename(tm: MExpr): String = toJavaType(tm, spec.javaPackage)
def fqTypename(name: String, ty: TypeDef): String = withPackage(spec.javaPackage, idJava.ty(name)) def fqTypename(name: String, ty: TypeDef): String = withPackage(spec.javaPackage, idJava.ty(name))
override def paramType(tm: MExpr): String = typename(tm) override def paramType(tm: MExpr): String = toJavaValueType(tm, None)
override def fqParamType(tm: MExpr): String = fqTypename(tm) override def fqParamType(tm: MExpr): String = toJavaValueType(tm, spec.javaPackage)
override def returnType(ret: Option[TypeRef]): String = ret.fold("void")(ty => toJavaType(ty.resolved, None)) override def returnType(ret: Option[TypeRef]): String = ret.fold("void")(ty => toJavaValueType(ty.resolved, None))
override def fqReturnType(ret: Option[TypeRef]): String = ret.fold("void")(ty => toJavaType(ty.resolved, spec.javaPackage)) override def fqReturnType(ret: Option[TypeRef]): String = ret.fold("void")(ty => toJavaValueType(ty.resolved, spec.javaPackage))
override def fieldType(tm: MExpr): String = typename(tm) override def fieldType(tm: MExpr): String = toJavaValueType(tm, None)
override def fqFieldType(tm: MExpr): String = fqTypename(tm) override def fqFieldType(tm: MExpr): String = toJavaValueType(tm, spec.javaPackage)
override def toCpp(tm: MExpr, expr: String): String = throw new AssertionError("direct java to cpp conversion not possible") override def toCpp(tm: MExpr, expr: String): String = throw new AssertionError("direct java to cpp conversion not possible")
override def fromCpp(tm: MExpr, expr: String): String = throw new AssertionError("direct cpp to java conversion not possible") override def fromCpp(tm: MExpr, expr: String): String = throw new AssertionError("direct cpp to java conversion not possible")
...@@ -36,6 +36,7 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) { ...@@ -36,6 +36,7 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
case MDate => List(ImportRef("java.util.Date")) case MDate => List(ImportRef("java.util.Date"))
case _ => List() case _ => List()
} }
case e if isEnumFlags(e) => List(ImportRef("java.util.EnumSet"))
case _ => List() case _ => List()
} }
...@@ -66,6 +67,21 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) { ...@@ -66,6 +67,21 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
case e: Enum => true case e: Enum => true
} }
def isEnumFlags(m: Meta): Boolean = m match {
case MDef(_, _, _, Enum(_, true)) => true
case MExtern(_, _, _, Enum(_, true), _, _, _, _, _) => true
case _ => false
}
def isEnumFlags(tm: MExpr): Boolean = tm.base match {
case MOptional => isEnumFlags(tm.args.head)
case _ => isEnumFlags(tm.base)
}
private def toJavaValueType(tm: MExpr, packageName: Option[String]): String = {
val name = toJavaType(tm, packageName)
if(isEnumFlags(tm)) s"EnumSet<$name>" else name
}
private def toJavaType(tm: MExpr, packageName: Option[String]): String = { private def toJavaType(tm: MExpr, packageName: Option[String]): String = {
def args(tm: MExpr) = if (tm.args.isEmpty) "" else tm.args.map(f(_, true)).mkString("<", ", ", ">") def args(tm: MExpr) = if (tm.args.isEmpty) "" else tm.args.map(f(_, true)).mkString("<", ", ", ">")
def f(tm: MExpr, needRef: Boolean): String = { def f(tm: MExpr, needRef: Boolean): String = {
......
...@@ -51,12 +51,11 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) { ...@@ -51,12 +51,11 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) {
val self = marshal.typename(ident, e) val self = marshal.typename(ident, e)
writeObjcFile(marshal.headerName(ident), origin, refs.header, w => { writeObjcFile(marshal.headerName(ident), origin, refs.header, w => {
writeDoc(w, doc) writeDoc(w, doc)
w.wl(s"typedef NS_ENUM(NSInteger, $self)") w.wl(if(e.flags) s"typedef NS_OPTIONS(NSUInteger, $self)" else s"typedef NS_ENUM(NSInteger, $self)")
w.bracedSemi { w.bracedSemi {
for (i <- e.options) { writeEnumOptionNone(w, e, self + idObjc.enum(_))
writeDoc(w, i.doc) writeEnumOptions(w, e, self + idObjc.enum(_))
w.wl(self + idObjc.enum(i.ident.name) + ",") writeEnumOptionAll(w, e, self + idObjc.enum(_))
}
} }
}) })
} }
......
...@@ -106,7 +106,8 @@ class YamlGenerator(spec: Spec) extends Generator(spec) { ...@@ -106,7 +106,8 @@ class YamlGenerator(spec: Spec) extends Generator(spec) {
td.body match { td.body match {
case i: Interface => "interface" + ext(i.ext) case i: Interface => "interface" + ext(i.ext)
case r: Record => "record" + ext(r.ext) + deriving(r) case r: Record => "record" + ext(r.ext) + deriving(r)
case e: Enum => "enum" case Enum(_, false) => "enum"
case Enum(_, true) => "flags"
} }
} }
......
...@@ -61,9 +61,14 @@ sealed abstract class TypeDef ...@@ -61,9 +61,14 @@ sealed abstract class TypeDef
case class Const(ident: Ident, ty: TypeRef, value: Any, doc: Doc) case class Const(ident: Ident, ty: TypeRef, value: Any, doc: Doc)
case class Enum(options: Seq[Enum.Option]) extends TypeDef case class Enum(options: Seq[Enum.Option], flags: Boolean) extends TypeDef
object Enum { object Enum {
case class Option(ident: Ident, doc: Doc) object SpecialFlag extends Enumeration {
type SpecialFlag = Value
val NoFlags, AllFlags = Value
}
import SpecialFlag._
case class Option(ident: Ident, doc: Doc, specialFlag: scala.Option[SpecialFlag])
} }
case class Record(ext: Ext, fields: Seq[Field], consts: Seq[Const], derivingTypes: Set[DerivingType]) extends TypeDef case class Record(ext: Ext, fields: Seq[Field], consts: Seq[Const], derivingTypes: Set[DerivingType]) extends TypeDef
......
...@@ -386,6 +386,33 @@ abstract class Generator(spec: Spec) ...@@ -386,6 +386,33 @@ abstract class Generator(spec: Spec)
w.w(end) w.w(end)
} }
def normalEnumOptions(e: Enum) = e.options.filter(_.specialFlag == None)
def writeEnumOptionNone(w: IndentWriter, e: Enum, ident: IdentConverter) {
for (o <- e.options.find(_.specialFlag == Some(Enum.SpecialFlag.NoFlags))) {
writeDoc(w, o.doc)
w.wl(ident(o.ident.name) + " = 0,")
}
}
def writeEnumOptions(w: IndentWriter, e: Enum, ident: IdentConverter) {
var shift = 0
for (o <- normalEnumOptions(e)) {
writeDoc(w, o.doc)
w.wl(ident(o.ident.name) + (if(e.flags) s" = 1 << $shift" else "") + ",")
shift += 1
}
}
def writeEnumOptionAll(w: IndentWriter, e: Enum, ident: IdentConverter) {
for (o <- e.options.find(_.specialFlag == Some(Enum.SpecialFlag.AllFlags))) {
writeDoc(w, o.doc)
w.w(ident(o.ident.name) + " = ")
w.w(normalEnumOptions(e).map(o => ident(o.ident.name)).fold("0")((acc, o) => acc + " | " + o))
w.wl(",")
}
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
def writeDoc(w: IndentWriter, doc: Doc) { def writeDoc(w: IndentWriter, doc: Doc) {
......
...@@ -105,7 +105,7 @@ private object IdlParser extends RegexParsers { ...@@ -105,7 +105,7 @@ private object IdlParser extends RegexParsers {
success(Ext(foundJava, foundCpp, foundObjc)) success(Ext(foundJava, foundCpp, foundObjc))
} }
def typeDef: Parser[TypeDef] = record | enum | interface def typeDef: Parser[TypeDef] = record | enum | flags | interface
def recordHeader = "record" ~> extRecord def recordHeader = "record" ~> extRecord
def record: Parser[Record] = recordHeader ~ bracesList(field | const) ~ opt(deriving) ^^ { def record: Parser[Record] = recordHeader ~ bracesList(field | const) ~ opt(deriving) ^^ {
...@@ -127,10 +127,25 @@ private object IdlParser extends RegexParsers { ...@@ -127,10 +127,25 @@ private object IdlParser extends RegexParsers {
}).toSet }).toSet
} }
def flagsAll = "all".r
def flagsNone = "none".r
def enumHeader = "enum".r def enumHeader = "enum".r
def enum: Parser[Enum] = enumHeader ~> bracesList(enumOption) ^^ Enum.apply def flagsHeader = "flags".r
def enum: Parser[Enum] = enumHeader ~> bracesList(enumOption) ^^ {
case items => Enum(items, false)
}
def flags: Parser[Enum] = flagsHeader ~> bracesList(flagsOption) ^^ {
case items => Enum(items, true)
}
def enumOption: Parser[Enum.Option] = doc ~ ident ^^ { def enumOption: Parser[Enum.Option] = doc ~ ident ^^ {
case doc~ident => Enum.Option(ident, doc) case doc~ident => Enum.Option(ident, doc, None)
}
def flagsOption: Parser[Enum.Option] = doc ~ ident ~ opt("=" ~> (flagsAll | flagsNone)) ^^ {
case doc~ident~None => Enum.Option(ident, doc, None)
case doc~ident~Some("all") => Enum.Option(ident, doc, Some(Enum.SpecialFlag.AllFlags))
case doc~ident~Some("none") => Enum.Option(ident, doc, Some(Enum.SpecialFlag.NoFlags))
} }
def interfaceHeader = "interface" ~> extInterface def interfaceHeader = "interface" ~> extInterface
...@@ -142,8 +157,9 @@ private object IdlParser extends RegexParsers { ...@@ -142,8 +157,9 @@ private object IdlParser extends RegexParsers {
} }
} }
def externTypeDecl: Parser[TypeDef] = externEnum | externInterface | externRecord def externTypeDecl: Parser[TypeDef] = externEnum | externFlags | externInterface | externRecord
def externEnum: Parser[Enum] = enumHeader ^^ { case _ => Enum(List()) } def externEnum: Parser[Enum] = enumHeader ^^ { case _ => Enum(List(), false) }
def externFlags: Parser[Enum] = flagsHeader ^^ { case _ => Enum(List(), true) }
def externRecord: Parser[Record] = recordHeader ~ opt(deriving) ^^ { case ext~deriving => Record(ext, List(), List(), deriving.getOrElse(Set[DerivingType]())) } def externRecord: Parser[Record] = recordHeader ~ opt(deriving) ^^ { case ext~deriving => Record(ext, List(), List(), deriving.getOrElse(Set[DerivingType]())) }
def externInterface: Parser[Interface] = interfaceHeader ^^ { case ext => Interface(ext, List(), List()) } def externInterface: Parser[Interface] = interfaceHeader ^^ { case ext => Interface(ext, List(), List()) }
......
...@@ -267,6 +267,40 @@ LocalRef<jobject> JniEnum::create(JNIEnv * env, jint value) const { ...@@ -267,6 +267,40 @@ LocalRef<jobject> JniEnum::create(JNIEnv * env, jint value) const {
return result; return result;
} }
JniFlags::JniFlags(const std::string & name)
: JniEnum { name }
{}
unsigned JniFlags::flags(JNIEnv * env, jobject obj) const {
DJINNI_ASSERT(obj && env->IsInstanceOf(obj, m_clazz.get()), env);
auto size = env->CallIntMethod(obj, m_methSize);
jniExceptionCheck(env);
unsigned flags = 0;
auto it = LocalRef<jobject>(env, env->CallObjectMethod(obj, m_methIterator));
jniExceptionCheck(env);
for(jint i = 0; i < size; ++i) {
auto jf = LocalRef<jobject>(env, env->CallObjectMethod(it, m_iterator.methNext));
jniExceptionCheck(env);
flags |= (1u << static_cast<unsigned>(ordinal(env, jf)));
}
return flags;
}
LocalRef<jobject> JniFlags::create(JNIEnv * env, unsigned flags, int bits) const {
auto j = LocalRef<jobject>(env, env->CallStaticObjectMethod(m_clazz.get(), m_methNoneOf, enumClass()));
jniExceptionCheck(env);
unsigned mask = 1;
for(int i = 0; i < bits; ++i, mask <<= 1) {
if((flags & mask) != 0) {
auto jf = create(env, static_cast<jint>(i));
jniExceptionCheck(env);
env->CallBooleanMethod(j, m_methAdd, jf.get());
jniExceptionCheck(env);
}
}
return j;
}
JniLocalScope::JniLocalScope(JNIEnv* p_env, jint capacity, bool throwOnError) JniLocalScope::JniLocalScope(JNIEnv* p_env, jint capacity, bool throwOnError)
: m_env(p_env) : m_env(p_env)
, m_success(_pushLocalFrame(m_env, capacity)) { , m_success(_pushLocalFrame(m_env, capacity)) {
......
...@@ -546,6 +546,7 @@ public: ...@@ -546,6 +546,7 @@ public:
protected: protected:
JniEnum(const std::string & name); JniEnum(const std::string & name);
jclass enumClass() const { return m_clazz.get(); }
private: private:
const GlobalRef<jclass> m_clazz; const GlobalRef<jclass> m_clazz;
...@@ -553,6 +554,37 @@ private: ...@@ -553,6 +554,37 @@ private:
const jmethodID m_methOrdinal; const jmethodID m_methOrdinal;
}; };
class JniFlags : private JniEnum {
public:
/*
* Given a Java EnumSet convert it to the corresponding bit pattern
* which can then be static_cast<> to the actual enum.
*/
unsigned flags(JNIEnv * env, jobject obj) const;
/*
* Create a Java EnumSet of the specified flags considering the given number of active bits.
*/
LocalRef<jobject> create(JNIEnv * env, unsigned flags, int bits) const;
using JniEnum::create;
protected:
JniFlags(const std::string & name);
private:
const GlobalRef<jclass> m_clazz { jniFindClass("java/util/EnumSet") };
const jmethodID m_methNoneOf { jniGetStaticMethodID(m_clazz.get(), "noneOf", "(Ljava/lang/Class;)Ljava/util/EnumSet;") };
const jmethodID m_methAdd { jniGetMethodID(m_clazz.get(), "add", "(Ljava/lang/Object;)Z") };
const jmethodID m_methIterator { jniGetMethodID(m_clazz.get(), "iterator", "()Ljava/util/Iterator;") };
const jmethodID m_methSize { jniGetMethodID(m_clazz.get(), "size", "()I") };
struct {
const GlobalRef<jclass> clazz { jniFindClass("java/util/Iterator") };
const jmethodID methNext { jniGetMethodID(clazz.get(), "next", "()Ljava/lang/Object;") };
} m_iterator;
};
#define DJINNI_FUNCTION_PROLOGUE0(env_) #define DJINNI_FUNCTION_PROLOGUE0(env_)
#define DJINNI_FUNCTION_PROLOGUE1(env_, arg1_) #define DJINNI_FUNCTION_PROLOGUE1(env_, arg1_)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <chrono> #include <chrono>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <type_traits>
#include <unordered_set> #include <unordered_set>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
...@@ -94,8 +95,17 @@ struct Enum { ...@@ -94,8 +95,17 @@ struct Enum {
struct Boxed { struct Boxed {
using ObjcType = NSNumber*; using ObjcType = NSNumber*;
static CppType toCpp(ObjcType x) noexcept { return Enum::toCpp(static_cast<Enum::ObjcType>([x integerValue])); } static CppType toCpp(ObjcType x) noexcept { return toCpp(x, Tag<typename std::underlying_type<CppType>::type>()); }
static ObjcType fromCpp(CppType x) noexcept { return [NSNumber numberWithInteger:static_cast<NSInteger>(Enum::fromCpp(x))]; } static ObjcType fromCpp(CppType x) noexcept { return fromCpp(x, Tag<typename std::underlying_type<CppType>::type>()); }
private:
template<class T> struct Tag { };
static CppType toCpp(ObjcType x, Tag<int>) noexcept { return Enum::toCpp(static_cast<Enum::ObjcType>([x integerValue])); }
static ObjcType fromCpp(CppType x, Tag<int>) noexcept { return [NSNumber numberWithInteger:static_cast<NSInteger>(Enum::fromCpp(x))]; }
static CppType toCpp(ObjcType x, Tag<unsigned>) noexcept { return Enum::toCpp(static_cast<Enum::ObjcType>([x unsignedIntegerValue])); }
static ObjcType fromCpp(CppType x, Tag<unsigned>) noexcept { return [NSNumber numberWithUnsignedInteger:static_cast<NSUInteger>(Enum::fromCpp(x))]; }
}; };
}; };
......
...@@ -26,3 +26,33 @@ enum_usage_interface = interface +c +j +o { ...@@ -26,3 +26,33 @@ enum_usage_interface = interface +c +j +o {
s(s: set<color>): set<color>; s(s: set<color>): set<color>;
m(m: map<color, color>): map<color, color>; m(m: map<color, color>): map<color, color>;
} }
access_flags = flags {
nobody = none;
owner_read;
owner_write;
owner_execute;
group_read;
group_write;
group_execute;
system_read;
system_write;
system_execute;
everybody = all;
}
empty_flags = flags {
none = none;
all = all;
}
flag_roundtrip = interface +c {
static roundtrip_access(flag: access_flags): access_flags;
static roundtrip_empty(flag: empty_flags): empty_flags;
static roundtrip_access_boxed(flag: optional<access_flags>): optional<access_flags>;
static roundtrip_empty_boxed(flag: optional<empty_flags>): optional<empty_flags>;
}
record_with_flags = record {
access: access_flags;
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include <functional>
namespace testsuite {
enum class access_flags : unsigned {
NOBODY = 0,
OWNER_READ = 1 << 0,
OWNER_WRITE = 1 << 1,
OWNER_EXECUTE = 1 << 2,
GROUP_READ = 1 << 3,
GROUP_WRITE = 1 << 4,
GROUP_EXECUTE = 1 << 5,
SYSTEM_READ = 1 << 6,
SYSTEM_WRITE = 1 << 7,
SYSTEM_EXECUTE = 1 << 8,
EVERYBODY = 0 | OWNER_READ | OWNER_WRITE | OWNER_EXECUTE | GROUP_READ | GROUP_WRITE | GROUP_EXECUTE | SYSTEM_READ | SYSTEM_WRITE | SYSTEM_EXECUTE,
};
constexpr access_flags operator|(access_flags lhs, access_flags rhs) noexcept {
return static_cast<access_flags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
}
constexpr access_flags& operator|=(access_flags& lhs, access_flags rhs) noexcept {
return lhs = lhs | rhs;
}
constexpr access_flags operator&(access_flags lhs, access_flags rhs) noexcept {
return static_cast<access_flags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
}
constexpr access_flags& operator&=(access_flags& lhs, access_flags rhs) noexcept {
return lhs = lhs & rhs;
}
constexpr access_flags operator^(access_flags lhs, access_flags rhs) noexcept {
return static_cast<access_flags>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs));
}
constexpr access_flags& operator^=(access_flags& lhs, access_flags rhs) noexcept {
return lhs = lhs ^ rhs;
}
constexpr access_flags operator~(access_flags x) noexcept {
return static_cast<access_flags>(~static_cast<unsigned>(x));
}
} // namespace testsuite
namespace std {
template <>
struct hash<::testsuite::access_flags> {
size_t operator()(::testsuite::access_flags type) const {
return std::hash<unsigned>()(static_cast<unsigned>(type));
}
};
} // namespace std
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include <functional>
namespace testsuite {
enum class empty_flags : unsigned {
NONE = 0,
ALL = 0,
};
constexpr empty_flags operator|(empty_flags lhs, empty_flags rhs) noexcept {
return static_cast<empty_flags>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
}
constexpr empty_flags& operator|=(empty_flags& lhs, empty_flags rhs) noexcept {
return lhs = lhs | rhs;
}
constexpr empty_flags operator&(empty_flags lhs, empty_flags rhs) noexcept {
return static_cast<empty_flags>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs));
}
constexpr empty_flags& operator&=(empty_flags& lhs, empty_flags rhs) noexcept {
return lhs = lhs & rhs;
}
constexpr empty_flags operator^(empty_flags lhs, empty_flags rhs) noexcept {
return static_cast<empty_flags>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs));
}
constexpr empty_flags& operator^=(empty_flags& lhs, empty_flags rhs) noexcept {
return lhs = lhs ^ rhs;
}
constexpr empty_flags operator~(empty_flags x) noexcept {
return static_cast<empty_flags>(~static_cast<unsigned>(x));
}
} // namespace testsuite
namespace std {
template <>
struct hash<::testsuite::empty_flags> {
size_t operator()(::testsuite::empty_flags type) const {
return std::hash<unsigned>()(static_cast<unsigned>(type));
}
};
} // namespace std
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include "../../handwritten-src/cpp/optional.hpp"
namespace testsuite {
enum class access_flags : unsigned;
enum class empty_flags : unsigned;
class FlagRoundtrip {
public:
virtual ~FlagRoundtrip() {}
static access_flags roundtrip_access(access_flags flag);
static empty_flags roundtrip_empty(empty_flags flag);
static std::experimental::optional<access_flags> roundtrip_access_boxed(std::experimental::optional<access_flags> flag);
static std::experimental::optional<empty_flags> roundtrip_empty_boxed(std::experimental::optional<empty_flags> flag);
};
} // namespace testsuite
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include "access_flags.hpp"
#include <utility>
namespace testsuite {
struct RecordWithFlags final {
access_flags access;
RecordWithFlags(access_flags access_)
: access(std::move(access_))
{}
};
} // namespace testsuite
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
package com.dropbox.djinni.test;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public enum AccessFlags {
OWNER_READ,
OWNER_WRITE,
OWNER_EXECUTE,
GROUP_READ,
GROUP_WRITE,
GROUP_EXECUTE,
SYSTEM_READ,
SYSTEM_WRITE,
SYSTEM_EXECUTE,
;
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
package com.dropbox.djinni.test;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public enum EmptyFlags {
;
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
package com.dropbox.djinni.test;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public abstract class FlagRoundtrip {
@Nonnull
public static native EnumSet<AccessFlags> roundtripAccess(@Nonnull EnumSet<AccessFlags> flag);
@Nonnull
public static native EnumSet<EmptyFlags> roundtripEmpty(@Nonnull EnumSet<EmptyFlags> flag);
@CheckForNull
public static native EnumSet<AccessFlags> roundtripAccessBoxed(@CheckForNull EnumSet<AccessFlags> flag);
@CheckForNull
public static native EnumSet<EmptyFlags> roundtripEmptyBoxed(@CheckForNull EnumSet<EmptyFlags> flag);
private static final class CppProxy extends FlagRoundtrip
{
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 enum.djinni
package com.dropbox.djinni.test;
import java.util.EnumSet;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public class RecordWithFlags {
/*package*/ final EnumSet<AccessFlags> mAccess;
public RecordWithFlags(
@Nonnull EnumSet<AccessFlags> access) {
this.mAccess = access;
}
@Nonnull
public EnumSet<AccessFlags> getAccess() {
return mAccess;
}
@Override
public String toString() {
return "RecordWithFlags{" +
"mAccess=" + mAccess +
"}";
}
}
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include "access_flags.hpp"
#include "djinni_support.hpp"
namespace djinni_generated {
class NativeAccessFlags final : ::djinni::JniFlags {
public:
using CppType = ::testsuite::access_flags;
using JniType = jobject;
using Boxed = NativeAccessFlags;
static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<NativeAccessFlags>::get().flags(jniEnv, j)); }
static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<NativeAccessFlags>::get().create(jniEnv, static_cast<unsigned>(c), 9); }
private:
NativeAccessFlags() : JniFlags("com/dropbox/djinni/test/AccessFlags") {}
friend ::djinni::JniClass<NativeAccessFlags>;
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include "djinni_support.hpp"
#include "empty_flags.hpp"
namespace djinni_generated {
class NativeEmptyFlags final : ::djinni::JniFlags {
public:
using CppType = ::testsuite::empty_flags;
using JniType = jobject;
using Boxed = NativeEmptyFlags;
static CppType toCpp(JNIEnv* jniEnv, JniType j) { return static_cast<CppType>(::djinni::JniClass<NativeEmptyFlags>::get().flags(jniEnv, j)); }
static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<NativeEmptyFlags>::get().create(jniEnv, static_cast<unsigned>(c), 0); }
private:
NativeEmptyFlags() : JniFlags("com/dropbox/djinni/test/EmptyFlags") {}
friend ::djinni::JniClass<NativeEmptyFlags>;
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#include "NativeFlagRoundtrip.hpp" // my header
#include "Marshal.hpp"
#include "NativeAccessFlags.hpp"
#include "NativeEmptyFlags.hpp"
namespace djinni_generated {
NativeFlagRoundtrip::NativeFlagRoundtrip() : ::djinni::JniInterface<::testsuite::FlagRoundtrip, NativeFlagRoundtrip>("com/dropbox/djinni/test/FlagRoundtrip$CppProxy") {}
NativeFlagRoundtrip::~NativeFlagRoundtrip() = default;
CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_FlagRoundtrip_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef)
{
try {
DJINNI_FUNCTION_PROLOGUE1(jniEnv, nativeRef);
delete reinterpret_cast<::djinni::CppProxyHandle<::testsuite::FlagRoundtrip>*>(nativeRef);
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, )
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_FlagRoundtrip_roundtripAccess(JNIEnv* jniEnv, jobject /*this*/, jobject j_flag)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::FlagRoundtrip::roundtrip_access(::djinni_generated::NativeAccessFlags::toCpp(jniEnv, j_flag));
return ::djinni::release(::djinni_generated::NativeAccessFlags::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_FlagRoundtrip_roundtripEmpty(JNIEnv* jniEnv, jobject /*this*/, jobject j_flag)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::FlagRoundtrip::roundtrip_empty(::djinni_generated::NativeEmptyFlags::toCpp(jniEnv, j_flag));
return ::djinni::release(::djinni_generated::NativeEmptyFlags::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_FlagRoundtrip_roundtripAccessBoxed(JNIEnv* jniEnv, jobject /*this*/, jobject j_flag)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::FlagRoundtrip::roundtrip_access_boxed(::djinni::Optional<std::experimental::optional, ::djinni_generated::NativeAccessFlags>::toCpp(jniEnv, j_flag));
return ::djinni::release(::djinni::Optional<std::experimental::optional, ::djinni_generated::NativeAccessFlags>::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_djinni_test_FlagRoundtrip_roundtripEmptyBoxed(JNIEnv* jniEnv, jobject /*this*/, jobject j_flag)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::testsuite::FlagRoundtrip::roundtrip_empty_boxed(::djinni::Optional<std::experimental::optional, ::djinni_generated::NativeEmptyFlags>::toCpp(jniEnv, j_flag));
return ::djinni::release(::djinni::Optional<std::experimental::optional, ::djinni_generated::NativeEmptyFlags>::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 enum.djinni
#pragma once
#include "djinni_support.hpp"
#include "flag_roundtrip.hpp"
namespace djinni_generated {
class NativeFlagRoundtrip final : ::djinni::JniInterface<::testsuite::FlagRoundtrip, NativeFlagRoundtrip> {
public:
using CppType = std::shared_ptr<::testsuite::FlagRoundtrip>;
using CppOptType = std::shared_ptr<::testsuite::FlagRoundtrip>;
using JniType = jobject;
using Boxed = NativeFlagRoundtrip;
~NativeFlagRoundtrip();
static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeFlagRoundtrip>::get()._fromJava(jniEnv, j); }
static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeFlagRoundtrip>::get()._toJava(jniEnv, c)}; }
static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }
private:
NativeFlagRoundtrip();
friend ::djinni::JniClass<NativeFlagRoundtrip>;
friend ::djinni::JniInterface<::testsuite::FlagRoundtrip, NativeFlagRoundtrip>;
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#include "NativeRecordWithFlags.hpp" // my header
#include "NativeAccessFlags.hpp"
namespace djinni_generated {
NativeRecordWithFlags::NativeRecordWithFlags() = default;
NativeRecordWithFlags::~NativeRecordWithFlags() = default;
auto NativeRecordWithFlags::fromCpp(JNIEnv* jniEnv, const CppType& c) -> ::djinni::LocalRef<JniType> {
const auto& data = ::djinni::JniClass<NativeRecordWithFlags>::get();
auto r = ::djinni::LocalRef<JniType>{jniEnv->NewObject(data.clazz.get(), data.jconstructor,
::djinni::get(::djinni_generated::NativeAccessFlags::fromCpp(jniEnv, c.access)))};
::djinni::jniExceptionCheck(jniEnv);
return r;
}
auto NativeRecordWithFlags::toCpp(JNIEnv* jniEnv, JniType j) -> CppType {
::djinni::JniLocalScope jscope(jniEnv, 2);
assert(j != nullptr);
const auto& data = ::djinni::JniClass<NativeRecordWithFlags>::get();
return {::djinni_generated::NativeAccessFlags::toCpp(jniEnv, jniEnv->GetObjectField(j, data.field_mAccess))};
}
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#pragma once
#include "djinni_support.hpp"
#include "record_with_flags.hpp"
namespace djinni_generated {
class NativeRecordWithFlags final {
public:
using CppType = ::testsuite::RecordWithFlags;
using JniType = jobject;
using Boxed = NativeRecordWithFlags;
~NativeRecordWithFlags();
static CppType toCpp(JNIEnv* jniEnv, JniType j);
static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c);
private:
NativeRecordWithFlags();
friend ::djinni::JniClass<NativeRecordWithFlags>;
const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/dropbox/djinni/test/RecordWithFlags") };
const jmethodID jconstructor { ::djinni::jniGetMethodID(clazz.get(), "<init>", "(Ljava/util/EnumSet;)V") };
const jfieldID field_mAccess { ::djinni::jniGetFieldID(clazz.get(), "mAccess", "Ljava/util/EnumSet;") };
};
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#include "access_flags.hpp"
#import "DJIMarshal+Private.h"
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSUInteger, DBAccessFlags)
{
DBAccessFlagsNobody = 0,
DBAccessFlagsOwnerRead = 1 << 0,
DBAccessFlagsOwnerWrite = 1 << 1,
DBAccessFlagsOwnerExecute = 1 << 2,
DBAccessFlagsGroupRead = 1 << 3,
DBAccessFlagsGroupWrite = 1 << 4,
DBAccessFlagsGroupExecute = 1 << 5,
DBAccessFlagsSystemRead = 1 << 6,
DBAccessFlagsSystemWrite = 1 << 7,
DBAccessFlagsSystemExecute = 1 << 8,
DBAccessFlagsEverybody = 0 | DBAccessFlagsOwnerRead | DBAccessFlagsOwnerWrite | DBAccessFlagsOwnerExecute | DBAccessFlagsGroupRead | DBAccessFlagsGroupWrite | DBAccessFlagsGroupExecute | DBAccessFlagsSystemRead | DBAccessFlagsSystemWrite | DBAccessFlagsSystemExecute,
};
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#include "empty_flags.hpp"
#import "DJIMarshal+Private.h"
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSUInteger, DBEmptyFlags)
{
DBEmptyFlagsNone = 0,
DBEmptyFlagsAll = 0,
};
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#include "flag_roundtrip.hpp"
#include <memory>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@class DBFlagRoundtrip;
namespace djinni_generated {
class FlagRoundtrip
{
public:
using CppType = std::shared_ptr<::testsuite::FlagRoundtrip>;
using CppOptType = std::shared_ptr<::testsuite::FlagRoundtrip>;
using ObjcType = DBFlagRoundtrip*;
using Boxed = FlagRoundtrip;
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 enum.djinni
#import "DBFlagRoundtrip+Private.h"
#import "DBFlagRoundtrip.h"
#import "DBAccessFlags+Private.h"
#import "DBEmptyFlags+Private.h"
#import "DJICppWrapperCache+Private.h"
#import "DJIError.h"
#import "DJIMarshal+Private.h"
#include <exception>
#include <stdexcept>
#include <utility>
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@interface DBFlagRoundtrip ()
- (id)initWithCpp:(const std::shared_ptr<::testsuite::FlagRoundtrip>&)cppRef;
@end
@implementation DBFlagRoundtrip {
::djinni::CppProxyCache::Handle<std::shared_ptr<::testsuite::FlagRoundtrip>> _cppRefHandle;
}
- (id)initWithCpp:(const std::shared_ptr<::testsuite::FlagRoundtrip>&)cppRef
{
if (self = [super init]) {
_cppRefHandle.assign(cppRef);
}
return self;
}
+ (DBAccessFlags)roundtripAccess:(DBAccessFlags)flag {
try {
auto objcpp_result_ = ::testsuite::FlagRoundtrip::roundtrip_access(::djinni::Enum<::testsuite::access_flags, DBAccessFlags>::toCpp(flag));
return ::djinni::Enum<::testsuite::access_flags, DBAccessFlags>::fromCpp(objcpp_result_);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (DBEmptyFlags)roundtripEmpty:(DBEmptyFlags)flag {
try {
auto objcpp_result_ = ::testsuite::FlagRoundtrip::roundtrip_empty(::djinni::Enum<::testsuite::empty_flags, DBEmptyFlags>::toCpp(flag));
return ::djinni::Enum<::testsuite::empty_flags, DBEmptyFlags>::fromCpp(objcpp_result_);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nullable NSNumber *)roundtripAccessBoxed:(nullable NSNumber *)flag {
try {
auto objcpp_result_ = ::testsuite::FlagRoundtrip::roundtrip_access_boxed(::djinni::Optional<std::experimental::optional, ::djinni::Enum<::testsuite::access_flags, DBAccessFlags>>::toCpp(flag));
return ::djinni::Optional<std::experimental::optional, ::djinni::Enum<::testsuite::access_flags, DBAccessFlags>>::fromCpp(objcpp_result_);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nullable NSNumber *)roundtripEmptyBoxed:(nullable NSNumber *)flag {
try {
auto objcpp_result_ = ::testsuite::FlagRoundtrip::roundtrip_empty_boxed(::djinni::Optional<std::experimental::optional, ::djinni::Enum<::testsuite::empty_flags, DBEmptyFlags>>::toCpp(flag));
return ::djinni::Optional<std::experimental::optional, ::djinni::Enum<::testsuite::empty_flags, DBEmptyFlags>>::fromCpp(objcpp_result_);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
namespace djinni_generated {
auto FlagRoundtrip::toCpp(ObjcType objc) -> CppType
{
if (!objc) {
return nullptr;
}
return objc->_cppRefHandle.get();
}
auto FlagRoundtrip::fromCppOpt(const CppOptType& cpp) -> ObjcType
{
if (!cpp) {
return nil;
}
return ::djinni::get_cpp_proxy<DBFlagRoundtrip>(cpp);
}
} // namespace djinni_generated
@end
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#import "DBAccessFlags.h"
#import "DBEmptyFlags.h"
#import <Foundation/Foundation.h>
@interface DBFlagRoundtrip : NSObject
+ (DBAccessFlags)roundtripAccess:(DBAccessFlags)flag;
+ (DBEmptyFlags)roundtripEmpty:(DBEmptyFlags)flag;
+ (nullable NSNumber *)roundtripAccessBoxed:(nullable NSNumber *)flag;
+ (nullable NSNumber *)roundtripEmptyBoxed:(nullable NSNumber *)flag;
@end
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#import "DBRecordWithFlags.h"
#include "record_with_flags.hpp"
static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file");
@class DBRecordWithFlags;
namespace djinni_generated {
struct RecordWithFlags
{
using CppType = ::testsuite::RecordWithFlags;
using ObjcType = DBRecordWithFlags*;
using Boxed = RecordWithFlags;
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 enum.djinni
#import "DBRecordWithFlags+Private.h"
#import "DBAccessFlags+Private.h"
#include <cassert>
namespace djinni_generated {
auto RecordWithFlags::toCpp(ObjcType obj) -> CppType
{
assert(obj);
return {::djinni::Enum<::testsuite::access_flags, DBAccessFlags>::toCpp(obj.access)};
}
auto RecordWithFlags::fromCpp(const CppType& cpp) -> ObjcType
{
return [[DBRecordWithFlags alloc] initWithAccess:(::djinni::Enum<::testsuite::access_flags, DBAccessFlags>::fromCpp(cpp.access))];
}
} // namespace djinni_generated
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#import "DBAccessFlags.h"
#import <Foundation/Foundation.h>
@interface DBRecordWithFlags : NSObject
- (nonnull instancetype)initWithAccess:(DBAccessFlags)access;
+ (nonnull instancetype)recordWithFlagsWithAccess:(DBAccessFlags)access;
@property (nonatomic, readonly) DBAccessFlags access;
@end
// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from enum.djinni
#import "DBRecordWithFlags.h"
@implementation DBRecordWithFlags
- (nonnull instancetype)initWithAccess:(DBAccessFlags)access
{
if (self = [super init]) {
_access = access;
}
return self;
}
+ (nonnull instancetype)recordWithFlagsWithAccess:(DBAccessFlags)access
{
return [[self alloc] initWithAccess:access];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@ %p access:%@>", self.class, (void *)self, @(self.access)];
}
@end
...@@ -35,6 +35,10 @@ djinni-output-temp/cpp/user_token.hpp ...@@ -35,6 +35,10 @@ djinni-output-temp/cpp/user_token.hpp
djinni-output-temp/cpp/color.hpp djinni-output-temp/cpp/color.hpp
djinni-output-temp/cpp/enum_usage_record.hpp djinni-output-temp/cpp/enum_usage_record.hpp
djinni-output-temp/cpp/enum_usage_interface.hpp djinni-output-temp/cpp/enum_usage_interface.hpp
djinni-output-temp/cpp/access_flags.hpp
djinni-output-temp/cpp/empty_flags.hpp
djinni-output-temp/cpp/flag_roundtrip.hpp
djinni-output-temp/cpp/record_with_flags.hpp
djinni-output-temp/cpp/client_returned_record.hpp djinni-output-temp/cpp/client_returned_record.hpp
djinni-output-temp/cpp/client_interface.hpp djinni-output-temp/cpp/client_interface.hpp
djinni-output-temp/cpp/reverse_client_interface.hpp djinni-output-temp/cpp/reverse_client_interface.hpp
...@@ -77,6 +81,10 @@ djinni-output-temp/java/UserToken.java ...@@ -77,6 +81,10 @@ djinni-output-temp/java/UserToken.java
djinni-output-temp/java/Color.java djinni-output-temp/java/Color.java
djinni-output-temp/java/EnumUsageRecord.java djinni-output-temp/java/EnumUsageRecord.java
djinni-output-temp/java/EnumUsageInterface.java djinni-output-temp/java/EnumUsageInterface.java
djinni-output-temp/java/AccessFlags.java
djinni-output-temp/java/EmptyFlags.java
djinni-output-temp/java/FlagRoundtrip.java
djinni-output-temp/java/RecordWithFlags.java
djinni-output-temp/java/ClientReturnedRecord.java djinni-output-temp/java/ClientReturnedRecord.java
djinni-output-temp/java/ClientInterface.java djinni-output-temp/java/ClientInterface.java
djinni-output-temp/java/ReverseClientInterface.java djinni-output-temp/java/ReverseClientInterface.java
...@@ -145,6 +153,12 @@ djinni-output-temp/jni/NativeEnumUsageRecord.hpp ...@@ -145,6 +153,12 @@ djinni-output-temp/jni/NativeEnumUsageRecord.hpp
djinni-output-temp/jni/NativeEnumUsageRecord.cpp djinni-output-temp/jni/NativeEnumUsageRecord.cpp
djinni-output-temp/jni/NativeEnumUsageInterface.hpp djinni-output-temp/jni/NativeEnumUsageInterface.hpp
djinni-output-temp/jni/NativeEnumUsageInterface.cpp djinni-output-temp/jni/NativeEnumUsageInterface.cpp
djinni-output-temp/jni/NativeAccessFlags.hpp
djinni-output-temp/jni/NativeEmptyFlags.hpp
djinni-output-temp/jni/NativeFlagRoundtrip.hpp
djinni-output-temp/jni/NativeFlagRoundtrip.cpp
djinni-output-temp/jni/NativeRecordWithFlags.hpp
djinni-output-temp/jni/NativeRecordWithFlags.cpp
djinni-output-temp/jni/NativeClientReturnedRecord.hpp djinni-output-temp/jni/NativeClientReturnedRecord.hpp
djinni-output-temp/jni/NativeClientReturnedRecord.cpp djinni-output-temp/jni/NativeClientReturnedRecord.cpp
djinni-output-temp/jni/NativeClientInterface.hpp djinni-output-temp/jni/NativeClientInterface.hpp
...@@ -209,6 +223,11 @@ djinni-output-temp/objc/DBColor.h ...@@ -209,6 +223,11 @@ djinni-output-temp/objc/DBColor.h
djinni-output-temp/objc/DBEnumUsageRecord.h djinni-output-temp/objc/DBEnumUsageRecord.h
djinni-output-temp/objc/DBEnumUsageRecord.mm djinni-output-temp/objc/DBEnumUsageRecord.mm
djinni-output-temp/objc/DBEnumUsageInterface.h djinni-output-temp/objc/DBEnumUsageInterface.h
djinni-output-temp/objc/DBAccessFlags.h
djinni-output-temp/objc/DBEmptyFlags.h
djinni-output-temp/objc/DBFlagRoundtrip.h
djinni-output-temp/objc/DBRecordWithFlags.h
djinni-output-temp/objc/DBRecordWithFlags.mm
djinni-output-temp/objc/DBClientReturnedRecord.h djinni-output-temp/objc/DBClientReturnedRecord.h
djinni-output-temp/objc/DBClientReturnedRecord.mm djinni-output-temp/objc/DBClientReturnedRecord.mm
djinni-output-temp/objc/DBClientInterface.h djinni-output-temp/objc/DBClientInterface.h
...@@ -285,6 +304,12 @@ djinni-output-temp/objc/DBEnumUsageRecord+Private.h ...@@ -285,6 +304,12 @@ djinni-output-temp/objc/DBEnumUsageRecord+Private.h
djinni-output-temp/objc/DBEnumUsageRecord+Private.mm djinni-output-temp/objc/DBEnumUsageRecord+Private.mm
djinni-output-temp/objc/DBEnumUsageInterface+Private.h djinni-output-temp/objc/DBEnumUsageInterface+Private.h
djinni-output-temp/objc/DBEnumUsageInterface+Private.mm djinni-output-temp/objc/DBEnumUsageInterface+Private.mm
djinni-output-temp/objc/DBAccessFlags+Private.h
djinni-output-temp/objc/DBEmptyFlags+Private.h
djinni-output-temp/objc/DBFlagRoundtrip+Private.h
djinni-output-temp/objc/DBFlagRoundtrip+Private.mm
djinni-output-temp/objc/DBRecordWithFlags+Private.h
djinni-output-temp/objc/DBRecordWithFlags+Private.mm
djinni-output-temp/objc/DBClientReturnedRecord+Private.h djinni-output-temp/objc/DBClientReturnedRecord+Private.h
djinni-output-temp/objc/DBClientReturnedRecord+Private.mm djinni-output-temp/objc/DBClientReturnedRecord+Private.mm
djinni-output-temp/objc/DBClientInterface+Private.h djinni-output-temp/objc/DBClientInterface+Private.h
......
#include "flag_roundtrip.hpp"
using namespace testsuite;
access_flags FlagRoundtrip::roundtrip_access(access_flags flag) {
return flag;
}
empty_flags FlagRoundtrip::roundtrip_empty(empty_flags flag) {
return flag;
}
std::experimental::optional<access_flags> FlagRoundtrip::roundtrip_access_boxed(std::experimental::optional<access_flags> flag) {
return flag;
}
std::experimental::optional<empty_flags> FlagRoundtrip::roundtrip_empty_boxed(std::experimental::optional<empty_flags> flag) {
return flag;
}
...@@ -2,6 +2,7 @@ package com.dropbox.djinni.test; ...@@ -2,6 +2,7 @@ package com.dropbox.djinni.test;
import junit.framework.TestCase; import junit.framework.TestCase;
import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
public class EnumTest extends TestCase { public class EnumTest extends TestCase {
...@@ -17,4 +18,33 @@ public class EnumTest extends TestCase { ...@@ -17,4 +18,33 @@ public class EnumTest extends TestCase {
m.put(Color.VIOLET, "violet"); m.put(Color.VIOLET, "violet");
TestHelpers.checkEnumMap(m); TestHelpers.checkEnumMap(m);
} }
public void testAccessFlagRoundtrip() {
EnumSet[] flags = {
EnumSet.noneOf(AccessFlags.class),
EnumSet.allOf(AccessFlags.class),
EnumSet.of(AccessFlags.OWNER_READ),
EnumSet.of(AccessFlags.OWNER_READ, AccessFlags.OWNER_WRITE),
EnumSet.of(AccessFlags.OWNER_READ, AccessFlags.OWNER_WRITE, AccessFlags.OWNER_EXECUTE),
};
for(EnumSet flag : flags) {
assertEquals(flag, FlagRoundtrip.roundtripAccess(flag));
assertEquals(flag, FlagRoundtrip.roundtripAccessBoxed(flag));
}
assertEquals(null, FlagRoundtrip.roundtripAccessBoxed(null));
}
public void testEmptyFlagRoundtrip() {
EnumSet[] flags = {
EnumSet.noneOf(EmptyFlags.class),
EnumSet.allOf(EmptyFlags.class),
};
for(EnumSet flag : flags) {
assertEquals(flag, FlagRoundtrip.roundtripEmpty(flag));
assertEquals(flag, FlagRoundtrip.roundtripEmptyBoxed(flag));
}
assertEquals(null, FlagRoundtrip.roundtripEmptyBoxed(null));
}
} }
//
// DBFlagsTests.m
// DjinniObjcTest
//
// Created by knejp on 2.8.15.
// Copyright (c) 2015 Dropbox, Inc. All rights reserved.
//
#import "DBAccessFlags.h"
#import "DBEmptyFlags.h"
#import "DBFlagRoundtrip.h"
#import "DJIMarshal+Private.h"
#include "access_flags.hpp"
#include "empty_flags.hpp"
#import <XCTest/XCTest.h>
using testsuite::access_flags;
@interface DBFlagsTests : XCTestCase
@end
@implementation DBFlagsTests
- (void)testOperators {
using T = ::djinni::Enum<access_flags, DBAccessFlags>;
XCTAssertEqual(DBAccessFlagsOwnerRead | DBAccessFlagsOwnerWrite,
T::fromCpp(access_flags::OWNER_READ | access_flags::OWNER_WRITE),
"flag mismatch");
XCTAssertEqual(DBAccessFlagsOwnerRead & DBAccessFlagsEverybody,
T::fromCpp(access_flags::OWNER_READ & access_flags::EVERYBODY),
"flag mismatch");
XCTAssertEqual(DBAccessFlagsOwnerRead ^ DBAccessFlagsNobody,
T::fromCpp(access_flags::OWNER_READ ^ access_flags::NOBODY),
"flag mismatch");
XCTAssertEqual(access_flags::GROUP_READ | access_flags::GROUP_EXECUTE,
T::toCpp(DBAccessFlagsGroupRead | DBAccessFlagsGroupExecute),
"flag mismatch");
XCTAssertEqual(access_flags::GROUP_READ & access_flags::EVERYBODY,
T::toCpp(DBAccessFlagsGroupRead & DBAccessFlagsEverybody),
"flag mismatch");
XCTAssertEqual(access_flags::GROUP_READ ^ access_flags::NOBODY,
T::toCpp(DBAccessFlagsGroupRead ^ DBAccessFlagsNobody),
"flag mismatch");
XCTAssertEqual(access_flags::SYSTEM_READ,
access_flags::SYSTEM_READ | access_flags::NOBODY,
"neutral flag wrong");
XCTAssertEqual(access_flags::NOBODY,
access_flags::SYSTEM_WRITE & ~access_flags::SYSTEM_WRITE,
"bitwise not wrong");
}
- (void)testRoundtripAccess {
DBAccessFlags flags[] = {
DBAccessFlagsNobody,
DBAccessFlagsEverybody,
DBAccessFlagsOwnerRead,
DBAccessFlagsOwnerRead | DBAccessFlagsOwnerWrite,
DBAccessFlagsOwnerRead | DBAccessFlagsOwnerWrite | DBAccessFlagsOwnerExecute,
};
for(auto flag : flags) {
XCTAssertEqual(flag, [DBFlagRoundtrip roundtripAccess:flag], "roundtrip failed");
XCTAssertEqual(flag, [[DBFlagRoundtrip roundtripAccessBoxed:@(flag)] unsignedIntegerValue], "roundtrip failed");
}
XCTAssertEqual(nil, [DBFlagRoundtrip roundtripAccessBoxed:nil], "roundtrip failed");
}
- (void)testRoundtripEmpty {
DBEmptyFlags flags[] = {
DBEmptyFlagsNone,
DBEmptyFlagsAll,
};
for(auto flag : flags) {
XCTAssertEqual(flag, [DBFlagRoundtrip roundtripEmpty:flag], "roundtrip failed");
XCTAssertEqual(flag, [[DBFlagRoundtrip roundtripEmptyBoxed:@(flag)] unsignedIntegerValue], "roundtrip failed");
}
XCTAssertEqual(nil, [DBFlagRoundtrip roundtripEmptyBoxed:nil], "roundtrip failed");
}
@end
...@@ -27,7 +27,7 @@ RUN wget http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.3-bin.tar.gz ...@@ -27,7 +27,7 @@ RUN wget http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.3-bin.tar.gz
RUN tar xvfvz apache-ant-1.9.3-bin.tar.gz -C /opt RUN tar xvfvz apache-ant-1.9.3-bin.tar.gz -C /opt
ENV ANT_HOME /opt/apache-ant-1.9.3/bin/ant ENV ANT_HOME /opt/apache-ant-1.9.3/bin/ant
RUN ln -s /opt/apache-ant-1.9.3/bin/ant /usr/bin/ant RUN ln -s /opt/apache-ant-1.9.3/bin/ant /usr/bin/ant
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.51-1.b16.el6_7.x86_64 ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk.x86_64
VOLUME /opt/djinni VOLUME /opt/djinni
CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh
......
...@@ -6,11 +6,12 @@ RUN echo "deb http://http.debian.net/debian jessie-backports main" >> /etc/apt/s ...@@ -6,11 +6,12 @@ RUN echo "deb http://http.debian.net/debian jessie-backports main" >> /etc/apt/s
RUN apt-get update RUN apt-get update
RUN apt-get -y install build-essential clang llvm cmake RUN apt-get -y install build-essential clang llvm cmake
RUN apt-get install -y -t jessie-backports ca-certificates-java
RUN apt-get install -y openjdk-8-jdk ant RUN apt-get install -y openjdk-8-jdk ant
# Select Java 8 # Select Java 8
RUN update-java-alternatives -s java-1.8.0-openjdk-amd64 RUN update-java-alternatives -s java-1.8.0-openjdk-amd64
RUN rm /usr/lib/jvm/default-java RUN rm -f /usr/lib/jvm/default-java
RUN ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java RUN ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java
ENV CXX clang++ ENV CXX clang++
......
...@@ -12,7 +12,7 @@ RUN echo 1 | update-alternatives --config javac ...@@ -12,7 +12,7 @@ RUN echo 1 | update-alternatives --config javac
# Get modern ant # Get modern ant
RUN yum install -y ant RUN yum install -y ant
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.92-5.b14.fc24.x86_64 ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
VOLUME /opt/djinni VOLUME /opt/djinni
CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh
......
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