All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shapeless.sybclass.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011-15 Miles Sabin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package shapeless

import poly._

/**
 * An implementation of [http://research.microsoft.com/en-us/um/people/simonpj/papers/hmap/
 * "Scrap your boilerplate with class"] in Scala.
 *
 * @author Miles Sabin
 */

/**
 * Type class representing one-level generic queries.
 */
trait Data[F, T, R] extends Serializable {
  def gmapQ(t: T): List[R]
}

trait Data0 {
  /**
   * Default Data type class instance.
   */
  implicit def dfltData[F, T, R]: Data[F, T, R] = new Data[F, T, R] {
    def gmapQ(t: T): List[R] = Nil
  }
}

trait Data1 extends Data0 {
  implicit def deriveInstance[P, F, R, G](implicit gen: Generic.Aux[F, G], dg: Lazy[Data[P, G, R]]): Data[P, F, R] =
    new Data[P, F, R] {
      def gmapQ(t: F) = dg.value.gmapQ(gen.to(t))
    }
}

object Data extends Data1 {
  import scala.collection.{ Map, GenTraversable }

  def apply[P, T, R](implicit dt: Lazy[Data[P, T, R]]): Data[P, T, R] = dt.value

  def gmapQ[F, T, R](f: F)(t: T)(implicit data: Lazy[Data[F, T, R]]) = data.value.gmapQ(t)

  /**
   * Data type class instance for `List`s.
   */
  @deprecated("Superseded by genTraversableData", "2.3.1")
  def listData[P, T, R](implicit qt: Lazy[Case1.Aux[P, T, R]]): Data[P, List[T], R] =
    new Data[P, List[T], R] {
      def gmapQ(t: List[T]) = t.map(qt.value(_))
    }

  implicit def genTraversableData[P, C[X] <: GenTraversable[X], T, R]
    (implicit qt: Lazy[Case1.Aux[P, T, R]]): Data[P, C[T], R] =
      new Data[P, C[T], R] {
        def gmapQ(t: C[T]) =
          t.foldLeft(List.newBuilder[R]) { (b, el) =>
            b += qt.value(el)
          }.result
      }

  implicit def genMapData[P, M[X, Y], K, V, R]
    (implicit ev: M[K, V] <:< Map[K, V], qv: Lazy[Case1.Aux[P, (K, V), R]]): Data[P, M[K, V], R] =
      new Data[P, M[K, V], R] {
        def gmapQ(t: M[K, V]) =
          t.foldLeft(List.newBuilder[R]) { case (b, el) =>
            b += qv.value(el)
          }.result
      }

  implicit def deriveHNil[P, R]: Data[P, HNil, R] =
    new Data[P, HNil, R] {
      def gmapQ(t: HNil) = Nil
    }

  implicit def deriveHCons[P, H, T <: HList, R]
    (implicit ch: Lazy[Case1.Aux[P, H, R]], dt: Lazy[Data[P, T, R]]): Data[P, H :: T, R] =
      new Data[P, H :: T, R] {
        def gmapQ(t: H :: T) = ch.value(t.head :: HNil) :: dt.value.gmapQ(t.tail)
      }

  implicit def deriveCNil[P, R]: Data[P, CNil, R] =
    new Data[P, CNil, R] {
      def gmapQ(t: CNil) = Nil
    }

  implicit def deriveCCons[P, H, T <: Coproduct, R]
    (implicit ch: Lazy[Case1.Aux[P, H, R]], dt: Lazy[Data[P, T, R]]): Data[P, H :+: T, R] =
      new Data[P, H :+: T, R] {
        def gmapQ(c: H :+: T) =
          c match {
            case Inl(h) => List(ch.value(h :: HNil))
            case Inr(t) => dt.value.gmapQ(t)
          }
      }
}

/**
 * Type class representing one-level generic transformations.
 */
trait DataT[F, T] extends Serializable {
  type Out
  def gmapT(t: T): Out
}

trait DataT0 {
  type Aux[F, T, Out0] = DataT[F, T] { type Out = Out0 }

  /**
   * Default DataT type class instance.
   */
  implicit def dfltDataT[F, T]: Aux[F, T, T] = new DataT[F, T] {
    type Out = T
    def gmapT(t: T) = t
  }
}

trait DataT1 extends DataT0 {
  implicit def deriveInstance[P, F, G]
    (implicit gen: Generic.Aux[F, G], dtg: Lazy[DataT.Aux[P, G, G]]): Aux[P, F, F] =
      new DataT[P, F] {
        type Out = F
        def gmapT(t: F) = gen.from(dtg.value.gmapT(gen.to(t)))
      }
}

object DataT extends DataT1 {
  import scala.collection.{ GenMap, Iterable }
  import scala.collection.Factory

  def apply[P, T](implicit dtt: Lazy[DataT[P, T]]): DataT[P, T] = dtt.value

  def gmapT[F, T](f: F)(t: T)(implicit data: Lazy[DataT[F, T]]) = data.value.gmapT(t)

  /**
   * DataT type class instance for `List`s.
   */
  @deprecated("Superseded by genTraversableDataT", "2.3.1")
  def listDataT[F <: Poly, T, U](implicit ft: Lazy[Case1.Aux[F, T, U]]): Aux[F, List[T], List[U]] =
    new DataT[F, List[T]] {
      type Out = List[U]
      def gmapT(t: List[T]) = t.map(ft.value)
    }

  implicit def genTraversableDataT[F <: Poly, CC[X] <: Iterable[X], T, U]
    (implicit ft: Lazy[Case1.Aux[F, T, U]], cbf: Factory[U, CC[U]]): Aux[F, CC[T], CC[U]] =
      new DataT[F, CC[T]] {
        type Out = CC[U]
        def gmapT(t: CC[T]) =
          t.foldLeft(cbf.newBuilder) { (b, x) =>
            b += ft.value(x)
          }.result
      }

  implicit def genMapDataT[F <: Poly, M[X, Y], K, V, U]
    (implicit
      ev: M[K, V] <:< GenMap[K, V],
      fv: Lazy[Case1.Aux[F, V, U]],
      cbf: Factory[(K, U), M[K, U]]
    ): Aux[F, M[K, V], M[K, U]] =
      new DataT[F, M[K, V]] {
        type Out = M[K, U]
        def gmapT(t: M[K, V]) =
          t.foldLeft(cbf.newBuilder) { case (b, (k, v)) =>
            b += k -> fv.value(v)
          }.result
      }

  implicit def deriveHNil[P]: Aux[P, HNil, HNil] =
    new DataT[P, HNil] {
      type Out = HNil
      def gmapT(t: HNil) = HNil
    }

  implicit def deriveHCons[P, H, T <: HList, OutH, OutT <: HList]
    (implicit ch: Lazy[Case1.Aux[P, H, OutH]], dtt: Lazy[DataT.Aux[P, T, OutT]]): Aux[P, H :: T, OutH :: OutT] =
      new DataT[P, H :: T] {
        type Out = OutH :: OutT
        def gmapT(t: H :: T): Out = ch.value(t.head :: HNil) :: dtt.value.gmapT(t.tail)
      }

  implicit def deriveCNil[P]: Aux[P, CNil, CNil] =
    new DataT[P, CNil] {
      type Out = CNil
      def gmapT(t: CNil) = sys.error("CNil is equivelant to Nothing: there should be no values of this type")
    }

  implicit def deriveCCons[P, H, T <: Coproduct, OutH, OutT <: Coproduct]
    (implicit ch: Lazy[Case1.Aux[P, H, OutH]], dtt: Lazy[DataT.Aux[P, T, OutT]]): Aux[P, H :+: T, OutH :+: OutT] =
      new DataT[P, H :+: T] {
        type Out = OutH :+: OutT
        def gmapT(c: H :+: T) = c match {
          case Inl(h) => Inl(ch.value(h :: HNil))
          case Inr(t) => Inr(dtt.value.gmapT(t))
        }
      }
}

class EverythingAux[F, K] extends Poly

object EverythingAux {
  implicit def default[E, F <: Poly, K <: Poly, T, R]
    (implicit
      unpack: Unpack2[E, EverythingAux, F, K],
      f: Case1.Aux[F, T, R],
      data: Lazy[Data[E, T, R]],
      k: Case2.Aux[K, R, R, R]
    ): Case1.Aux[E, T, R] = Case1[E, T, R](t => data.value.gmapQ(t).foldLeft(f(t))(k))
}

class EverywhereAux[F] extends Poly

object EverywhereAux {
  implicit def default[E, F <: Poly, T, U, V]
    (implicit
      unpack: Unpack1[E, EverywhereAux, F],
      data: Lazy[DataT.Aux[E, T, U]],
      f: Case1.Aux[F, U, V] = Case1[F, U, U](identity)
    ): Case1.Aux[E, T, V] = Case1[E, T, V](t => f(data.value.gmapT(t)))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy