-
-
Notifications
You must be signed in to change notification settings - Fork 285
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
See #633
- Loading branch information
Showing
5 changed files
with
156 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
compiler-plugin/src/main/scala/scalapb/compiler/SealedOneofsGenerator.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package scalapb.compiler | ||
|
||
import scalapb.compiler.FunctionalPrinter.PrinterEndo | ||
import com.google.protobuf.Descriptors._ | ||
|
||
sealed trait SealedOneofStyle | ||
|
||
object SealedOneofStyle { | ||
case object Default extends SealedOneofStyle | ||
|
||
case object OrEmpty extends SealedOneofStyle | ||
} | ||
|
||
class SealedOneofsGenerator(message: Descriptor, implicits: DescriptorImplicits) { | ||
import implicits._ | ||
|
||
def generateSealedOneofTrait: PrinterEndo = { fp => | ||
if (!message.isSealedOneofType) fp | ||
else { | ||
val baseType = message.scalaTypeName | ||
val sealedOneofType = message.sealedOneofScalaType | ||
val sealedOneofNonEmptyName = message.sealedOneofNonEmptyName | ||
val sealedOneofNonEmptyType = message.sealedOneofNonEmptyScalaType | ||
val sealedOneofName = message.sealedOneofNameSymbol | ||
val typeMapper = s"_root_.scalapb.TypeMapper[${baseType}, ${sealedOneofType}]" | ||
val oneof = message.getOneofs.get(0) | ||
val typeMapperName = message.sealedOneofNameSymbol + "TypeMapper" | ||
val nonEmptyTopLevel = message.sealedOneofStyle == SealedOneofStyle.OrEmpty | ||
|
||
def addNonEmptySealedTrait: PrinterEndo = _.add( | ||
s"sealed trait $sealedOneofNonEmptyName extends $sealedOneofType", | ||
"" | ||
) | ||
|
||
fp.add( | ||
s"sealed trait $sealedOneofName extends ${message.sealedOneofBaseClasses.mkString(" with ")} {" | ||
) | ||
.addIndented( | ||
s"type MessageType = $baseType", | ||
s"final def isEmpty = this.isInstanceOf[${sealedOneofType}.Empty.type]", | ||
s"final def isDefined = !isEmpty", | ||
s"final def asMessage: $baseType = ${message.sealedOneofScalaType}.$typeMapperName.toBase(this)", | ||
s"final def asNonEmpty: Option[$sealedOneofNonEmptyType] = if (isEmpty) None else Some(this.asInstanceOf[$sealedOneofNonEmptyType])" | ||
) | ||
.add("}") | ||
.add("") | ||
.when(nonEmptyTopLevel)(addNonEmptySealedTrait) | ||
.add(s"object $sealedOneofName {") | ||
.indented( | ||
_.add(s"case object Empty extends $sealedOneofType", "") | ||
.when(!nonEmptyTopLevel)(addNonEmptySealedTrait) | ||
.add( | ||
s"def defaultInstance: ${sealedOneofType} = Empty", | ||
"", | ||
s"implicit val $typeMapperName: $typeMapper = new $typeMapper {" | ||
) | ||
.indented( | ||
_.add( | ||
s"override def toCustom(__base: $baseType): $sealedOneofType = __base.${oneof.scalaName} match {" | ||
).indented( | ||
_.print(oneof.fields) { | ||
case (fp, field) => | ||
fp.add(s"case __v: ${field.oneOfTypeName} => __v.value") | ||
}.add(s"case ${oneof.scalaTypeName}.Empty => Empty") | ||
) | ||
.add("}") | ||
.add( | ||
s"override def toBase(__custom: $sealedOneofType): $baseType = $baseType(__custom match {" | ||
) | ||
.indented( | ||
_.print(oneof.fields) { | ||
case (fp, field) => | ||
fp.add(s"case __v: ${field.scalaTypeName} => ${field.oneOfTypeName}(__v)") | ||
}.add(s"case Empty => ${oneof.scalaTypeName}.Empty") | ||
) | ||
.add("})") | ||
) | ||
.add("}") | ||
) | ||
.add("}") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
syntax = "proto3"; | ||
|
||
package com.thesamet.proto.e2e.or_empty; | ||
|
||
message Lit { | ||
int32 value = 1; | ||
} | ||
|
||
message Add { | ||
Expr lhs = 1; | ||
Expr rhs = 2; | ||
} | ||
|
||
message Expr { | ||
oneof sealed_value_or_empty { | ||
Lit lit = 1; | ||
Add add = 2; | ||
} | ||
} | ||
|
||
message Programs { | ||
repeated Expr programs = 1; | ||
Expr optional_expr = 2; | ||
map<string, Expr> expr_map = 3; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters