Skip to content

Instantly share code, notes, and snippets.

@elyphas
Created May 24, 2020 23:37
Show Gist options
  • Save elyphas/0ee7267766bf0662113ae2eda347183a to your computer and use it in GitHub Desktop.
Save elyphas/0ee7267766bf0662113ae2eda347183a to your computer and use it in GitHub Desktop.
package encoderLabelledGeneric
import typesJson._
import shapeless.{HList, ::, HNil, Lazy}
import shapeless.Witness
import shapeless.labelled.FieldType
import shapeless.LabelledGeneric
import shapeless._
import syntax.singleton._
import record._
object HelpersLabelledGeneric2 {
trait JsonEncoder[A] {
def encode(value: A): JsonValue
}
object JsonEncoder {
def apply[A](implicit enc: JsonEncoder[A]): JsonEncoder[A] = enc
}
implicit val stringEncoder: JsonEncoder[String] = createEncoder( str => JsonString(str) )
implicit val doubleEncoder: JsonEncoder[Double] = createEncoder( num => JsonNumber(num) )
implicit val intEncoder: JsonEncoder[Int] = createEncoder( num => JsonNumber(num) )
implicit val booleanEncoder: JsonEncoder[Boolean] = createEncoder( bool => JsonBoolean(bool) )
implicit def listEncoder[A](implicit enc: JsonEncoder[A]): JsonEncoder[List[A]] = createEncoder( list => JsonArray( list.map( enc.encode ) ) )
implicit def optionEncoder[A](implicit enc: JsonEncoder[A]): JsonEncoder[Option[A]] = createEncoder( opt => opt.map( enc.encode ).getOrElse( JsonNull ) )
def createEncoder[A](func: A => JsonValue): JsonEncoder[A] = new JsonEncoder[A] {
def encode ( value: A ): JsonValue = func( value )
}
trait JsonObjectEncoder[A] extends JsonEncoder[A] {
def encode(value: A): JsonObject
}
def createObjectEncoder[A](fn: A => JsonObject): JsonObjectEncoder[A] = new JsonObjectEncoder[A] {
def encode(value: A): JsonObject = fn ( value )
}
implicit val hnilEncoder: JsonObjectEncoder[HNil] = createObjectEncoder ( hnil => JsonObject ( Nil ) )
implicit def hlistObjectEncoder[K <: Symbol, H, T <: HList]( implicit witness: Witness.Aux[K],
hEncoder: Lazy[JsonEncoder[H]],
tEncoder: JsonObjectEncoder[T]
): JsonObjectEncoder[FieldType[K, H] :: T] = {
val fieldName: String = witness.value.name
createObjectEncoder { hlist =>
val head = hEncoder.value.encode ( hlist.head )
val tail = tEncoder.encode ( hlist.tail )
JsonObject ( ( fieldName, head ) :: tail.fields )
//JsonObject ( fieldName ->> head :: tail.fields )
}
}
implicit def genericObjectEncoder[A, H]( implicit generic: LabelledGeneric.Aux[A, H],
hEncoder: Lazy[JsonObjectEncoder[H]]
): JsonEncoder[A] =
createObjectEncoder { value => hEncoder.value.encode ( generic.to ( value ) ) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment