scala 优化尺寸上的模式匹配
Pattern matching on scala Refined size
我想根据不同的类型(包括 Scala 精化)json 案例 class 的模式(在编译时)
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()))
}
但是考虑是否可以将您的逻辑编码为类型 class 而不是原始宏是有意义的。
我想根据不同的类型(包括 Scala 精化)json 案例 class 的模式(在编译时)
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()))
}
但是考虑是否可以将您的逻辑编码为类型 class 而不是原始宏是有意义的。