Created
August 25, 2019 14:45
-
-
Save zsolt-donca/a009e219978a50b202cf45e495631bc4 to your computer and use it in GitHub Desktop.
EnumCodec.scala - working
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
package testing | |
import shapeless.labelled.FieldType | |
import shapeless.{:+:, CNil, Coproduct, HNil, Inl, Inr, LabelledGeneric, Lazy, Witness, labelled} | |
trait EnumCodec[T] { | |
def encode: T => String | |
def decode: String => Option[T] | |
} | |
object EnumCodec { | |
def apply[T](implicit instance: EnumCodec[T]): EnumCodec[T] = instance | |
implicit def genInst[T, R](implicit gen: LabelledGeneric.Aux[T, R], genEnumCodec: EnumCodec[R]): EnumCodec[T] = new EnumCodec[T] { | |
override def encode: T => String = value => genEnumCodec.encode(gen.to(value)) | |
override def decode: String => Option[T] = genEnumCodec.decode andThen (_.map(gen.from)) | |
} | |
implicit def sumEnumCodec[K <: Symbol, H, T <: Coproduct](implicit | |
witness: Witness.Aux[K], | |
hEncoder: Lazy[EnumCase[H]], | |
tEncoder: EnumCodec[T] | |
): EnumCodec[FieldType[K, H] :+: T] = | |
new EnumCodec[FieldType[K, H] :+: T] { | |
override def encode: FieldType[K, H] :+: T => String = { | |
case Inl(_) => witness.value.name | |
case Inr(tail) => tEncoder.encode(tail) | |
} | |
override def decode: String => Option[FieldType[K, H] :+: T] = value => { | |
if (value == witness.value.name) { | |
val value = hEncoder.value.value | |
Some(Inl(labelled.field[K](value))) | |
} else { | |
tEncoder.decode(value).map(Inr(_)) | |
} | |
} | |
} | |
implicit def cnilEnumCodec: EnumCodec[CNil] = new EnumCodec[CNil] { | |
override def encode: CNil => String = sys.error("Impossible") | |
override def decode: String => Option[CNil] = _ => None | |
} | |
} | |
trait EnumCase[T] { | |
def value: T | |
} | |
object EnumCase { | |
implicit def hNilCase: EnumCase[HNil] = new EnumCase[HNil] { | |
override def value: HNil = HNil | |
} | |
implicit def caseObjectEnumCase[T, R](implicit gen: LabelledGeneric.Aux[T, R], enumCase: EnumCase[R]): EnumCase[T] = new EnumCase[T] { | |
override def value: T = gen.from(enumCase.value) | |
} | |
} | |
sealed trait TestEnum | |
case object CaseOne extends TestEnum | |
object CirceEnumCodecTest extends App { | |
val enumCodec: EnumCodec[TestEnum] = EnumCodec[TestEnum] | |
assert(enumCodec.encode(CaseOne) == "CaseOne") | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment