Skip to content
Open
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
11 changes: 8 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,14 @@ lazy val enumeratum = project
),
scalatestSettings,
publishSettings,
mimaSettings(),
scalaSettings,
testSettings
mimaSettings(excludeScala3 = true),
scalaSettings ++ Seq(
crossScalaVersions += scala3
),
testSettings,
Test / scalacOptions ++= {
if (scalaVersion.value.startsWith("3")) List("-Yretain-trees") else Nil
}
)
.dependsOn(core, generic)

Expand Down
27 changes: 27 additions & 0 deletions modules/enumeratum/src/main/scala-3/enumeratum/Vulcan.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2019 OVO Energy Limited
*
* SPDX-License-Identifier: Apache-2.0
*/

package enumeratum

import vulcan.{Avro, AvroError, Codec}
import vulcan.internal.Names
import vulcan.generic.deriveEnum

object Vulcan {
def enumCodec[A <: EnumEntry](
`enum`: Enum[A]
)(implicit names: Names[A]): Codec.Aux[Avro.EnumSymbol, A] = {
lazy val entries = `enum`.values.map(_.entryName).mkString(", ")
val notFound = (name: String) =>
AvroError(s"$name is not a member of ${names.typeName} ($entries)")

deriveEnum(
symbols = `enum`.values.map(_.entryName),
encode = _.entryName,
decode = name => `enum`.withNameOption(name).toRight(notFound(name))
)
}
}
14 changes: 14 additions & 0 deletions modules/enumeratum/src/main/scala-3/enumeratum/VulcanEnum.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2019 OVO Energy Limited
*
* SPDX-License-Identifier: Apache-2.0
*/

package enumeratum

import vulcan.Codec
import vulcan.internal.Names

trait VulcanEnum[A <: EnumEntry] { this: Enum[A] =>
given (using names: Names[A]): Codec[A] = Vulcan.enumCodec(this)
}
40 changes: 40 additions & 0 deletions modules/enumeratum/src/main/scala-3/enumeratum/values/Vulcan.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2019 OVO Energy Limited
*
* SPDX-License-Identifier: Apache-2.0
*/

package enumeratum.values

import vulcan.{Avro, AvroError, Codec}
import vulcan.internal.Names
import vulcan.generic.deriveEnum

object Vulcan {
def codec[ValueType, EntryType <: ValueEnumEntry[ValueType]](
`enum`: ValueEnum[ValueType, EntryType]
)(implicit
codec: Codec[ValueType],
names: Names[EntryType]
): Codec.Aux[codec.AvroType, EntryType] = {
lazy val entries = `enum`.values.map(_.value).mkString(", ")
val notFound = (value: ValueType) =>
AvroError(s"$value is not a member of ${names.typeName} ($entries)")

codec.imapError(value => `enum`.withValueOpt(value).toRight(notFound(value)))(_.value)
}

def enumCodec[EntryType <: ValueEnumEntry[String]](
`enum`: ValueEnum[String, EntryType]
)(implicit names: Names[EntryType]): Codec.Aux[Avro.EnumSymbol, EntryType] = {
lazy val entries = `enum`.values.map(_.value).mkString(", ")
val notFound = (value: String) =>
AvroError(s"$value is not a member of ${names.typeName} ($entries)")

deriveEnum(
symbols = `enum`.values.map(_.value),
encode = _.value,
decode = value => `enum`.withValueOpt(value).toRight(notFound(value))
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2019 OVO Energy Limited
*
* SPDX-License-Identifier: Apache-2.0
*/

package enumeratum.values

import vulcan.{Avro, Codec}
import vulcan.internal.Names

sealed trait VulcanValueEnum[ValueType, EntryType <: ValueEnumEntry[ValueType]] {
this: ValueEnum[ValueType, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec[EntryType]
}

trait ByteVulcanEnum[EntryType <: ByteEnumEntry] extends VulcanValueEnum[Byte, EntryType] {
this: ValueEnum[Byte, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec.Aux[Avro.Int, EntryType] =
Vulcan.codec(this)
}

trait CharVulcanEnum[EntryType <: CharEnumEntry] extends VulcanValueEnum[Char, EntryType] {
this: ValueEnum[Char, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec.Aux[Avro.String, EntryType] =
Vulcan.codec(this)
}

trait IntVulcanEnum[EntryType <: IntEnumEntry] extends VulcanValueEnum[Int, EntryType] {
this: ValueEnum[Int, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec.Aux[Avro.Int, EntryType] =
Vulcan.codec(this)
}

trait LongVulcanEnum[EntryType <: LongEnumEntry] extends VulcanValueEnum[Long, EntryType] {
this: ValueEnum[Long, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec.Aux[Avro.Long, EntryType] =
Vulcan.codec(this)
}

trait ShortVulcanEnum[EntryType <: ShortEnumEntry] extends VulcanValueEnum[Short, EntryType] {
this: ValueEnum[Short, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec.Aux[Avro.Int, EntryType] =
Vulcan.codec(this)
}

trait StringVulcanEnum[EntryType <: StringEnumEntry] extends VulcanValueEnum[String, EntryType] {
this: ValueEnum[String, EntryType] =>

given vulcanCodec(using names: Names[EntryType]): Codec.Aux[Avro.EnumSymbol, EntryType] =
Vulcan.enumCodec(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package enumeratum.values

import vulcan.generic.{AvroDoc, AvroNamespace}

sealed abstract class CustomByteEnum(val value: Byte) extends ByteEnumEntry

object CustomByteEnum extends ByteEnum[CustomByteEnum] with ByteVulcanEnum[CustomByteEnum] {
case object First extends CustomByteEnum(1)
case object Second extends CustomByteEnum(2)
case object Third extends CustomByteEnum(3)

val values = findValues

override def withValueOpt(i: Byte): Option[CustomByteEnum] =
if (i == 3) None
else super.withValueOpt(i)
}

sealed abstract class CustomCharEnum(val value: Char) extends CharEnumEntry

object CustomCharEnum extends CharEnum[CustomCharEnum] with CharVulcanEnum[CustomCharEnum] {
case object First extends CustomCharEnum('1')
case object Second extends CustomCharEnum('2')
case object Third extends CustomCharEnum('3')

val values = findValues

override def withValueOpt(c: Char): Option[CustomCharEnum] =
if (c == '3') None
else super.withValueOpt(c)
}

sealed abstract class CustomIntEnum(val value: Int) extends IntEnumEntry

object CustomIntEnum extends IntEnum[CustomIntEnum] with IntVulcanEnum[CustomIntEnum] {
case object First extends CustomIntEnum(1)
case object Second extends CustomIntEnum(2)
case object Third extends CustomIntEnum(3)

val values = findValues

override def withValueOpt(i: Int): Option[CustomIntEnum] =
if (i == 3) None
else super.withValueOpt(i)
}

sealed abstract class CustomLongEnum(val value: Long) extends LongEnumEntry

object CustomLongEnum extends LongEnum[CustomLongEnum] with LongVulcanEnum[CustomLongEnum] {
case object First extends CustomLongEnum(1L)
case object Second extends CustomLongEnum(2L)
case object Third extends CustomLongEnum(3L)

val values = findValues

override def withValueOpt(l: Long): Option[CustomLongEnum] =
if (l == 3L) None
else super.withValueOpt(l)
}

sealed abstract class CustomShortEnum(val value: Short) extends ShortEnumEntry

object CustomShortEnum extends ShortEnum[CustomShortEnum] with ShortVulcanEnum[CustomShortEnum] {
case object First extends CustomShortEnum(1)
case object Second extends CustomShortEnum(2)
case object Third extends CustomShortEnum(3)

val values = findValues

override def withValueOpt(s: Short): Option[CustomShortEnum] =
if (s == 3) None
else super.withValueOpt(s)
}

@AvroNamespace("com.example")
@AvroDoc("Custom enumeration")
sealed abstract class CustomStringEnum(val value: String) extends StringEnumEntry

object CustomStringEnum
extends StringEnum[CustomStringEnum]
with StringVulcanEnum[CustomStringEnum] {
case object First extends CustomStringEnum("first")
case object Second extends CustomStringEnum("second")
case object Third extends CustomStringEnum("third")

val values = findValues

override def withValueOpt(s: String): Option[CustomStringEnum] =
if (s == "third") None
else super.withValueOpt(s)
}
Loading
Loading