Skip to content

Commit

Permalink
Fixing enum and some macro warnings. (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
luksow committed Dec 22, 2021
1 parent a4e1d5f commit db6cff2
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ import enumeratum.{Enum, EnumEntry}
import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf}

trait EnumUnmarshallers {
final def enumUnmarshaller[E <: EnumEntry](enum: Enum[E]): FromStringUnmarshaller[E] = Unmarshaller { _ => name =>
enum.withNameInsensitiveOption(name) match {
final def enumUnmarshaller[E <: EnumEntry](`enum`: Enum[E]): FromStringUnmarshaller[E] = Unmarshaller { _ =>name =>
`enum`.withNameInsensitiveOption(name) match {
case Some(enumEntry) => FastFuture.successful(enumEntry)
case None =>
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${enum.namesToValuesMap.keysIterator
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${`enum`.namesToValuesMap.keysIterator
.mkString(", ")}"""))
}
}

implicit def kebsEnumUnmarshaller[E <: EnumEntry](implicit ev: EnumOf[E]): FromStringUnmarshaller[E] =
enumUnmarshaller(ev.enum)
enumUnmarshaller(ev.`enum`)
}

trait ValueEnumUnmarshallers {
final def valueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E]): Unmarshaller[V, E] = Unmarshaller { _ => v =>
enum.withValueOpt(v) match {
final def valueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E]): Unmarshaller[V, E] = Unmarshaller { _ =>v =>
`enum`.withValueOpt(v) match {
case Some(enumEntry) => FastFuture.successful(enumEntry)
case None =>
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${enum.valuesToEntriesMap.keysIterator
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.valuesToEntriesMap.keysIterator
.mkString(", ")}"""))
}
}
Expand Down
60 changes: 30 additions & 30 deletions circe/src/main/scala/pl/iterators/kebs/circe/KebsEnumFormats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,57 @@ import io.circe._
import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf}

trait CirceEnum {
@inline protected final def enumNameDeserializationError[E <: EnumEntry](enum: Enum[E], name: String): String = {
val enumNames = enum.namesToValuesMap.values.mkString(", ")
@inline protected final def enumNameDeserializationError[E <: EnumEntry](`enum`: Enum[E], name: String): String = {
val enumNames = `enum`.namesToValuesMap.values.mkString(", ")
s"$name should be one of $enumNames"
}

@inline protected final def enumValueDeserializationError[E <: EnumEntry](enum: Enum[E], value: Json): String = {
val enumNames = enum.namesToValuesMap.values.mkString(", ")
@inline protected final def enumValueDeserializationError[E <: EnumEntry](`enum`: Enum[E], value: Json): String = {
val enumNames = `enum`.namesToValuesMap.values.mkString(", ")
s"$value should be a string of value $enumNames"
}

protected final def enumDecoder[E <: EnumEntry](enum: Enum[E], _comap: String => Option[E]): Decoder[E] =
protected final def enumDecoder[E <: EnumEntry](`enum`: Enum[E], _comap: String => Option[E]): Decoder[E] =
(c: HCursor) =>
Decoder.decodeString.emap(str => _comap(str).toRight("")).withErrorMessage(enumValueDeserializationError(enum, c.value))(c)
Decoder.decodeString.emap(str => _comap(str).toRight("")).withErrorMessage(enumValueDeserializationError(`enum`, c.value))(c)

protected final def enumEncoder[E <: EnumEntry](enum: Enum[E], _map: E => String): Encoder[E] =
protected final def enumEncoder[E <: EnumEntry](`enum`: Enum[E], _map: E => String): Encoder[E] =
(obj: E) => Encoder.encodeString(_map(obj))

def enumDecoder[E <: EnumEntry](enum: Enum[E]): Decoder[E] =
enumDecoder[E](enum, enum.withNameInsensitiveOption(_))
def enumEncoder[E <: EnumEntry](enum: Enum[E]): Encoder[E] =
enumEncoder[E](enum, (e: EnumEntry) => e.entryName)
def enumDecoder[E <: EnumEntry](`enum`: Enum[E]): Decoder[E] =
enumDecoder[E](`enum`, `enum`.withNameInsensitiveOption(_))
def enumEncoder[E <: EnumEntry](`enum`: Enum[E]): Encoder[E] =
enumEncoder[E](`enum`, (e: EnumEntry) => e.entryName)

def lowercaseEnumDecoder[E <: EnumEntry](enum: Enum[E]): Decoder[E] =
enumDecoder[E](enum, enum.withNameLowercaseOnlyOption(_))
def lowercaseEnumEncoder[E <: EnumEntry](enum: Enum[E]): Encoder[E] =
enumEncoder[E](enum, (e: EnumEntry) => e.entryName.toLowerCase)
def lowercaseEnumDecoder[E <: EnumEntry](`enum`: Enum[E]): Decoder[E] =
enumDecoder[E](`enum`, `enum`.withNameLowercaseOnlyOption(_))
def lowercaseEnumEncoder[E <: EnumEntry](`enum`: Enum[E]): Encoder[E] =
enumEncoder[E](`enum`, (e: EnumEntry) => e.entryName.toLowerCase)

def uppercaseEnumDecoder[E <: EnumEntry](enum: Enum[E]): Decoder[E] =
enumDecoder[E](enum, enum.withNameUppercaseOnlyOption(_))
def uppercaseEnumEncoder[E <: EnumEntry](enum: Enum[E]): Encoder[E] =
enumEncoder[E](enum, (e: EnumEntry) => e.entryName.toUpperCase())
def uppercaseEnumDecoder[E <: EnumEntry](`enum`: Enum[E]): Decoder[E] =
enumDecoder[E](`enum`, `enum`.withNameUppercaseOnlyOption(_))
def uppercaseEnumEncoder[E <: EnumEntry](`enum`: Enum[E]): Encoder[E] =
enumEncoder[E](`enum`, (e: EnumEntry) => e.entryName.toUpperCase())
}

trait CirceValueEnum {
@inline protected final def valueEnumDeserializationError[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E], value: Json): String = {
val enumValues = enum.valuesToEntriesMap.keys.mkString(", ")
@inline protected final def valueEnumDeserializationError[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E], value: Json): String = {
val enumValues = `enum`.valuesToEntriesMap.keys.mkString(", ")
s"$value is not a member of $enumValues"
}

def valueEnumDecoder[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E])(implicit decoder: Decoder[V]): Decoder[E] =
def valueEnumDecoder[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E])(implicit decoder: Decoder[V]): Decoder[E] =
(c: HCursor) =>
decoder.emap(obj => enum.withValueOpt(obj).toRight("")).withErrorMessage(valueEnumDeserializationError(enum, c.value))(c)
decoder.emap(obj => `enum`.withValueOpt(obj).toRight("")).withErrorMessage(valueEnumDeserializationError(`enum`, c.value))(c)

def valueEnumEncoder[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E])(implicit encoder: Encoder[V]): Encoder[E] =
def valueEnumEncoder[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E])(implicit encoder: Encoder[V]): Encoder[E] =
(obj: E) => encoder(obj.value)
}

trait KebsEnumFormats extends CirceEnum with CirceValueEnum {
implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] = enumDecoder(ev.enum)
implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] = enumDecoder(ev.`enum`)

implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] = enumEncoder(ev.enum)
implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] = enumEncoder(ev.`enum`)

implicit def valueEnumDecoder[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E], decoder: Decoder[V]): Decoder[E] =
valueEnumDecoder(ev.valueEnum)
Expand All @@ -67,18 +67,18 @@ trait KebsEnumFormats extends CirceEnum with CirceValueEnum {

trait Uppercase extends CirceEnum {
implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] =
uppercaseEnumDecoder(ev.enum)
uppercaseEnumDecoder(ev.`enum`)

implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] =
uppercaseEnumEncoder(ev.enum)
uppercaseEnumEncoder(ev.`enum`)
}

trait Lowercase extends CirceEnum {
implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] =
lowercaseEnumDecoder(ev.enum)
lowercaseEnumDecoder(ev.`enum`)

implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] =
lowercaseEnumEncoder(ev.enum)
lowercaseEnumEncoder(ev.`enum`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ object AkkaHttpUnmarshallers {
case class PaginationQuery(sortBy: Column, sortOrder: SortOrder, offset: Offset, limit: Limit)

object BeforeKebs {
final def enumUnmarshaller[E <: EnumEntry](enum: Enum[E]): FromStringUnmarshaller[E] = Unmarshaller { _ => name =>
enum.withNameInsensitiveOption(name) match {
final def enumUnmarshaller[E <: EnumEntry](`enum`: Enum[E]): FromStringUnmarshaller[E] = Unmarshaller { _ =>name =>
`enum`.withNameInsensitiveOption(name) match {
case Some(enumEntry) => FastFuture.successful(enumEntry)
case None =>
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${enum.namesToValuesMap.keysIterator
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${`enum`.namesToValuesMap.keysIterator
.mkString(", ")}"""))
}
}
final def valueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E]): Unmarshaller[V, E] = Unmarshaller { _ => v =>
enum.withValueOpt(v) match {
final def valueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E]): Unmarshaller[V, E] = Unmarshaller { _ =>v =>
`enum`.withValueOpt(v) match {
case Some(enumEntry) => FastFuture.successful(enumEntry)
case None =>
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${enum.valuesToEntriesMap.keysIterator
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.valuesToEntriesMap.keysIterator
.mkString(", ")}"""))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import enumeratum.{Enum, EnumEntry}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class EnumOf[E <: EnumEntry](val enum: Enum[E])
class EnumOf[E <: EnumEntry](val `enum`: Enum[E])

object EnumOf {
implicit def enumOf[E <: EnumEntry]: EnumOf[E] = macro EnumEntryMacros.enumOfImpl[E]
Expand Down
20 changes: 10 additions & 10 deletions slick/src/main/scala/pl/iterators/kebs/enums/KebsEnums.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf}
import slick.lifted.Isomorphism

trait SlickEnum {
def enumIsomorphism[E <: EnumEntry](enum: Enum[E]): Isomorphism[E, String] = new Isomorphism[E, String](_.entryName, enum.withName)
def uppercaseEnumIsomorphism[E <: EnumEntry](enum: Enum[E]): Isomorphism[E, String] =
new Isomorphism[E, String](_.entryName.toUpperCase, enum.withNameUppercaseOnly)
def lowercaseEnumIsomorphism[E <: EnumEntry](enum: Enum[E]): Isomorphism[E, String] =
new Isomorphism[E, String](_.entryName.toLowerCase, enum.withNameLowercaseOnly)
def enumIsomorphism[E <: EnumEntry](`enum`: Enum[E]): Isomorphism[E, String] = new Isomorphism[E, String](_.entryName, `enum`.withName)
def uppercaseEnumIsomorphism[E <: EnumEntry](`enum`: Enum[E]): Isomorphism[E, String] =
new Isomorphism[E, String](_.entryName.toUpperCase, `enum`.withNameUppercaseOnly)
def lowercaseEnumIsomorphism[E <: EnumEntry](`enum`: Enum[E]): Isomorphism[E, String] =
new Isomorphism[E, String](_.entryName.toLowerCase, `enum`.withNameLowercaseOnly)

implicit def enumListColumnType[E <: EnumEntry](implicit iso: Isomorphism[E, String]): Isomorphism[List[E], List[String]] =
new Isomorphism[List[E], List[String]](_.map(iso.map), _.map(iso.comap))
Expand All @@ -19,21 +19,21 @@ trait SlickEnum {
}

trait SlickValueEnum {
def valueEnumIsomorphism[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E]): Isomorphism[E, V] =
new Isomorphism[E, V](_.value, enum.withValue)
def valueEnumIsomorphism[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E]): Isomorphism[E, V] =
new Isomorphism[E, V](_.value, `enum`.withValue)
}

trait KebsEnums extends SlickEnum with SlickValueEnum {
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = enumIsomorphism(ev.enum)
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = enumIsomorphism(ev.`enum`)
implicit def valueEnumColumn[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E]): Isomorphism[E, V] =
valueEnumIsomorphism(ev.valueEnum)

trait Uppercase extends SlickEnum {
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = uppercaseEnumIsomorphism(ev.enum)
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = uppercaseEnumIsomorphism(ev.`enum`)
}

trait Lowercase extends SlickEnum {
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = lowercaseEnumIsomorphism(ev.enum)
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = lowercaseEnumIsomorphism(ev.`enum`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,56 @@ import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf}
import spray.json.{JsString, JsValue, JsonFormat}

trait SprayJsonEnum {
@inline protected final def enumNameDeserializationError[E <: EnumEntry](enum: Enum[E], name: String) = {
val enumNames = enum.namesToValuesMap.values.mkString(", ")
@inline protected final def enumNameDeserializationError[E <: EnumEntry](`enum`: Enum[E], name: String) = {
val enumNames = `enum`.namesToValuesMap.values.mkString(", ")
spray.json.deserializationError(s"$name should be one of $enumNames")
}

@inline protected final def enumValueDeserializationError[E <: EnumEntry](enum: Enum[E], value: JsValue) = {
val enumNames = enum.namesToValuesMap.values.mkString(", ")
@inline protected final def enumValueDeserializationError[E <: EnumEntry](`enum`: Enum[E], value: JsValue) = {
val enumNames = `enum`.namesToValuesMap.values.mkString(", ")
spray.json.deserializationError(s"$value should be a string of value $enumNames")
}

protected final def enumJsonFormat[E <: EnumEntry](enum: Enum[E], map: E => String, comap: String => Option[E]) = new JsonFormat[E] {
protected final def enumJsonFormat[E <: EnumEntry](`enum`: Enum[E], map: E => String, comap: String => Option[E]) = new JsonFormat[E] {
override def write(obj: E): JsValue = JsString(map(obj))
override def read(json: JsValue): E = json match {
case JsString(name) => comap(name).getOrElse(enumNameDeserializationError(enum, name))
case _ => enumValueDeserializationError(enum, json)
case JsString(name) => comap(name).getOrElse(enumNameDeserializationError(`enum`, name))
case _ => enumValueDeserializationError(`enum`, json)
}
}
def jsonFormat[E <: EnumEntry](enum: Enum[E]) = enumJsonFormat[E](enum, _.entryName, enum.withNameInsensitiveOption(_))
def lowercaseJsonFormat[E <: EnumEntry](enum: Enum[E]) =
enumJsonFormat[E](enum, _.entryName.toLowerCase, enum.withNameLowercaseOnlyOption(_))
def uppercaseJsonFormat[E <: EnumEntry](enum: Enum[E]) =
enumJsonFormat[E](enum, _.entryName.toUpperCase, enum.withNameUppercaseOnlyOption(_))
def jsonFormat[E <: EnumEntry](`enum`: Enum[E]) = enumJsonFormat[E](`enum`, _.entryName, `enum`.withNameInsensitiveOption(_))
def lowercaseJsonFormat[E <: EnumEntry](`enum`: Enum[E]) =
enumJsonFormat[E](`enum`, _.entryName.toLowerCase, `enum`.withNameLowercaseOnlyOption(_))
def uppercaseJsonFormat[E <: EnumEntry](`enum`: Enum[E]) =
enumJsonFormat[E](`enum`, _.entryName.toUpperCase, `enum`.withNameUppercaseOnlyOption(_))
}

trait SprayJsonValueEnum {
@inline protected final def valueEnumDeserializationError[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E], value: V) = {
val enumValues = enum.valuesToEntriesMap.keys.mkString(", ")
@inline protected final def valueEnumDeserializationError[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E], value: V) = {
val enumValues = `enum`.valuesToEntriesMap.keys.mkString(", ")
spray.json.deserializationError(s"$value is not a member of $enumValues")
}

def jsonFormat[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E])(implicit baseJsonFormat: JsonFormat[V]) = new JsonFormat[E] {
def jsonFormat[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E])(implicit baseJsonFormat: JsonFormat[V]) = new JsonFormat[E] {
override def write(obj: E): JsValue = baseJsonFormat.write(obj.value)
override def read(json: JsValue): E = {
val value = baseJsonFormat.read(json)
enum.withValueOpt(value).getOrElse(valueEnumDeserializationError(enum, value))
`enum`.withValueOpt(value).getOrElse(valueEnumDeserializationError(`enum`, value))
}
}
}

trait KebsEnumFormats extends SprayJsonEnum with SprayJsonValueEnum {
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = jsonFormat(ev.enum)
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = jsonFormat(ev.`enum`)
implicit def jsonValueEnumFormat[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E],
baseJsonFormat: JsonFormat[V]): JsonFormat[E] = jsonFormat(ev.valueEnum)

trait Uppercase extends SprayJsonEnum {
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = uppercaseJsonFormat(ev.enum)
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = uppercaseJsonFormat(ev.`enum`)
}

trait Lowercase extends SprayJsonEnum {
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = lowercaseJsonFormat(ev.enum)
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = lowercaseJsonFormat(ev.`enum`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ final class macroImpl(val c: whitebox.Context) {
case Some(ModuleDef(mods, companionName, template)) =>
val generatedMethods = List(generateFromMethod, generateApplyMethod)
ModuleDef(mods, companionName, Template(template.parents, template.self, template.body ++ generatedMethods))
case Some(_) =>
c.abort(c.enclosingPosition, "Could not generate companion for tagged type, check proper context for @tagged")
case None =>
q"object ${name.toTermName} { ..${List(generateFromMethod, generateApplyMethod)} }"
}
Expand Down Expand Up @@ -155,6 +157,8 @@ final class macroImpl(val c: whitebox.Context) {
maybeCompanion match {
case Some(ModuleDef(mods, companionName, template)) =>
ModuleDef(mods, companionName, Template(template.parents, template.self, template.body ++ implicits))
case Some(_) =>
c.abort(c.enclosingPosition, "Could not generate companion for tagged type, check proper context for @tagged")
case None =>
q"object ${tagName.toTermName} { ..$implicits }"
}
Expand Down

0 comments on commit db6cff2

Please sign in to comment.