@@ -268,6 +268,18 @@ public struct SmallProjectionPath : Hashable, CustomStringConvertible, NoReflect
268
268
return !matches( pattern: Self ( . anyValueFields) )
269
269
}
270
270
271
+ /// Returns true if the path may have a class projection.
272
+ /// For example:
273
+ /// returns false for `v**`
274
+ /// returns false for `c0`
275
+ /// returns true for `c0.c1`
276
+ /// returns true for `c0.**` (because '**' can have any number of class projections)
277
+ /// returns true for `**` (because '**' can have any number of class projections)
278
+ public var mayHaveTwoClassProjections : Bool {
279
+ return !matches( pattern: Self ( . anyValueFields) ) &&
280
+ !matches( pattern: Self ( . anyValueFields) . push ( . anyClassField) . push ( . anyValueFields) )
281
+ }
282
+
271
283
/// Pops all value field components from the beginning of the path.
272
284
/// For example:
273
285
/// `s0.e2.3.c4.s1` -> `c4.s1`
@@ -691,6 +703,12 @@ extension SmallProjectionPath {
691
703
testPredicate ( " 1 " , \. mayHaveClassProjection, expect: false )
692
704
testPredicate ( " ** " , \. mayHaveClassProjection, expect: true )
693
705
706
+ testPredicate ( " v** " , \. mayHaveTwoClassProjections, expect: false )
707
+ testPredicate ( " c0 " , \. mayHaveTwoClassProjections, expect: false )
708
+ testPredicate ( " ** " , \. mayHaveTwoClassProjections, expect: true )
709
+ testPredicate ( " v**.c*.s2.1.c0 " , \. mayHaveTwoClassProjections, expect: true )
710
+ testPredicate ( " c*.s2.1.c0.v** " , \. mayHaveTwoClassProjections, expect: true )
711
+ testPredicate ( " v**.c*.** " , \. mayHaveTwoClassProjections, expect: true )
694
712
}
695
713
696
714
func testPredicate( _ pathStr: String , _ property: ( SmallProjectionPath ) -> Bool , expect: Bool ) {
0 commit comments