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

shapeless.lenses.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2012-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 scala.language.dynamics

import labelled.{ FieldType, field }
import ops.coproduct.{ Inject, Selector => CSelector }
import ops.hlist.{ At, Init, Last, Prepend, Selector, ReplaceAt, Replacer, Tupler }
import ops.record.{ Selector => RSelector, Updater }
import tag.@@

trait Lens[S, A] extends LPLens[S, A] { outer =>
  def get(s: S): A
  def set(s: S)(a: A): S
  def modify(s: S)(f: A => A): S = set(s)(f(get(s)))

  def compose[T](g: Lens[T, S]) = new Lens[T, A] {
    def get(t: T): A = outer.get(g.get(t))
    def set(t: T)(a: A): T = g.modify(t)(outer.set(_)(a))
  }

  def compose[T](g: Prism[T, S]) = new Prism[T, A] {
    def get(t: T): Option[A] = g.get(t).map(outer.get)
    def set(t: T)(a: A): T = g.modify(t)(outer.set(_)(a))
  }

  def >>(n: Nat)(implicit mkLens: MkNthFieldLens[A, n.N]): Lens[S, mkLens.Elem] = mkLens() compose this

  def >>(k: Witness)(implicit mkLens: MkFieldLens[A, k.T]): Lens[S, mkLens.Elem] = mkLens() compose this

  def selectDynamic(k: String)
    (implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, Symbol @@ k.type, Nothing]): mkLens.Out = mkLens(this)

  def apply[B](implicit mkPrism: MkCtorPrism[A, B]): Prism[S, B] = mkPrism() compose this

  def unapply(s: S): Option[A] = Some(get(s))

  def ~[B](other: Lens[S, B]) = new ProductLensBuilder[S, (A, B)] {
    def get(s: S): (A, B) = (outer.get(s), other.get(s))
    def set(s: S)(ab: (A, B)) = other.set(outer.set(s)(ab._1))(ab._2)
  }

  def ~[B](other: Prism[S, B]) = new ProductPrismBuilder[S, (A, B)] {
    def get(s: S): Option[(A, B)] = other.get(s).map((outer.get(s), _))
    def set(s: S)(ab: (A, B)) = other.set(outer.set(s)(ab._1))(ab._2)
  }
}

trait LPLens[S, A] extends Dynamic with Serializable { self: Lens[S, A] =>
  def selectDynamic[B](k: String)
    (implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, Symbol @@ k.type, B], dummy: DummyImplicit): mkLens.Out = mkLens(this)
}

trait Prism[S, A] extends LPPrism[S, A] { outer =>
  def get(s: S): Option[A]
  def set(s: S)(a: A): S
  def modify(s: S)(f: A => A): S = get(s).map(f).map(a => set(s)(a)).getOrElse(s)

  def compose[T](g: Lens[T, S]) = new Prism[T, A] {
    def get(t: T): Option[A] = outer.get(g.get(t))
    def set(t: T)(a: A): T = g.modify(t)(outer.set(_)(a))
  }

  def compose[T](g: Prism[T, S]) = new Prism[T, A] {
    def get(t: T): Option[A] = g.get(t).flatMap(outer.get)
    def set(t: T)(a: A): T = g.modify(t)(outer.set(_)(a))
  }

  def selectDynamic(k: String)
    (implicit mkPrism: MkSelectDynamicOptic[Prism[S, A], A, Symbol @@ k.type, Nothing]): mkPrism.Out = mkPrism(this)

  def apply[B](implicit mkPrism: MkCtorPrism[A, B]): Prism[S, B] = mkPrism() compose this

  def unapply(s: S): Option[A] = get(s)

  def ~[B](other: Lens[S, B]) = new ProductPrismBuilder[S, (A, B)] {
    def get(s: S): Option[(A, B)] = outer.get(s).map((_, other.get(s)))

    def set(s: S)(ab: (A, B)) = other.set(outer.set(s)(ab._1))(ab._2)
  }

  def ~[B](other: Prism[S, B]) = new ProductPrismBuilder[S, (A, B)] {
    def get(s: S): Option[(A, B)] =
      for {
        fst <- outer.get(s)
        snd <- other.get(s)
      } yield (fst, snd)

    def set(s: S)(ab: (A, B)) = other.set(outer.set(s)(ab._1))(ab._2)
  }
}

trait LPPrism[S, A] extends Dynamic with Serializable { self: Prism[S, A] =>
  def selectDynamic[B](k: String)
    (implicit mkPrism: MkSelectDynamicOptic[Prism[S, A], A, Symbol @@ k.type, B], dummy: DummyImplicit): mkPrism.Out = mkPrism(this)
}

trait ProductLensBuilder[C, P <: Product] extends Lens[C, P] with Serializable {
  outer =>
  def ~[T, L <: HList, LT <: HList, Q <: Product, QL <: HList](other: Lens[C, T])
    (implicit
      genp: Generic.Aux[P, L],
      tpp: Tupler.Aux[L, P],
      pre: Prepend.Aux[L, T :: HNil, LT],
      tpq: Tupler.Aux[LT, Q],
      genq: Generic.Aux[Q, QL],
      init: Init.Aux[QL, L],
      last: Last.Aux[QL, T]) =
      new ProductLensBuilder[C, Q] {
        def get(c: C): Q = (genp.to(outer.get(c)) :+ other.get(c)).tupled
        def set(c: C)(q: Q) = {
          val l = genq.to(q)
          other.set(outer.set(c)(l.init.tupled))(l.last)
        }
      }
}

trait ProductPrismBuilder[C, P <: Product] extends Prism[C, P] with Serializable {
  outer =>
  def ~[T, L <: HList, LT <: HList, Q <: Product, QL <: HList](other: Prism[C, T])
    (implicit
      genp: Generic.Aux[P, L],
      tpp: Tupler.Aux[L, P],
      pre: Prepend.Aux[L, T :: HNil, LT],
      tpq: Tupler.Aux[LT, Q],
      genq: Generic.Aux[Q, QL],
      init: Init.Aux[QL, L],
      last: Last.Aux[QL, T]) =
      new ProductPrismBuilder[C, Q] {
        def get(c: C): Option[Q] = 
          for {
            init <- outer.get(c)
            last <- other.get(c)
          } yield (genp.to(init) :+ last).tupled

        def set(c: C)(q: Q) = {
          val l = genq.to(q)
          other.set(outer.set(c)(l.init.tupled))(l.last)
        }
      }
}

object OpticDefns {
  def apply[C] = id[C]

  object compose extends Poly2 {
    implicit def default[A, B, C] = at[Lens[B, C], Lens[A, B]](_ compose _)
  }

  class RootLens[C] extends Lens[C, C] {
    def apply[P <: HList](path: Path[P])(implicit mkPath: MkPathOptic[C, P]): mkPath.Out = mkPath()

    def get(c: C): C = c
    def set(c: C)(f: C): C = f
  }

  def id[C] = new RootLens[C]

  def setLens[E](e: E) =
    new Lens[Set[E], Boolean] {
      def get(s: Set[E]): Boolean = s contains e
      def set(s: Set[E])(b: Boolean): Set[E] = if(b) s+e else s-e
    }

  def mapLens[K, V](k: K) =
    new Lens[Map[K, V], Option[V]] {
      def get(m: Map[K, V]): Option[V] = m get k
      def set(m: Map[K, V])(ov: Option[V]): Map[K, V] = ov match {
        case Some(v) => m+(k -> v)
        case None => m-k
      }
    }

  def mapPrism[K, V](k: K) =
    new Prism[Map[K, V], V] {
      def get(m: Map[K, V]): Option[V] = m get k
      def set(m: Map[K, V])(v: V): Map[K, V] = m+(k -> v)
    }

  def hlistSelectLens[L <: HList, U](implicit mkLens: MkHListSelectLens[L, U]) = mkLens()

  def coproductSelectPrism[C <: Coproduct, T](implicit mkPrism: MkCoproductSelectPrism[C, T]) = mkPrism()

  def hlistNthLens[L <: HList, N <: Nat](implicit mkLens: MkHListNthLens[L, N]) = mkLens()

  def recordLens[R <: HList](k: Witness)(implicit mkLens: MkRecordSelectLens[R, k.T]) = mkLens()
}

trait OpticComposer[L, R] extends Serializable {
  type Out
  def apply(l: L, r: R): Out
}

object OpticComposer {
  type Aux[L, R, Out0] = OpticComposer[L, R] { type Out = Out0 }

  implicit def composeLL[S, A, T]: Aux[Lens[S, A], Lens[T, S], Lens[T, A]] =
    new OpticComposer[Lens[S, A], Lens[T, S]] {
      type Out = Lens[T, A]
      def apply(l: Lens[S, A], r: Lens[T, S]): Lens[T, A] = l compose r
    }

  implicit def composeLP[S, A, T]: Aux[Lens[S, A], Prism[T, S], Prism[T, A]] =
    new OpticComposer[Lens[S, A], Prism[T, S]] {
      type Out = Prism[T, A]
      def apply(l: Lens[S, A], r: Prism[T, S]): Prism[T, A] = l compose r
    }

  implicit def composePL[S, A, T]: Aux[Prism[S, A], Lens[T, S], Prism[T, A]] =
    new OpticComposer[Prism[S, A], Lens[T, S]] {
      type Out = Prism[T, A]
      def apply(l: Prism[S, A], r: Lens[T, S]): Prism[T, A] = l compose r
    }

  implicit def composePP[S, A, T]: Aux[Prism[S, A], Prism[T, S], Prism[T, A]] =
    new OpticComposer[Prism[S, A], Prism[T, S]] {
      type Out = Prism[T, A]
      def apply(l: Prism[S, A], r: Prism[T, S]): Prism[T, A] = l compose r
    }
}

trait MkFieldLens[A, K] extends Serializable {
  type Elem
  def apply(): Lens[A, Elem]
}

object MkFieldLens {
  type Aux[A, K, Elem0] = MkFieldLens[A, K] { type Elem = Elem0 }

  implicit def mkFieldLens[A, K, R <: HList, B]
    (implicit
      mkGen: MkLabelledGenericLens.Aux[A, R],
      mkLens: MkRecordSelectLens[R, K]): Aux[A, K, mkLens.Elem] =
        new MkFieldLens[A, K] {
          type Elem = mkLens.Elem
          def apply(): Lens[A, mkLens.Elem] = mkLens() compose mkGen()
        }
}

trait MkNthFieldLens[A, N <: Nat] extends Serializable {
  type Elem
  def apply(): Lens[A, Elem]
}

object MkNthFieldLens {
  type Aux[A, N <: Nat, Elem0] = MkNthFieldLens[A, N] { type Elem = Elem0 }

  implicit def mkGenPNth[A, N <: Nat, R <: HList, B]
    (implicit
      mkGen: MkGenericLens.Aux[A, R],
      mkLens: MkHListNthLens[R, N]): Aux[A, N, mkLens.Elem] =
        new MkNthFieldLens[A, N] {
          type Elem = mkLens.Elem
          def apply(): Lens[A, mkLens.Elem] = mkLens() compose mkGen()
        }
}

trait MkCtorPrism[A, B] extends Serializable {
  def apply(): Prism[A, B]
}

object MkCtorPrism {
  implicit def mkCtorPrism[A, R <: Coproduct, B]
    (implicit
      mkGen: MkGenericLens.Aux[A, R],
      mkPrism: MkCoproductSelectPrism[R, B]): MkCtorPrism[A, B] =
      new MkCtorPrism[A, B] {
        def apply(): Prism[A, B] = mkPrism() compose mkGen()
      }
}

trait InferProduct[C <: Coproduct, K] extends Serializable {
  type Prod
}

object InferProduct {
  type Aux[C <: Coproduct, K, P] = InferProduct[C, K] { type Prod = P }

  implicit def inferProduct1[P, R <: HList, T <: Coproduct, K]
    (implicit gen: LabelledGeneric.Aux[P, R], sel: RSelector[R, K]): Aux[P :+: T, K, P] =
      new InferProduct[P :+: T, K] {
        type Prod = P
      }

  implicit def inferProduct2[H, T <: Coproduct, K, P](implicit it: Aux[T, K, P]): Aux[H :+: T, K, P] =
    new InferProduct[H :+: T, K] {
      type Prod = P
    }
}

trait MkSelectDynamicOptic[R, A, K, B] extends Serializable {
  type Out
  def apply(r: R): Out
}

trait LowPriorityMkSelectDynamicOptic {
  type Aux[R, A, K, B, Out0] = MkSelectDynamicOptic[R, A, K, B] { type Out = Out0 }

  implicit def mkInferCtorSelField[R, A, C <: Coproduct, I, K, E]
    (implicit
      gen: Generic.Aux[A, C],
      infer: InferProduct.Aux[C, K, I],
      mkCSel: MkCtorPrism[A, I],
      mkPSel: MkFieldLens.Aux[I, K, E],
      compose: OpticComposer[Prism[A, E], R]
    ): Aux[R, A, K, Nothing, compose.Out] =
      new MkSelectDynamicOptic[R, A, K, Nothing] {
        type Out = compose.Out
        def apply(r: R): Out = compose(mkPSel() compose mkCSel(), r)
      }

  implicit def mkSelFieldCtor[R, A, K, B, C]
    (implicit
      mkPSel: MkFieldLens.Aux[A, K, C],
      mkCSel: MkCtorPrism[C, B],
      compose: OpticComposer[Prism[A, B], R]
    ): Aux[R, A, K, B, compose.Out] =
    new MkSelectDynamicOptic[R, A, K, B] {
      type Out = compose.Out
      def apply(r: R): Out = compose(mkCSel() compose mkPSel(), r)
    }
}

object MkSelectDynamicOptic extends LowPriorityMkSelectDynamicOptic {
  implicit def mkSelField[R, A, K, E]
    (implicit
      mkLens: MkFieldLens.Aux[A, K, E],
      compose: OpticComposer[Lens[A, E], R]
    ): Aux[R, A, K, Nothing, compose.Out] =
    new MkSelectDynamicOptic[R, A, K, Nothing] {
      type Out = compose.Out
      def apply(r: R): Out = compose(mkLens(), r)
    }

  implicit def mkSelCtor[R, A, B]
    (implicit
      mkPrism: MkCtorPrism[A, B],
      compose: OpticComposer[Prism[A, B], R]
    ): Aux[R, A, Nothing, B, compose.Out] =
    new MkSelectDynamicOptic[R, A, Nothing, B] {
      type Out = compose.Out
      def apply(r: R): Out = compose(mkPrism(), r)
    }
}

trait MkGenericLens[T] extends Serializable {
  type Repr
  def apply(): Lens[T, Repr]
}

object MkGenericLens {
  type Aux[T, Repr0] = MkGenericLens[T] { type Repr = Repr0 }

  implicit def mkGenericLens[T](implicit gen: Generic[T]): Aux[T, gen.Repr] =
    new MkGenericLens[T] {
      type Repr = gen.Repr
      def apply(): Lens[T, Repr] =
        new Lens[T, Repr] {
          def get(t: T): Repr = gen.to(t)
          def set(t: T)(r: Repr): T = gen.from(r)
        }
    }
}

trait MkLabelledGenericLens[T] extends Serializable {
  type Repr
  def apply(): Lens[T, Repr]
}

object MkLabelledGenericLens {
  type Aux[T, Repr0] = MkLabelledGenericLens[T] { type Repr = Repr0 }

  implicit def mkLabelledGenericLens[T](implicit gen: LabelledGeneric[T]): Aux[T, gen.Repr] =
    new MkLabelledGenericLens[T] {
      type Repr = gen.Repr
      def apply(): Lens[T, Repr] =
        new Lens[T, Repr] {
          def get(t: T): Repr = gen.to(t)
          def set(t: T)(r: Repr): T = gen.from(r)
        }
    }
}

trait MkHListNthLens[L <: HList, N <: Nat] extends Serializable {
  type Elem
  def apply(): Lens[L, Elem]
}

object MkHListNthLens {
  type Aux[L <: HList, N <: Nat, Elem0] = MkHListNthLens[L, N] { type Elem = Elem0 }

  implicit def mkHListNthLens[L <: HList, N <: Nat, E]
    (implicit atx: At.Aux[L, N, E], replace: ReplaceAt.Aux[L, N, E, (E, L)]): Aux[L, N, E] =
    new MkHListNthLens[L, N] {
      type Elem = E
      def apply(): Lens[L, E] =
        new Lens[L, E] {
          def get(l: L): E = l[N]
          def set(l: L)(e: E): L = l.updatedAt[N](e)
        }
    }
}

trait MkHListSelectLens[L <: HList, U] extends Serializable {
  def apply(): Lens[L, U]
}

object MkHListSelectLens {
  implicit def mKHlistSelectLens[L <: HList, U]
    (implicit selector: Selector[L, U], replacer: Replacer.Aux[L, U, U, (U, L)]): MkHListSelectLens[L, U] =
      new MkHListSelectLens[L, U] {
        def apply(): Lens[L, U] =
          new Lens[L, U] {
            def get(l: L) = selector(l)
            def set(l: L)(u: U) = replacer(l, u)._2
          }
      }
}

trait MkCoproductSelectPrism[C <: Coproduct, T] extends Serializable {
  def apply(): Prism[C, T]
}

object MkCoproductSelectPrism {
  implicit def mKCoproductSelectPrism[C <: Coproduct, T]
    (implicit selector: CSelector[C, T], injector: Inject[C, T]): MkCoproductSelectPrism[C, T] =
      new MkCoproductSelectPrism[C, T] {
        def apply(): Prism[C, T] =
          new Prism[C, T] {
            def get(c: C): Option[T] = selector(c)
            def set(c: C)(t: T): C = injector(t)
          }
      }
}

trait MkRecordSelectLens[R <: HList, K] extends Serializable {
  type Elem
  def apply(): Lens[R, Elem]
}

object MkRecordSelectLens {
  type Aux[R <: HList, K, Elem0] = MkRecordSelectLens[R, K] { type Elem = Elem0 }

  implicit def mkRecordSelectLens[R <: HList, K, E]
    (implicit selector: RSelector.Aux[R, K, E], updater: Updater.Aux[R, FieldType[K, E], R]): Aux[R, K, E] =
      new MkRecordSelectLens[R, K] {
        type Elem = E
        def apply(): Lens[R, E] =
          new Lens[R, E] {
            def get(r: R) = selector(r)
            def set(r: R)(e: E) = updater(r, field[K](e))
          }
      }
}

trait MkPathOptic[S, P <: HList] extends Serializable {
  type Out
  type Elem
  def apply(): Out
}

trait LowPriorityMkPathOptic {
  type Aux[S, P <: HList, Out0, E0] = MkPathOptic[S, P] { type Out = Out0 ; type Elem = E0 }

  type Aux1[S, P <: HList, Out0] = MkPathOptic[S, P] { type Out = Out0 }

  implicit def mkCoselSelPathOptic[S, P <: HList, K, A, C <: Coproduct, I, E, R]
    (implicit
      mkPrefix: Aux[S, P, R, A],
      gen: Generic.Aux[A, C],
      infer: InferProduct.Aux[C, K, I],
      mkPrism: MkCtorPrism[A, I],
      mkLens: MkFieldLens.Aux[I, K, E],
      compose: OpticComposer[Prism[A, E], R]
    ): Aux[S, Select[K] :: P, compose.Out, E] =
      new MkPathOptic[S, Select[K] :: P] {
        type Out = compose.Out
        type Elem = E
        def apply(): compose.Out = compose(mkLens() compose mkPrism(), mkPrefix())
      }
}

object MkPathOptic extends LowPriorityMkPathOptic {
  implicit def mkHNilPathLens[S]: Aux[S, HNil, Lens[S, S], S] =
    new MkPathOptic[S, HNil] {
      type Out = Lens[S, S]
      type Elem = S
      def apply(): Lens[S, S] = lens[S]
    }

  implicit def mkSelPathOptic[S, P <: HList, K, A, E, R]
    (implicit
      mkPrefix: Aux[S, P, R, A],
      mkLens: MkFieldLens.Aux[A, K, E],
      compose: OpticComposer[Lens[A, E], R]
    ): Aux[S, Select[K] :: P, compose.Out, E] =
      new MkPathOptic[S, Select[K] :: P] {
        type Out = compose.Out
        type Elem = E
        def apply(): compose.Out = compose(mkLens(), mkPrefix())
      }

  implicit def mkCoselPathOptic[S, P <: HList, B, A, R]
    (implicit
      mkPrefix: Aux[S, P, R, A],
      mkPrism: MkCtorPrism[A, B],
      compose: OpticComposer[Prism[A, B], R]
    ): Aux[S, Coselect[B] :: P, compose.Out, B] =
      new MkPathOptic[S, Coselect[B] :: P] {
        type Out = compose.Out
        type Elem = B
        def apply(): compose.Out = compose(mkPrism(), mkPrefix())
      }
}

trait Select[T]
trait Coselect[T]

trait Segment[P, S, T <: HList] {
  type Out <: HList
}

trait LowPrioritySegment {
  type Aux[P, S, T <: HList, Out0 <: HList] = Segment[P, S, T] { type Out = Out0 }

  implicit def two[P, S, T <: HList]: Aux[P, S, T, Coselect[S] :: Select[Symbol @@ P] :: T] = new Segment[P, S, T] {
    type Out = Coselect[S] :: Select[Symbol @@ P] :: T
  }
}

object Segment extends LowPrioritySegment {
  implicit def one[P, T <: HList]: Aux[P, Nothing, T, Select[Symbol @@ P] :: T] = new Segment[P, Nothing, T] {
    type Out = Select[Symbol @@ P] :: T
  }
}

trait Path[T <: HList] extends LPPath[T] {
  type P = Path[T]
  type L = T

  type Lens[T, E] = MkPathOptic.Aux1[T, L, shapeless.Lens[T, E]]
  type Prism[T, E] = MkPathOptic.Aux1[T, L, shapeless.Prism[T, E]]

  def apply[H]: Path[Coselect[H] :: T] = new Path[Coselect[H] :: T] {}

  def selectDynamic(h: String)(implicit segment: Segment[h.type, Nothing, T]): Path[segment.Out] =
    new Path[segment.Out] {}
}

trait LPPath[T <: HList] extends Dynamic { self: Path[T] =>
  def selectDynamic[H](h: String)(implicit segment: Segment[h.type, H, T], dummy: DummyImplicit): Path[segment.Out] =
    new Path[segment.Out] {}
}

object Path extends Path[HNil]




© 2015 - 2024 Weber Informatics LLC | Privacy Policy