Skip to content

Commit 6f88b7b

Browse files
committed
allowed incomplete metadata classes
1 parent 5aef78f commit 6f88b7b

File tree

10 files changed

+100
-42
lines changed

10 files changed

+100
-42
lines changed

commons-annotations/src/main/scala/com/avsystem/commons/meta/metaAnnotations.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ trait RealSymAnnotation extends StaticAnnotation
1414
* method against raw RPC methods).
1515
*/
1616
trait RawSymAnnotation extends StaticAnnotation
17+
trait RawRpcAnnotation extends RawSymAnnotation
1718
trait RawMethodAnnotation extends RawSymAnnotation
1819
trait RawParamAnnotation extends RawSymAnnotation
1920

@@ -287,3 +288,14 @@ final class reifyDefaultValue extends MetadataParamStrategy
287288
* ignores that fact and error is only reported after macro is fully expanded.
288289
*/
289290
final class checked extends StaticAnnotation
291+
292+
/**
293+
* When applied on:
294+
* - RPC trait metadata class: does not require that all RPC methods must be matched by
295+
* method metadata parameter
296+
* - RPC method metadata class: does not require that all RPC params must be matched by
297+
* param metadata parameter
298+
* - ADT metadata class: does not require that all case types or case class parameters must be matched by
299+
* metadata parameter
300+
*/
301+
final class allowIncomplete extends RawSymAnnotation

commons-annotations/src/main/scala/com/avsystem/commons/rpc/rpcAnnotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ final class tried extends RawMethodAnnotation
205205
* @tparam BaseTag base type for tags that can be used on real RPC methods
206206
* @param defaultTag default tag value assumed for untagged methods
207207
**/
208-
final class methodTag[BaseTag <: RpcTag](val defaultTag: BaseTag = null) extends RawSymAnnotation
208+
final class methodTag[BaseTag <: RpcTag](val defaultTag: BaseTag = null) extends RawRpcAnnotation
209209

210210
/**
211211
* Parameter tagging lets you have more explicit control over which raw parameters can match which real

commons-core/src/test/scala/com/avsystem/commons/rpc/NewRawRpc.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,25 @@ case class NameInfo(
206206
) {
207207
def repr: String = name + (if (rpcName != name) s"<$rpcName>" else "")
208208
}
209+
210+
@allowIncomplete
211+
case class PartialMetadata[T](
212+
@multi @rpcMethodMetadata @annotated[POST] posts: List[PostMethod[_]]
213+
) {
214+
def repr: String = posts.map(_.repr).mkString("\n")
215+
}
216+
object PartialMetadata extends RpcMetadataCompanion[PartialMetadata]
217+
218+
@allowIncomplete
219+
case class PostMethod[T](
220+
@reifyName name: String,
221+
@multi @rpcParamMetadata @annotated[header] headerParams: List[HeaderParam[_]]
222+
) extends TypedMetadata[T] {
223+
def repr: String = s"$name(${headerParams.map(_.repr).mkString(",")})"
224+
}
225+
226+
case class HeaderParam[T](
227+
@reifyAnnot header: header
228+
) extends TypedMetadata[T] {
229+
def repr: String = header.name
230+
}

commons-core/src/test/scala/com/avsystem/commons/rpc/NewRpcMetadataTest.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ trait TestApi extends SomeBase {
2525
def postit(arg: String, bar: String, int: Int, @suchMeta(3, "c") foo: String): String
2626
}
2727
object TestApi {
28-
import NewRawRpc._
2928
implicit val asRawReal: NewRawRpc.AsRawRealRpc[TestApi] = NewRawRpc.materializeAsRawReal[TestApi]
3029
implicit val metadata: NewRpcMetadata[TestApi] = NewRpcMetadata.materialize[TestApi]
30+
implicit val partialMetadata: PartialMetadata[TestApi] = PartialMetadata.materialize[TestApi]
3131
}
3232

3333
class NewRpcMetadataTest extends FunSuite {
@@ -85,4 +85,8 @@ class NewRpcMetadataTest extends FunSuite {
8585
|""".stripMargin
8686
)
8787
}
88+
89+
test("TestApi partial metadata") {
90+
assert(TestApi.partialMetadata.repr == "postit(X-Bar,X-Foo)")
91+
}
8892
}

commons-macros/src/main/scala/com/avsystem/commons/macros/meta/AdtMetadataMacros.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class AdtMetadataMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx)
100100

101101
def paramMappings(params: List[AdtParam]): Res[Map[AdtParamMetadataParam, Tree]] =
102102
if (paramMdParams.isEmpty) Ok(Map.empty)
103-
else collectParamMappings(params, paramMdParams, "metadata parameter")(
103+
else collectParamMappings(params, paramMdParams, "metadata parameter", allowIncomplete)(
104104
(param, parser) => param.metadataFor(parser).map(t => (param, t))).map(_.toMap)
105105

106106
def collectCaseMappings(cases: List[AdtSymbol]): Res[Map[AdtCaseMetadataParam, List[AdtCaseMapping]]] =
@@ -121,7 +121,9 @@ class AdtMetadataMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx)
121121
} match {
122122
case Ok(m) => Some(m)
123123
case Fail(err) =>
124-
addFailure(adtCase, err)
124+
if (!allowIncomplete) {
125+
addFailure(adtCase, err)
126+
}
125127
None
126128
}
127129
}

commons-macros/src/main/scala/com/avsystem/commons/macros/meta/MacroMetadatas.scala

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@ trait MacroMetadatas extends MacroSymbols {
99

1010
import c.universe._
1111

12-
val ParamPositionObj: Tree = q"$MetaPackage.ParamPosition"
13-
val TypedMetadataType: Type = staticType(tq"$MetaPackage.TypedMetadata[_]")
14-
val MetadataParamStrategyType: Type = staticType(tq"$MetaPackage.MetadataParamStrategy")
15-
val ReifyAnnotAT: Type = staticType(tq"$MetaPackage.reifyAnnot")
16-
val IsAnnotatedAT: Type = staticType(tq"$MetaPackage.isAnnotated[_]")
17-
val ReifyNameAT: Type = staticType(tq"$MetaPackage.reifyName")
18-
val ReifyPositionAT: Type = staticType(tq"$MetaPackage.reifyPosition")
19-
val ReifyFlagsAT: Type = staticType(tq"$MetaPackage.reifyFlags")
20-
val CheckedAT: Type = staticType(tq"$MetaPackage.checked")
21-
val ParamPositionTpe: Type = staticType(tq"$MetaPackage.ParamPosition")
22-
val ParamFlagsTpe: Type = staticType(tq"$MetaPackage.ParamFlags")
23-
val TypeFlagsTpe: Type = staticType(tq"$MetaPackage.TypeFlags")
12+
final def ParamPositionObj: Tree = q"$MetaPackage.ParamPosition"
13+
final lazy val TypedMetadataType: Type = staticType(tq"$MetaPackage.TypedMetadata[_]")
14+
final lazy val MetadataParamStrategyType: Type = staticType(tq"$MetaPackage.MetadataParamStrategy")
15+
final lazy val ReifyAnnotAT: Type = staticType(tq"$MetaPackage.reifyAnnot")
16+
final lazy val IsAnnotatedAT: Type = staticType(tq"$MetaPackage.isAnnotated[_]")
17+
final lazy val ReifyNameAT: Type = staticType(tq"$MetaPackage.reifyName")
18+
final lazy val ReifyPositionAT: Type = staticType(tq"$MetaPackage.reifyPosition")
19+
final lazy val ReifyFlagsAT: Type = staticType(tq"$MetaPackage.reifyFlags")
20+
final lazy val CheckedAT: Type = staticType(tq"$MetaPackage.checked")
21+
final lazy val AllowIncompleteAT: Type = staticType(tq"$MetaPackage.allowIncomplete")
22+
final lazy val ParamPositionTpe: Type = staticType(tq"$MetaPackage.ParamPosition")
23+
final lazy val ParamFlagsTpe: Type = staticType(tq"$MetaPackage.ParamFlags")
24+
final lazy val TypeFlagsTpe: Type = staticType(tq"$MetaPackage.TypeFlags")
2425

2526
def actualMetadataType(baseMetadataType: Type, realType: Type, realTypeDesc: String, verbatim: Boolean): Res[Type] = {
2627
val (wildcards, underlying) = baseMetadataType match {
@@ -83,7 +84,11 @@ trait MacroMetadatas extends MacroSymbols {
8384
abstract class MetadataConstructor(val ownerType: Type, val atParam: Option[CompositeParam])
8485
extends MacroMethod { this: MetadataConstructor =>
8586

86-
lazy val symbol: Symbol = primaryConstructor(ownerType, atParam)
87+
lazy val symbol: Symbol =
88+
primaryConstructor(ownerType, atParam)
89+
90+
lazy val allowIncomplete: Boolean =
91+
findAnnotation(ownerType.typeSymbol, AllowIncompleteAT).nonEmpty
8792

8893
// fallback to annotations on the class itself
8994
def annot(tpe: Type): Option[Annot] =

commons-macros/src/main/scala/com/avsystem/commons/macros/meta/MacroSymbols.scala

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@ trait MacroSymbols extends MacroCommons {
1010

1111
import c.universe._
1212

13-
val RpcPackage = q"$CommonsPkg.rpc"
14-
val MetaPackage = q"$CommonsPkg.meta"
15-
val RpcUtils = q"$RpcPackage.RpcUtils"
16-
val OptionLikeCls = tq"$MetaPackage.OptionLike"
17-
val CanBuildFromCls = tq"$CollectionPkg.generic.CanBuildFrom"
18-
val RpcArityAT: Type = staticType(tq"$MetaPackage.SymbolArity")
19-
val SingleArityAT: Type = staticType(tq"$MetaPackage.single")
20-
val OptionalArityAT: Type = staticType(tq"$MetaPackage.optional")
21-
val MultiArityAT: Type = staticType(tq"$MetaPackage.multi")
22-
val CompositeAT: Type = staticType(tq"$MetaPackage.composite")
23-
val AuxiliaryAT: Type = staticType(tq"$MetaPackage.auxiliary")
24-
val AnnotatedAT: Type = staticType(tq"$MetaPackage.annotated[_]")
25-
val TaggedAT: Type = staticType(tq"$RpcPackage.tagged[_]")
26-
val WhenUntaggedArg: Symbol = TaggedAT.member(TermName("whenUntagged"))
13+
final def RpcPackage = q"$CommonsPkg.rpc"
14+
final def MetaPackage = q"$CommonsPkg.meta"
15+
final def RpcUtils = q"$RpcPackage.RpcUtils"
16+
final def OptionLikeCls = tq"$MetaPackage.OptionLike"
17+
final def CanBuildFromCls = tq"$CollectionPkg.generic.CanBuildFrom"
18+
final lazy val RpcArityAT: Type = staticType(tq"$MetaPackage.SymbolArity")
19+
final lazy val SingleArityAT: Type = staticType(tq"$MetaPackage.single")
20+
final lazy val OptionalArityAT: Type = staticType(tq"$MetaPackage.optional")
21+
final lazy val MultiArityAT: Type = staticType(tq"$MetaPackage.multi")
22+
final lazy val CompositeAT: Type = staticType(tq"$MetaPackage.composite")
23+
final lazy val AuxiliaryAT: Type = staticType(tq"$MetaPackage.auxiliary")
24+
final lazy val AnnotatedAT: Type = staticType(tq"$MetaPackage.annotated[_]")
25+
final lazy val TaggedAT: Type = staticType(tq"$RpcPackage.tagged[_]")
26+
final lazy val WhenUntaggedArg: Symbol = TaggedAT.member(TermName("whenUntagged"))
2727

2828
def primaryConstructor(ownerType: Type, ownerParam: Option[MacroSymbol]): Symbol =
2929
primaryConstructorOf(ownerType, ownerParam.fold("")(p => s"${p.problemStr}: "))
@@ -281,12 +281,17 @@ trait MacroSymbols extends MacroCommons {
281281
}
282282

283283
def collectParamMappings[Real <: MacroParam, Raw <: MacroParam, M](
284-
reals: List[Real], raws: List[Raw], rawShortDesc: String)(
285-
createMapping: (Raw, ParamsParser[Real]) => Res[M]): Res[List[M]] = {
284+
reals: List[Real],
285+
raws: List[Raw],
286+
rawShortDesc: String,
287+
allowIncomplete: Boolean
288+
)(
289+
createMapping: (Raw, ParamsParser[Real]) => Res[M]
290+
): Res[List[M]] = {
286291

287292
val parser = new ParamsParser(reals)
288293
Res.traverse(raws)(createMapping(_, parser)).flatMap { result =>
289-
if (parser.remaining.isEmpty) Ok(result)
294+
if (allowIncomplete || parser.remaining.isEmpty) Ok(result)
290295
else {
291296
val unmatched = parser.remaining.iterator.map(_.nameStr).mkString(",")
292297
Fail(s"no $rawShortDesc(s) were found that would match real parameter(s) $unmatched")

commons-macros/src/main/scala/com/avsystem/commons/macros/rpc/RpcMappings.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ trait RpcMappings { this: RpcMacroCommons with RpcSymbols =>
1111
import c.universe._
1212

1313
def collectMethodMappings[Raw <: TagMatchingSymbol with AritySymbol, M](
14-
rawSymbols: List[Raw], errorBase: String, realMethods: List[RealMethod])(
14+
rawSymbols: List[Raw], errorBase: String, realMethods: List[RealMethod], allowIncomplete: Boolean)(
1515
createMapping: (Raw, MatchedMethod) => Res[M]): List[M] = {
1616

1717
val failedReals = new ListBuffer[String]
@@ -35,7 +35,9 @@ trait RpcMappings { this: RpcMacroCommons with RpcSymbols =>
3535
} match {
3636
case Ok(v) => Some(v)
3737
case Fail(msg) =>
38-
addFailure(realMethod, msg)
38+
if (!allowIncomplete) {
39+
addFailure(realMethod, msg)
40+
}
3941
None
4042
}
4143
}
@@ -300,13 +302,14 @@ trait RpcMappings { this: RpcMacroCommons with RpcSymbols =>
300302
for {
301303
resultConv <- resultEncoding
302304
paramMappings <- collectParamMappings(
303-
matchedMethod.real.realParams, rawMethod.allValueParams, "raw parameter")(extractMapping(matchedMethod, _, _))
305+
matchedMethod.real.realParams, rawMethod.allValueParams, "raw parameter", allowIncomplete = false
306+
)(extractMapping(matchedMethod, _, _))
304307
} yield MethodMapping(matchedMethod, rawMethod, paramMappings, resultConv)
305308
}
306309

307310
lazy val methodMappings: List[MethodMapping] = {
308311
val errorBase = s"it has no matching raw methods in ${raw.description}"
309-
collectMethodMappings(raw.rawMethods, errorBase, real.realMethods)(mappingRes)
312+
collectMethodMappings(raw.rawMethods, errorBase, real.realMethods, allowIncomplete = false)(mappingRes)
310313
}
311314

312315
def ensureUniqueRpcNames(): Unit =

commons-macros/src/main/scala/com/avsystem/commons/macros/rpc/RpcMetadatas.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ trait RpcMetadatas extends MacroMetadatas { this: RpcMacroCommons with RpcSymbol
108108

109109
def methodMappings(rpc: RealRpcTrait): Map[MethodMetadataParam, List[MethodMetadataMapping]] = {
110110
val errorBase = s"it has no matching metadata parameters in $description"
111-
collectMethodMappings(methodMdParams, errorBase, rpc.realMethods)(_.mappingFor(_)).groupBy(_.mdParam)
111+
collectMethodMappings(
112+
methodMdParams, errorBase, rpc.realMethods, allowIncomplete
113+
)(_.mappingFor(_)).groupBy(_.mdParam)
112114
}
113115

114116
def tryMaterializeFor(rpc: RealRpcTrait, methodMappings: Map[MethodMetadataParam, List[MethodMetadataMapping]]): Res[Tree] =
@@ -147,8 +149,11 @@ trait RpcMetadatas extends MacroMetadatas { this: RpcMacroCommons with RpcSymbol
147149
new MethodMetadataConstructor(param.collectedType, containingMethodParam, Some(param))
148150

149151
def paramMappings(matchedMethod: MatchedMethod): Res[Map[ParamMetadataParam, Tree]] =
150-
collectParamMappings(matchedMethod.real.realParams, paramMdParams, "metadata parameter")(
151-
(param, parser) => param.metadataFor(matchedMethod, parser).map(t => (param, t))).map(_.toMap)
152+
collectParamMappings(
153+
matchedMethod.real.realParams, paramMdParams, "metadata parameter", allowIncomplete
154+
) { (param, parser) =>
155+
param.metadataFor(matchedMethod, parser).map(t => (param, t))
156+
}.map(_.toMap)
152157

153158
def tryMaterializeFor(matchedMethod: MatchedMethod, paramMappings: Map[ParamMetadataParam, Tree]): Res[Tree] =
154159
tryMaterialize(matchedMethod) {

version.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version in ThisBuild := "1.33.0"
1+
version in ThisBuild := "1.33.1-SNAPSHOT"

0 commit comments

Comments
 (0)