99//
1010//===----------------------------------------------------------------------===//
1111
12- /// A namespace for methods which overlay a collection of elements
13- /// over a region of a base collection.
12+ /// A namespace for methods which return composed collections,
13+ /// formed by replacing a region of a base collection
14+ /// with another collection of elements.
1415///
1516/// Access the namespace via the `.overlay` member, available on all collections:
1617///
2425///
2526public  struct  OverlayCollectionNamespace < Elements:  Collection >  { 
2627
27-   @usableFromInline  
28-   internal  var  elements :  Elements 
28+   public  let  elements :  Elements 
2929
3030  @inlinable  
3131  internal  init ( elements:  Elements )  { 
@@ -35,13 +35,44 @@ public struct OverlayCollectionNamespace<Elements: Collection> {
3535
3636extension  Collection  { 
3737
38-   /// A namespace for methods which overlay another collection of elements
39-   /// over a region of this collection.
38+   /// A namespace for methods which return composed collections,
39+   /// formed by replacing a region of this collection
40+   /// with another collection of elements.
4041  ///
4142  @inlinable  
4243  public  var  overlay :  OverlayCollectionNamespace < Self >  { 
4344    OverlayCollectionNamespace ( elements:  self ) 
4445  } 
46+ 
47+   /// If `condition` is true, returns an `OverlayCollection` by applying the given closure.
48+   /// Otherwise, returns an `OverlayCollection` containing the same elements as this collection.
49+   ///
50+   /// The following example takes an array of products, lazily wraps them in a `ListItem` enum,
51+   /// and conditionally inserts a call-to-action element if `showCallToAction` is true.
52+   ///
53+   /// ```swift
54+   /// var listItems: some Collection<ListItem> {
55+   ///   let products: [Product] = ...
56+   ///   return products
57+   ///     .lazy.map { 
58+   ///       ListItem.product($0)
59+   ///     }
60+   ///     .overlay(if: showCallToAction) {
61+   ///       $0.inserting(.callToAction, at: min(4, $0.elements.count))
62+   ///     }
63+   /// }
64+   /// ```
65+   ///
66+   @inlinable  
67+   public  func  overlay< Overlay> ( 
68+     if condition:  Bool ,  _ makeOverlay:  ( OverlayCollectionNamespace < Self > )  ->  OverlayCollection < Self ,  Overlay > 
69+   )  ->  OverlayCollection < Self ,  Overlay >  { 
70+     if  condition { 
71+       return  makeOverlay ( overlay) 
72+     }  else  { 
73+       return  OverlayCollection ( base:  self ,  overlay:  nil ,  replacedRange:  startIndex..< startIndex) 
74+     } 
75+   } 
4576} 
4677
4778extension  OverlayCollectionNamespace  { 
@@ -96,20 +127,34 @@ extension OverlayCollectionNamespace {
96127  } 
97128} 
98129
130+ /// A composed collections, formed by replacing a region of a base collection
131+ /// with another collection of elements.
132+ ///
133+ /// To create an OverlayCollection, use the methods in the ``OverlayCollectionNamespace``
134+ /// namespace:
135+ ///
136+ /// ```swift
137+ /// let base = 0..<5
138+ /// for n in base.overlay.inserting(42, at: 2) {
139+ ///   print(n)
140+ /// }
141+ /// // Prints: 0, 1, 42, 2, 3, 4
142+ /// ```
143+ ///
99144public  struct  OverlayCollection < Base,  Overlay> 
100145where  Base:  Collection ,  Overlay:  Collection ,  Base. Element ==  Overlay . Element  { 
101146
102147  @usableFromInline  
103148  internal  var  base :  Base 
104149
105150  @usableFromInline  
106-   internal  var  overlay :  Overlay 
151+   internal  var  overlay :  Optional < Overlay > 
107152
108153  @usableFromInline  
109154  internal  var  replacedRange :  Range < Base . Index > 
110155
111156  @inlinable  
112-   internal  init ( base:  Base ,  overlay:  Overlay ,  replacedRange:  Range < Base . Index > )  { 
157+   internal  init ( base:  Base ,  overlay:  Overlay ? ,  replacedRange:  Range < Base . Index > )  { 
113158    self . base =  base
114159    self . overlay =  overlay
115160    self . replacedRange =  replacedRange
@@ -187,7 +232,7 @@ extension OverlayCollection {
187232
188233  @inlinable  
189234  public  var  startIndex :  Index  { 
190-     if  base. startIndex ==  replacedRange. lowerBound { 
235+     if  let  overlay  =  overlay ,   base. startIndex ==  replacedRange. lowerBound { 
191236      if  overlay. isEmpty { 
192237        return  makeIndex ( replacedRange. upperBound) 
193238      } 
@@ -198,6 +243,9 @@ extension OverlayCollection {
198243
199244  @inlinable  
200245  public  var  endIndex :  Index  { 
246+     guard  let  overlay =  overlay else  { 
247+       return  makeIndex ( base. endIndex) 
248+     } 
201249    if  replacedRange. lowerBound !=  base. endIndex || overlay. isEmpty { 
202250      return  makeIndex ( base. endIndex) 
203251    } 
@@ -206,7 +254,10 @@ extension OverlayCollection {
206254
207255  @inlinable  
208256  public  var  count :  Int  { 
209-     base. distance ( from:  base. startIndex,  to:  replacedRange. lowerBound) 
257+     guard  let  overlay =  overlay else  { 
258+       return  base. count
259+     } 
260+     return  base. distance ( from:  base. startIndex,  to:  replacedRange. lowerBound) 
210261    +  overlay. count
211262    +  base. distance ( from:  replacedRange. upperBound,  to:  base. endIndex) 
212263  } 
@@ -216,7 +267,7 @@ extension OverlayCollection {
216267    switch  i. wrapped { 
217268    case  . base( var  baseIndex) : 
218269      base. formIndex ( after:  & baseIndex) 
219-       if  baseIndex ==  replacedRange. lowerBound { 
270+       if  let  overlay  =  overlay ,   baseIndex ==  replacedRange. lowerBound { 
220271        if  overlay. isEmpty { 
221272          return  makeIndex ( replacedRange. upperBound) 
222273        } 
@@ -225,8 +276,8 @@ extension OverlayCollection {
225276      return  makeIndex ( baseIndex) 
226277
227278    case  . overlay( var  overlayIndex) : 
228-       overlay. formIndex ( after:  & overlayIndex) 
229-       if  replacedRange. lowerBound !=  base. endIndex,  overlayIndex ==  overlay. endIndex { 
279+       overlay! . formIndex ( after:  & overlayIndex) 
280+       if  replacedRange. lowerBound !=  base. endIndex,  overlayIndex ==  overlay! . endIndex { 
230281        return  makeIndex ( replacedRange. upperBound) 
231282      } 
232283      return  makeIndex ( overlayIndex) 
@@ -239,7 +290,7 @@ extension OverlayCollection {
239290    case  . base( let  baseIndex) :  
240291      return  base [ baseIndex] 
241292    case  . overlay( let  overlayIndex) : 
242-       return  overlay [ overlayIndex] 
293+       return  overlay! [ overlayIndex] 
243294    } 
244295  } 
245296} 
@@ -251,7 +302,7 @@ where Base: BidirectionalCollection, Overlay: BidirectionalCollection {
251302  public  func  index( before i:  Index )  ->  Index  { 
252303    switch  i. wrapped { 
253304    case  . base( var  baseIndex) : 
254-       if  baseIndex ==  replacedRange. upperBound { 
305+       if  let  overlay  =  overlay ,   baseIndex ==  replacedRange. upperBound { 
255306        if  overlay. isEmpty { 
256307          return  makeIndex ( base. index ( before:  replacedRange. lowerBound) ) 
257308        } 
@@ -261,10 +312,10 @@ where Base: BidirectionalCollection, Overlay: BidirectionalCollection {
261312      return  makeIndex ( baseIndex) 
262313
263314    case  . overlay( var  overlayIndex) : 
264-       if  overlayIndex ==  overlay. startIndex { 
315+       if  overlayIndex ==  overlay! . startIndex { 
265316        return  makeIndex ( base. index ( before:  replacedRange. lowerBound) ) 
266317      } 
267-       overlay. formIndex ( before:  & overlayIndex) 
318+       overlay! . formIndex ( before:  & overlayIndex) 
268319      return  makeIndex ( overlayIndex) 
269320    } 
270321  } 
0 commit comments