
org.scalacheck.derive.MkShrink.scala Maven / Gradle / Ivy
package org.scalacheck
package derive
import shapeless._
/**
* Derives `Shrink[T]` instances for `T` an `HList`, a `Coproduct`,
* a case class or an ADT (or more generally, a type represented
* `Generic`ally as an `HList` or a `Coproduct`).
*
* The instances derived here are more specific than the default ones
* derived for any type by `Shrink.shrinkAny`.
*
* Use like
* val shrink: Shrink[T] = MkShrink[T].shrink
* or look up for an implicit `MkShrink[T]`.
*/
trait MkShrink[T] {
/** `Shrink[T]` instance built by this `MkShrink[T]` */
def shrink: Shrink[T]
}
object MkShrink {
def apply[T](implicit mkShrink: MkShrink[T]): MkShrink[T] = mkShrink
def instance[T](shrink0: => Shrink[T]): MkShrink[T] =
new MkShrink[T] {
def shrink = shrink0
}
private def lazyxmap[T, U](from: T => U, to: U => T)(st: => Shrink[T]): Shrink[U] = Shrink[U] { u: U ⇒
st.shrink(to(u)).map(from)
}
implicit def genericProduct[P, L <: HList]
(implicit
gen: Generic.Aux[P, L],
shrink: Lazy[MkHListShrink[L]]
): MkShrink[P] =
instance(
lazyxmap(gen.from, gen.to)(shrink.value.shrink)
)
implicit def genericCoproduct[S, C <: Coproduct]
(implicit
gen: Generic.Aux[S, C],
shrink: Lazy[MkCoproductShrink[C]]
): MkShrink[S] =
instance(
lazyxmap(gen.from, gen.to)(shrink.value.shrink)
)
}
trait MkHListShrink[L <: HList] {
/** `Shrink[T]` instance built by this `MkHListShrink[T]` */
def shrink: Shrink[L]
}
object MkHListShrink {
def apply[L <: HList](implicit mkShrink: MkHListShrink[L]): MkHListShrink[L] = mkShrink
def instance[L <: HList](shrink0: => Shrink[L]): MkHListShrink[L] =
new MkHListShrink[L] {
def shrink = shrink0
}
implicit val hnil: MkHListShrink[HNil] =
instance(Shrink.shrinkAny)
implicit def hcons[H, T <: HList]
(implicit
headShrink: Strict[Shrink[H]],
tailShrink: MkHListShrink[T]
): MkHListShrink[H :: T] =
instance(
Shrink {
case h :: t =>
headShrink.value.shrink(h).map(_ :: t) #:::
tailShrink.shrink.shrink(t).map(h :: _)
}
)
}
trait MkCoproductShrink[C <: Coproduct] {
/** `Shrink[T]` instance built by this `MkCoproductShrink[T]` */
def shrink: Shrink[C]
}
object MkCoproductShrink {
def apply[T <: Coproduct](implicit mkShrink: MkCoproductShrink[T]): MkCoproductShrink[T] = mkShrink
def instance[T <: Coproduct](shrink0: => Shrink[T]): MkCoproductShrink[T] =
new MkCoproductShrink[T] {
def shrink = shrink0
}
implicit val cnil: MkCoproductShrink[CNil] =
instance(Shrink.shrinkAny)
implicit def ccons[H, T <: Coproduct]
(implicit
headShrink: Strict[Shrink[H]],
tailShrink: MkCoproductShrink[T],
headSingletons: Strict[Singletons[H]],
tailSingletons: Strict[Singletons[T]]
): MkCoproductShrink[H :+: T] =
instance(
Shrink {
case Inl(h) =>
tailSingletons.value().toStream.map(Inr(_)) ++ headShrink.value.shrink(h).map(Inl(_))
case Inr(t) =>
headSingletons.value().toStream.map(Inl(_)) ++ tailShrink.shrink.shrink(t).map(Inr(_))
}
)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy