diff --git a/.scalafix-scala3.conf b/.scalafix-scala3.conf index 608608e..378cbab 100644 --- a/.scalafix-scala3.conf +++ b/.scalafix-scala3.conf @@ -23,7 +23,7 @@ rules = [ OptionMatchToRight SimplifyForYield - ThrowableToNonFatal +// ThrowableToNonFatal UnnecessaryCase UnnecessaryMatch UnnecessarySort diff --git a/modules/refined4s-core/shared/src/main/scala/refined4s/InlinedRefined.scala b/modules/refined4s-core/shared/src/main/scala/refined4s/InlinedRefined.scala new file mode 100644 index 0000000..7941923 --- /dev/null +++ b/modules/refined4s-core/shared/src/main/scala/refined4s/InlinedRefined.scala @@ -0,0 +1,18 @@ +package refined4s + +import scala.compiletime.* + +/** @author Kevin Lee + * @since 2023-08-12 + */ +trait InlinedRefined[A] extends RefinedBase[A] { + + inline def inlinedInvalidReason(inline a: A): String + + inline def inlinedPredicate(inline a: A): Boolean + + inline def apply(inline a: A): Type = + inline if inlinedPredicate(a) then a.asInstanceOf[Type] // scalafix:ok DisableSyntax.asInstanceOf + else error("Invalid value: [" + codeOf(a) + "]. " + inlinedInvalidReason(a)) + +} diff --git a/modules/refined4s-core/shared/src/test/scala/refined4s/InlinedRefinedSpec.scala b/modules/refined4s-core/shared/src/test/scala/refined4s/InlinedRefinedSpec.scala new file mode 100644 index 0000000..3d19084 --- /dev/null +++ b/modules/refined4s-core/shared/src/test/scala/refined4s/InlinedRefinedSpec.scala @@ -0,0 +1,30 @@ +package refined4s + +import hedgehog._ +import hedgehog.runner._ + +/** @author Kevin Lee + * @since 2023-08-14 + */ +object InlinedRefinedSpec extends Properties { + override def tests: List[Test] = List( + example("test InlinedRefined with valid value", testInlinedRefined) + ) + + def testInlinedRefined: Result = { + import InlinedRefinedType.* + + Something(1) + Result.success + } + +// def testInlinedRefined2: Result = { +// import InlinedRefinedType.* +// +// val a = 1 +// // This should not compile. +// Something(a) +// Result.failure +// } + +} diff --git a/modules/refined4s-core/shared/src/test/scala/refined4s/InlinedRefinedType.scala b/modules/refined4s-core/shared/src/test/scala/refined4s/InlinedRefinedType.scala new file mode 100644 index 0000000..df909db --- /dev/null +++ b/modules/refined4s-core/shared/src/test/scala/refined4s/InlinedRefinedType.scala @@ -0,0 +1,47 @@ +package refined4s + +object InlinedRefinedType { + type Something = Something.Type + object Something extends InlinedRefined[Int] { + import scala.compiletime.* + import scala.quoted.* + override inline def inlinedInvalidReason(inline a: Int): String = + "The number is a negative Int. [a: " + codeOf(a) + "]" + + private def inlinedPredicate0(a: Expr[Int])(using Quotes): Expr[Boolean] = { + import quotes.reflect.* + a.asTerm match { + case Inlined(_, _, Literal(IntConstant(num))) => + try { + validate(num) + Expr(true) + } catch { + case _: Throwable => Expr(false) + } + case _ => + report.error( + "Something must be a Int literal.", + a, + ) + Expr(false) + } + + } + + override inline def inlinedPredicate(inline a: Int): Boolean = ${ inlinedPredicate0('a) } + + override def invalidReason(a: Int): String = s"The number is a negative Int. [a: ${a.toString}" + + override def predicate(a: Int): Boolean = + try { + validate(a) + true + } catch { + case _: Throwable => false + } + } + + def validate(a: Int): Int = + if (a >= 0) a else sys.error("The number should be non-negative number.") + +}