From 3caafe7374004ce64a3d78566132b9dee42496c2 Mon Sep 17 00:00:00 2001 From: Nicholas Yip Date: Mon, 28 Jan 2019 00:37:34 +0900 Subject: [PATCH] Enable `asRoot` on `FilePath.Empty` --- .../eyrie/instances/DescendantInstances.scala | 82 ++++++++++++++----- .../scala/eyrie/ops/PotentialDescendant.scala | 15 +++- .../syntax/PotentialDescendantSyntax.scala | 3 + .../file/instances/FilePathConvertible.scala | 6 +- .../file/instances/FilePathInstances.scala | 4 +- .../file/test/PotentialDescendantSpec.scala | 12 ++- 6 files changed, 92 insertions(+), 30 deletions(-) diff --git a/core/src/main/scala/eyrie/instances/DescendantInstances.scala b/core/src/main/scala/eyrie/instances/DescendantInstances.scala index 7144e8c..b61aa31 100644 --- a/core/src/main/scala/eyrie/instances/DescendantInstances.scala +++ b/core/src/main/scala/eyrie/instances/DescendantInstances.scala @@ -31,23 +31,6 @@ trait DescendantInstances { private[eyrie] trait DescendantByInputInstances { - implicit def eyrieTrivialByInputInstance[A]( - implicit A: TrivialDescendant[A] - ): Descendant.ByInput.Aux[A, A] = - eyrieAmbiguousTrivialByInputInstance - - implicit def eyrieAmbiguousTrivialByInputInstance[A]( - implicit A: TrivialDescendant[A] - ): Descendant.ByInput.Aux[A, A] = - new Descendant.ByInput[A] { - override - type Root = A - - override - def root: A => A = - A.root - } - implicit def eyrieDescendantByInputInstance[A, B]( implicit A: Descendant[A, B] ): Descendant.ByInput.Aux[A, B] = @@ -59,6 +42,16 @@ trait DescendantByInputInstances { def root: A => B = A.root } + + implicit def eyrieTrivialDescendantByInputInstance[A]( + implicit A: TrivialDescendant[A] + ): Descendant.ByInput.Aux[A, A] = + eyrieDescendantByInputInstance[A, A] + + implicit def eyrieAmbiguousTrivialDescendantByInputInstance[A]( + implicit A: TrivialDescendant[A] + ): Descendant.ByInput.Aux[A, A] = + eyrieDescendantByInputInstance[A, A] } private[eyrie] @@ -90,15 +83,60 @@ trait PotentialDescendantInstances { private[eyrie] trait PotentialDescendantByInputInstances { - implicit def eyriePotentialDescendantByInputInstance[A, D]( - implicit A: PotentialDescendant[A, D] - ): PotentialDescendant.ByInput.Aux[A, D] = + implicit def eyriePotentialDescendantByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B] + ): PotentialDescendant.ByInput.Aux[A, B] = new PotentialDescendant.ByInput[A] { override - type Root = D + type Root = B override - def rootOption: A => Option[D] = + def rootOption: A => Option[B] = A.rootOption } + + implicit def eyrieLeftTrivialPotentialDescendantByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B], ev: Subdivision[A, B, _] + ): PotentialDescendant.ByInput.Aux[A, B] = + eyriePotentialDescendantByInputInstance[A, B] + + implicit def eyrieLeftAmbiguousTrivialPotentialDescendantByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B], ev: Subdivision[A, B, _] + ): PotentialDescendant.ByInput.Aux[A, B] = + eyriePotentialDescendantByInputInstance[A, B] + + implicit def eyrieRightTrivialPotentialDescendantByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B], ev: Subdivision[A, _, B] + ): PotentialDescendant.ByInput.Aux[A, B] = + eyriePotentialDescendantByInputInstance[A, B] + + implicit def eyrieRightAmbiguousTrivialPotentialDescendantByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B], ev: Subdivision[A, _, B] + ): PotentialDescendant.ByInput.Aux[A, B] = + eyriePotentialDescendantByInputInstance[A, B] +} + +private[eyrie] +trait PotentialDescendantTrivialByInputInstances { + implicit def eyrieLeftPotentialDescendantTrivialByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B], ev: Subdivision[A, B, _] + ): PotentialDescendant.TrivialByInput.Aux[A, B] = + new EyriePotentialDescendantInstance[A, B](A) + + implicit def eyrieRightPotentialDescendantTrivialByInputInstance[A, B]( + implicit A: PotentialDescendant[A, B], ev: Subdivision[A, _, B] + ): PotentialDescendant.TrivialByInput.Aux[A, B] = + new EyriePotentialDescendantInstance[A, B](A) + + private + class EyriePotentialDescendantInstance[A, B]( + val A: PotentialDescendant[A, B] + ) extends PotentialDescendant.TrivialByInput[A] { + override + type Root = B + + override + def asRoot: A => Option[B] = + A.rootOption + } } diff --git a/core/src/main/scala/eyrie/ops/PotentialDescendant.scala b/core/src/main/scala/eyrie/ops/PotentialDescendant.scala index 21671ac..0ef41e1 100644 --- a/core/src/main/scala/eyrie/ops/PotentialDescendant.scala +++ b/core/src/main/scala/eyrie/ops/PotentialDescendant.scala @@ -1,6 +1,6 @@ package eyrie.ops -import eyrie.instances.{PotentialDescendantByInputInstances, PotentialDescendantInstances} +import eyrie.instances.{PotentialDescendantByInputInstances, PotentialDescendantInstances, PotentialDescendantTrivialByInputInstances} import simulacrum.typeclass trait PotentialDescendant[A, B] { @@ -24,4 +24,17 @@ object PotentialDescendant extends PotentialDescendantInstances { type Root = B } } + + @typeclass + trait TrivialByInput[A] { + type Root + + def asRoot: A => Option[Root] + } + + object TrivialByInput extends PotentialDescendantTrivialByInputInstances { + type Aux[A, B] = TrivialByInput[A] { + type Root = B + } + } } diff --git a/core/src/main/scala/eyrie/syntax/PotentialDescendantSyntax.scala b/core/src/main/scala/eyrie/syntax/PotentialDescendantSyntax.scala index 5f0975a..514efe3 100644 --- a/core/src/main/scala/eyrie/syntax/PotentialDescendantSyntax.scala +++ b/core/src/main/scala/eyrie/syntax/PotentialDescendantSyntax.scala @@ -10,4 +10,7 @@ trait PotentialDescendantSyntax { final class PotentialDescendantOps[A](private val a: A) extends AnyVal { def rootOption(implicit A: PotentialDescendant.ByInput[A]): Option[A.Root] = A.rootOption(a) + + def asRoot(implicit A: PotentialDescendant.TrivialByInput[A]): Option[A.Root] = + A.asRoot(a) } diff --git a/file/src/main/scala/eyrie/file/instances/FilePathConvertible.scala b/file/src/main/scala/eyrie/file/instances/FilePathConvertible.scala index edbbd77..c5487a2 100644 --- a/file/src/main/scala/eyrie/file/instances/FilePathConvertible.scala +++ b/file/src/main/scala/eyrie/file/instances/FilePathConvertible.scala @@ -22,7 +22,7 @@ class FilePathConvertible[A[_]](implicit A: ClassTag[A[_]]) extends Convertible[ } private[file] -trait ConvertibleInstances extends LowPriorityConvertibleInstances { +trait ConvertibleInstances extends ConvertibleLowPriorityInstances { implicit def eyrieFileEmptyConvertibleInstance[C]: Convertible.Aux[ Emptiness, True, FilePath.Empty[C], FilePath[C]] = _emptyConvertibleInstance.of[C, Emptiness, True, FilePath] @@ -51,7 +51,7 @@ trait ConvertibleInstances extends LowPriorityConvertibleInstances { } private[file] -trait LowPriorityConvertibleInstances extends LowPriorityConvertibleInstances1 { +trait ConvertibleLowPriorityInstances extends ConvertibleLowPriorityInstances1 { implicit def eyrieFileIdentityFilePathEmptinessConvertibleInstance[C]: Convertible.Aux[ Relativity, True, IdentityFilePath[C], FilePath.Empty[C]] = _identityFilePathConvertibleInstance.of[C, Relativity, True, FilePath.Empty] @@ -80,7 +80,7 @@ trait LowPriorityConvertibleInstances extends LowPriorityConvertibleInstances1 { } private[file] -trait LowPriorityConvertibleInstances1 { +trait ConvertibleLowPriorityInstances1 { private[instances] lazy val _emptyConvertibleInstance = new FilePathConvertible[FilePath.Empty] private[instances] lazy val _nonEmptyConvertibleInstance = new FilePathConvertible[FilePath.NonEmpty] private[instances] lazy val _relativeConvertibleInstance = new FilePathConvertible[FilePath.Relative] diff --git a/file/src/main/scala/eyrie/file/instances/FilePathInstances.scala b/file/src/main/scala/eyrie/file/instances/FilePathInstances.scala index 24abda4..411ead6 100644 --- a/file/src/main/scala/eyrie/file/instances/FilePathInstances.scala +++ b/file/src/main/scala/eyrie/file/instances/FilePathInstances.scala @@ -5,7 +5,7 @@ import eyrie.ops.Subdivision import eyrie.{Emptiness, Relativity} private[file] -trait FilePathInstances extends LowPriorityFilePathInstances with EqualityInstances[FilePath] { +trait FilePathInstances extends FilePathLowPriorityInstances with EqualityInstances[FilePath] { private lazy val _relativitySubdivisionInstance = new FilePathSubdivision[Relativity, FilePath, FilePath.Absolute, FilePath.Relative] @@ -16,7 +16,7 @@ trait FilePathInstances extends LowPriorityFilePathInstances with EqualityInstan } private[file] -trait LowPriorityFilePathInstances { +trait FilePathLowPriorityInstances { private lazy val _emptinessSubdivisionInstance = new FilePathSubdivision[Emptiness, FilePath, FilePath.NonEmpty, FilePath.Empty] diff --git a/file/src/test/scala/eyrie/file/test/PotentialDescendantSpec.scala b/file/src/test/scala/eyrie/file/test/PotentialDescendantSpec.scala index cda0552..6228c23 100644 --- a/file/src/test/scala/eyrie/file/test/PotentialDescendantSpec.scala +++ b/file/src/test/scala/eyrie/file/test/PotentialDescendantSpec.scala @@ -8,6 +8,7 @@ import eyrie.file.{FilePath, RootDirectory} import org.junit.runner.RunWith import org.scalatest.FreeSpec import org.scalatest.junit.JUnitRunner +import shapeless.test.illTyped object PotentialDescendantSpec { val nonEmpty: FilePath.NonEmpty[Sys] = @@ -36,8 +37,15 @@ class PotentialDescendantSpec extends FreeSpec { } } "FilePath.Empty" - { - "rootOption should be Option of RootDirectory" in { - empty.rootOption: Option[RootDirectory[Sys]] + "rootOption should not be available" in { + illTyped( + """ + empty.rootOption + """ + ) + } + "asRoot should be Option of RootDirectory" in { + empty.asRoot: Option[RootDirectory[Sys]] } } }