Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions bzl/deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,18 @@ def djinni_deps():
url = "https://github.com/bazelbuild/rules_jvm_external/archive/{}.zip".format(rules_jvm_external_tag),
sha256 = "62133c125bf4109dfd9d2af64830208356ce4ef8b165a6ef15bbff7460b35c3a",
)

# Override zlib to use custom BUILD file that excludes problematic gz* files on macOS
zlib_version = "1.2.11"
maybe(
http_archive,
name = "zlib",
build_file = "//third_party/zlib:BUILD.bazel",
sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1",
strip_prefix = "zlib-{}".format(zlib_version),
urls = [
"https://mirror.bazel.build/zlib.net/zlib-{}.tar.gz".format(zlib_version),
"https://zlib.net/zlib-{}.tar.gz".format(zlib_version),
],
)

6 changes: 5 additions & 1 deletion src/source/CppGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
}
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = {
val refs = new CppRefs(ident.name)
val self = marshal.typename(ident, e)

Expand Down Expand Up @@ -125,6 +125,10 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
})
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, pe: djinni.ast.ProtobufEnum): Unit = {
// C++ protobuf enums are already defined by the protobuf library
}

def shouldConstexpr(c: Const) = {
// Make sure we don't constexpr optionals as some might not support it
val canConstexpr = c.ty.resolved.base match {
Expand Down
8 changes: 8 additions & 0 deletions src/source/CppMarshal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
case i: Interface => idCpp.ty(name)
case r: Record => idCpp.ty(name)
case p: ProtobufMessage => idCpp.ty(name)
case p: ProtobufEnum => idCpp.enumType(name)
}

override def fqTypename(tm: MExpr): String = toCppType(tm, Some(spec.cppNamespace), Seq())
Expand All @@ -44,6 +45,7 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
case i: Interface => withNs(Some(spec.cppNamespace), idCpp.ty(name))
case r: Record => withNs(Some(spec.cppNamespace), idCpp.ty(name))
case p: ProtobufMessage => withNs(Some(p.cpp.ns), idCpp.ty(name))
case p: ProtobufEnum => withNs(Some(p.cpp.ns), p.cpp.typename)
}

def paramType(tm: MExpr, scopeSymbols: Seq[String]): String = toCppParamType(tm, None, scopeSymbols)
Expand Down Expand Up @@ -113,6 +115,8 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
}
case p: ProtobufMessage =>
List(ImportRef(p.cpp.header))
case p: ProtobufEnum =>
List(ImportRef(p.cpp.header))
}
case e: MExtern => e.defType match {
// Do not forward declare extern types, they might be in arbitrary namespaces.
Expand All @@ -127,6 +131,8 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
}
case p: MProtobuf =>
List(ImportRef(p.body.cpp.header))
case p: MProtobufEnum =>
List(ImportRef(p.body.cpp.header))
case p: MParam => List()
case MVoid => List()
}
Expand Down Expand Up @@ -202,6 +208,7 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
}
case p: MParam => idCpp.typeParam(p.name)
case p: MProtobuf => withNs(Some(p.body.cpp.ns), p.name)
case p: MProtobufEnum => withNs(Some(p.body.cpp.ns), p.body.cpp.typename)
case MVoid => "void"
}
def expr(tm: MExpr): String = {
Expand Down Expand Up @@ -269,6 +276,7 @@ class CppMarshal(spec: Spec) extends Marshal(spec) {
case r: Record => false
case e: Enum => true
case p: ProtobufMessage => false
case p: ProtobufEnum => true
}

// this can be used in c++ generation to know whether a const& should be applied to the parameter or not
Expand Down
51 changes: 38 additions & 13 deletions src/source/JNIGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,18 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
def writeJniHppFile(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit = (w => {})) =
writeHppFileGeneric(spec.jniHeaderOutFolder.get, spec.jniNamespace, spec.jniFileIdentStyle)(name, origin, includes, fwds, f, f2)

class JNIRefs(name: String, cppPrefixOverride: Option[String]=None) {
class JNIRefs(name: String, cppPrefixOverride: Option[String]=None, customCppHeader: Option[String]=None) {
var jniHpp = mutable.TreeSet[String]()
var jniCpp = mutable.TreeSet[String]()

val cppPrefix = cppPrefixOverride.getOrElse(spec.jniIncludeCppPrefix)
jniHpp.add("#include " + q(cppPrefix + spec.cppFileIdentStyle(name) + "." + spec.cppHeaderExt))
// Add the C++ header - either custom (for protobuf enums) or auto-generated
customCppHeader match {
case Some(header) => jniHpp.add("#include " + header)
case None =>
val cppPrefix = cppPrefixOverride.getOrElse(spec.jniIncludeCppPrefix)
jniHpp.add("#include " + q(cppPrefix + spec.cppFileIdentStyle(name) + "." + spec.cppHeaderExt))
}

jniHpp.add("#include " + q(spec.jniBaseLibIncludePrefix + "djinni_support.hpp"))
spec.cppNnHeader match {
case Some(nnHdr) => jniHpp.add("#include " + nnHdr)
Expand All @@ -60,37 +66,56 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
}
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
val refs = new JNIRefs(ident.name)
// Helper method to generate JNI enum from either protobuf or regular enum
private def generateJniEnum(origin: String, ident: Ident, typeDef: TypeDef, customHeader: Option[String],
baseClass: String, isFlags: Boolean, enumCount: Int) {
val refs = new JNIRefs(ident.name, customCppHeader = customHeader)
val jniHelper = jniMarshal.helperClass(ident)
val cppSelf = cppMarshal.fqTypename(ident, e)
val cppSelf = cppMarshal.fqTypename(ident.name, typeDef)

writeJniHppFile(ident, origin, Iterable.concat(refs.jniHpp, refs.jniCpp), Nil, w => {
val base = if(e.flags) "JniFlags" else "JniEnum"
val count = normalEnumOptions(e).length
w.w(s"class $jniHelper final : ::djinni::$base").bracedSemi {
w.w(s"class $jniHelper final : ::djinni::$baseClass").bracedSemi {
w.wlOutdent("public:")
w.wl(s"using CppType = $cppSelf;")
w.wl(s"using JniType = jobject;")
w.wl
w.wl(s"using Boxed = $jniHelper;")
w.wl
if(e.flags) {
if(isFlags) {
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); }")
w.wl(s"static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, CppType c) { return ::djinni::JniClass<$jniHelper>::get().create(jniEnv, static_cast<unsigned>(c), $enumCount); }")
} 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.wlOutdent("private:")
val classLookup = q(jniMarshal.undecoratedTypename(ident, e))
w.wl(s"$jniHelper() : $base($classLookup) {}")
val classLookup = typeDef match {
case pe: ProtobufEnum =>
// For protobuf enums: baseClass + $ + typename (with $ separators)
val baseClassPath = pe.java.baseClass.replaceAllLiterally(".", "/")
val nestedClassPath = pe.java.typename.replaceAllLiterally(".", "$")
q(s"${baseClassPath}$$${nestedClassPath}")
case _ =>
// For regular enums, use the standard naming
q(jniMarshal.undecoratedTypename(ident.name, typeDef))
}
w.wl(s"$jniHelper() : $baseClass($classLookup) {}")
w.wl(s"friend ::djinni::JniClass<$jniHelper>;")
}
})
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = {
val baseClass = if(e.flags) "JniFlags" else "JniEnum"
val enumCount = normalEnumOptions(e).length
generateJniEnum(origin, ident, e, None, baseClass, e.flags, enumCount)
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, pe: djinni.ast.ProtobufEnum): Unit = {
generateJniEnum(origin, ident, pe, Some(pe.cpp.header), "JniEnum", false, 0)
}

override def generateRecord(origin: String, ident: Ident, doc: Doc, params: Seq[TypeParam], r: Record) {
val prefixOverride: Option[String] = if (r.ext.cpp) {
Some(spec.cppExtendedRecordIncludePrefix)
Expand Down
9 changes: 9 additions & 0 deletions src/source/JNIMarshal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) {
case _ => headers
}
}
case pe: MProtobufEnum => List(ImportRef(include(pe.name)))
case d: MDef => List(ImportRef(include(d.name)))
case e: MExtern => List(ImportRef(resolveExtJniHdr(e.jni.header)))
case _ => List()
Expand Down Expand Up @@ -118,6 +119,12 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) {
val prefix = p.body.java.pkg.replaceAllLiterally(".", "/")
s"L${prefix}$$${p.name};"
}
case p: MProtobufEnum => {
// For protobuf enums: baseClass + $ + typename (with $ separators)
val baseClassPath = p.body.java.baseClass.replaceAllLiterally(".", "/")
val nestedClassPath = p.body.java.typename.replaceAllLiterally(".", "$")
s"L${baseClassPath}$$${nestedClassPath};"
}
}

// Regexp shortcut
Expand All @@ -142,6 +149,7 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) {

def helperName(tm: MExpr): String = tm.base match {
case d: MDef => withNs(Some(spec.jniNamespace), helperClass(d.name))
case pe: MProtobufEnum => withNs(Some(spec.jniNamespace), helperClass(pe.name))
case e: MExtern => e.jni.translator
case o => withNs(Some("djinni"), o match {
case p: MPrimitive => p.idlName match {
Expand All @@ -161,6 +169,7 @@ class JNIMarshal(spec: Spec) extends Marshal(spec) {
case MSet => "Set"
case MMap => "Map"
case MProtobuf(_,_,_) => "Protobuf"
case MProtobufEnum(_,_,_) => throw new AssertionError("unreachable")
case MArray => "Array"
case d: MDef => throw new AssertionError("unreachable")
case e: MExtern => throw new AssertionError("unreachable")
Expand Down
6 changes: 5 additions & 1 deletion src/source/JavaGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
}
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = {
val refs = new JavaRefs()

writeJavaFile(ident, origin, refs.java, w => {
Expand All @@ -141,6 +141,10 @@ class JavaGenerator(spec: Spec) extends Generator(spec) {
})
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, pe: djinni.ast.ProtobufEnum): Unit = {
// Java protobuf enums are already defined by the protobuf library
}

override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface) {
val refs = new JavaRefs()

Expand Down
4 changes: 4 additions & 0 deletions src/source/JavaMarshal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
case _ => List()
}
case p: MProtobuf => List(ImportRef(withPackage(Some(p.body.java.pkg), p.name)))
case p: MProtobufEnum => List(ImportRef(p.body.java.baseClass + "." + p.body.java.typename))
case e if isEnumFlags(e) => List(ImportRef("java.util.EnumSet"))
case _ => List()
}
Expand Down Expand Up @@ -85,6 +86,7 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
case r: Record => true
case e: Enum => true
case p: ProtobufMessage => true
case p: djinni.ast.ProtobufEnum => true
}

def isEnumFlags(m: Meta): Boolean = m match {
Expand Down Expand Up @@ -118,6 +120,7 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
case MArray => toJavaType(tm.args.head, packageName) + "[]"
case e: MExtern => (if(needRef) e.java.boxed else e.java.typename) + (if(e.java.generic) args(tm) else "")
case p: MProtobuf => p.name
case p: MProtobufEnum => p.body.java.baseClass + "." + p.body.java.typename
case o =>
val base = o match {
case p: MPrimitive => if (needRef) p.jBoxed else p.jName
Expand All @@ -132,6 +135,7 @@ class JavaMarshal(spec: Spec) extends Marshal(spec) {
case d: MDef => withPackage(packageName, idJava.ty(d.name))
case e: MExtern => throw new AssertionError("unreachable")
case e: MProtobuf => throw new AssertionError("unreachable")
case e: MProtobufEnum => throw new AssertionError("unreachable")
case p: MParam => idJava.typeParam(p.name)
case MVoid => "Void"
}
Expand Down
6 changes: 5 additions & 1 deletion src/source/ObjcGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) {
}
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = {
val refs = new ObjcRefs()

refs.header.add("#import <Foundation/Foundation.h>")
Expand All @@ -70,6 +70,10 @@ class ObjcGenerator(spec: Spec) extends BaseObjcGenerator(spec) {
})
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, pe: djinni.ast.ProtobufEnum): Unit = {
// Objective-C protobuf enums are already defined by the protobuf library
}

def bodyName(ident: String): String = idObjc.ty(ident) + "." + spec.objcppExt // Must be a Obj-C++ file in case the constants are not compile-time constant expressions

def writeObjcConstMethDecl(c: Const, w: IndentWriter) {
Expand Down
15 changes: 15 additions & 0 deletions src/source/ObjcMarshal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class ObjcMarshal(spec: Spec) extends Marshal(spec) {

def cppProtoType(tm: MExpr):Option[String] = tm.base match {
case MProtobuf(name, _, ProtobufMessage(cpp, _, None, _)) => Some(cpp.ns + "::" + name)
case MProtobufEnum(name, _, enum) => enum.objc match {
case Some(_) => None // Use ObjC type if available
case None => throw new AssertionError(s"Protobuf enum '$name' requires Objective-C definition in yaml")
}
case _ => None
}

Expand All @@ -56,6 +60,7 @@ class ObjcMarshal(spec: Spec) extends Marshal(spec) {
case DRecord => if(e.objc.pointer) nonnull else None
}
case MProtobuf(_, _, ProtobufMessage(_, _, None, _)) => None
case MProtobufEnum(_, _, _) => None
case _ => nonnull
}
}
Expand Down Expand Up @@ -108,6 +113,10 @@ class ObjcMarshal(spec: Spec) extends Marshal(spec) {
case Some(o) => List(ImportRef(o.header))
case None => List(ImportRef(p.body.cpp.header))
}
case p: MProtobufEnum => p.body.objc match {
case Some(o) => List(ImportRef(o.header))
case None => List(ImportRef(p.body.cpp.header))
}
case p: MParam => List()
}

Expand All @@ -124,13 +133,15 @@ class ObjcMarshal(spec: Spec) extends Marshal(spec) {
case r: Record => true
case e: Enum => false
case p: ProtobufMessage => true
case p: djinni.ast.ProtobufEnum => false
}

def boxedTypename(td: TypeDecl) = td.body match {
case i: Interface => typename(td.ident, i)
case r: Record => typename(td.ident, r)
case e: Enum => "NSNumber"
case p: ProtobufMessage => typename(td.ident, p)
case p: djinni.ast.ProtobufEnum => "NSNumber"
}

// Return value: (Type_Name, Is_Class_Or_Not)
Expand Down Expand Up @@ -184,6 +195,10 @@ class ObjcMarshal(spec: Spec) extends Marshal(spec) {
case Some(o) => (o.prefix + p.name, true)
case None => (p.body.cpp.ns + "::" + p.name, true)
}
case p: MProtobufEnum => p.body.objc match {
case Some(o) => (o.typename, false)
case None => throw new AssertionError(s"Protobuf enum '${p.name}' requires Objective-C definition in yaml")
}
case p: MParam => throw new AssertionError("Parameter should not happen at Obj-C top level")
case MVoid => ("NSNull", true)
}
Expand Down
6 changes: 5 additions & 1 deletion src/source/ObjcppGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,18 @@ class ObjcppGenerator(spec: Spec) extends BaseObjcGenerator(spec) {

private def arcAssert(w: IndentWriter) = w.wl("static_assert(__has_feature(objc_arc), " + q("Djinni requires ARC to be enabled for this file") + ");")

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = {
var imports = mutable.TreeSet[String]()
imports.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIMarshal+Private.h"))
imports.add("!#include " + q(spec.objcppIncludeCppPrefix + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt))

writeObjcFile(objcppMarshal.privateHeaderName(ident.name), origin, imports, w => {} )
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, pe: djinni.ast.ProtobufEnum): Unit = {
// Objective-C++ protobuf enums are already defined by the protobuf library
}

def headerName(ident: String): String = idObjc.ty(ident) + "." + spec.objcHeaderExt
def privateBodyName(ident: String): String = idObjc.ty(ident) + "+Private." + spec.objcppExt

Expand Down
11 changes: 11 additions & 0 deletions src/source/ObjcppMarshal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class ObjcppMarshal(spec: Spec) extends Marshal(spec) {
case Some(o) => List(ImportRef(q(spec.objcBaseLibIncludePrefix + "DJIMarshal+Private.h")), ImportRef(o.header))
case None => List(ImportRef(q(spec.objcBaseLibIncludePrefix + "DJIMarshal+Private.h")))
}
case p: MProtobufEnum => p.body.objc match {
case Some(o) => List(ImportRef(q(spec.objcBaseLibIncludePrefix + "DJIMarshal+Private.h")), ImportRef(o.header))
case None => List(ImportRef(q(spec.objcBaseLibIncludePrefix + "DJIMarshal+Private.h")))
}
case d: MDef => d.defType match {
case DEnum | DInterface =>
List(ImportRef(include(m)))
Expand Down Expand Up @@ -98,6 +102,12 @@ class ObjcppMarshal(spec: Spec) extends Marshal(spec) {
case None => withNs(Some("djinni"), "ProtobufPassthrough") + "<" +
withNs(Some(p.body.cpp.ns), p.name) + ">"
}
case p: MProtobufEnum => p.body.objc match {
case Some(o) => withNs(Some("djinni"), "Enum") + "<" +
withNs(Some(p.body.cpp.ns), p.body.cpp.typename) + ", " + o.typename + ">"
case None => withNs(Some("djinni"), "ProtobufEnumPassthrough") + "<" +
withNs(Some(p.body.cpp.ns), p.body.cpp.typename) + ">"
}
case o => withNs(Some("djinni"), o match {
case p: MPrimitive => p.idlName match {
case "i8" => "I8"
Expand All @@ -120,6 +130,7 @@ class ObjcppMarshal(spec: Spec) extends Marshal(spec) {
case e: MExtern => throw new AssertionError("unreachable")
case p: MParam => throw new AssertionError("not applicable")
case p: MProtobuf => throw new AssertionError("not applicable")
case p: MProtobufEnum => throw new AssertionError("not applicable")
case MVoid => "Void"
})
}
Expand Down
Loading
Loading