繁体   English   中英

scala 上的模式匹配 Refined size

[英]Pattern matching on scala Refined size

我想提供一个案例类的 json 模式(在编译时),基于不同的类型(包括 Scala 精制)

object JsonSchema {

  def jsonSchema[T]: String = macro impl[T]

  def impl[T: c.WeakTypeTag](c: scala.reflect.macros.whitebox.Context): c.Expr[String] = {
    import c.universe._

    val r = weakTypeOf[T].decls.collect {
      case m: MethodSymbol if m.isCaseAccessor =>
        val typeArgs = m.info match {
          case NullaryMethodType(v) => v.typeArgs
        }

        val supportedStringFormat = List("IPv4", "IPv6", "Uri")


        typeArgs match {
          case _type :: _predicate :: Nil if _type =:= typeOf[String] && supportedStringFormat.contains(_predicate.typeSymbol.name.toString())  => Json.obj(m.name.decodedName.toString -> Json.obj("type" -> "string", "format" -> _predicate.typeSymbol.name.toString().toLowerCase()))
          case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate =:= typeOf[NonEmpty] => Json.obj(m.name.decodedName.toString -> Json.obj("type" -> "string", "minLength" -> 1))
          case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate =:= typeOf[Size[_0]] => {

            val size   = _predicate.typeArgs match {
              case h :: _ if h <:< typeOf[Nat._0] => 0
            }
            Json.obj(m.name.decodedName.toString->  Json.obj("type" -> "string", "minLength" -> size))
          }
          case _type :: _ if _type =:= typeOf[String]  => Json.obj(m.name.decodedName.toString ->  Json.obj("type" -> "string"))
          case _type :: _predicate :: Nil if _type =:= typeOf[Int] && _predicate =:= typeOf[Positive] =>  Json.obj(m.name.decodedName.toString ->Json.obj("type" -> "int", "minValue" -> 1))
          case _type :: _predicate :: Nil if _type =:= typeOf[List[String]] && _predicate =:= typeOf[NonEmpty] =>  Json.obj(m.name.decodedName.toString-> Json.obj("type" -> "array", "minLength" -> 1))
          case List() => Json.obj(m.name.decodedName.toString ->Json.obj("type"-> m.info.typeSymbol.name.decodedName.toString.toLowerCase()))
          case other => Json.obj("other"-> other.map(_.toString()).mkString)

        }
    }

    val json = r.reduce(_ ++ _)
    c.Expr[String](q"""${json.toString()}""")
  }

}

我希望能够为所有无形的自然模式匹配:

typeOf[Size[_]]而不是typeOf[Size[_0]]

但我有一个编译错误:

 No TypeTag available for eu.timepit.refined.collection.Size[_]
[error]           case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate =:= typeOf[Size[_]] => {

我想得到一个 int 大小

val size   = _predicate.typeArgs match {
             case h :: _ if h <:< typeOf[Nat._0] => 0
}

用法 :

case class StringWithMinSize22(k: String Refined MinSize[_22])

"String with min size 22" must {
    "return a schema with min size" in {
      JsonSchema.jsonSchema[StringWithMinSize22] mustBe """{"k":{"type":"string","minLength":22}}"""

    }  
  }

尝试

val sizeTC = typeOf[eu.timepit.refined.collection.Size[_]]

val r = weakTypeOf[T].decls.collect {

  // ...

  case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate <:< sizeTC => {
    val sizeTyp = _predicate.dealias.typeArgs.head.typeArgs.head
    val toIntTree = c.inferImplicitValue(c.typecheck(tq"_root_.shapeless.ops.nat.ToInt[$sizeTyp]", mode = c.TYPEmode).tpe, silent = false)
    val toInt = c.eval(c.Expr(c.untypecheck(toIntTree.duplicate)))

    Json.obj(m.name.decodedName.toString ->  Json.obj("type" -> "string", "minLength" -> toInt.asInstanceOf[ToInt[_]].apply()))
  }

但是考虑是否可以在类型类而不是原始宏中编码逻辑是有意义的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM