0001    // The MIT License
0002    //
0003    // Copyright (c) 2015 Gwendal Roué
0004    //
0005    // Permission is hereby granted, free of charge, to any person obtaining a copy
0006    // of this software and associated documentation files (the "Software"), to deal
0007    // in the Software without restriction, including without limitation the rights
0008    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0009    // copies of the Software, and to permit persons to whom the Software is
0010    // furnished to do so, subject to the following conditions:
0011    //
0012    // The above copyright notice and this permission notice shall be included in
0013    // all copies or substantial portions of the Software.
0014    //
0015    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0018    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0021    // THE SOFTWARE.
0022    
0023    let ZipFilter
StandardLibrary.swift:220
    public static let zip = ZipFilter
= VariadicFilter { (boxes) in 0024 0025 // Turn collection arguments into generators. Generators can be iterated 0026 // all together, and this is what we need. 0027 // 0028 // Other kinds of arguments generate an error. 0029 0030 var zippedGenerators: [AnyGenerator<MustacheBox>] = [] 0031 0032 for box in boxes { 0033 if box.isEmpty { 0034 // Missing collection does not provide anything 0035 } else if let array = box.arrayValue { 0036 // Array 0037 zippedGenerators.append(AnyGenerator(array.generate())) 0038 } else { 0039 // Error 0040 throw MustacheError(kind: .RenderError, message: "Non-enumerable argument in zip filter: `\(box.value)`") 0041 } 0042 } 0043 0044 0045 // Build an array of custom render functions 0046 0047 var renderFunctions: [RenderFunction] = [] 0048 0049 while true { 0050 0051 // Extract from all generators the boxes that should enter the rendering 0052 // context at each iteration. 0053 // 0054 // Given the [1,2,3], [a,b,c] input collections, those boxes would be 0055 // [1,a] then [2,b] and finally [3,c]. 0056 0057 var zippedBoxes: [MustacheBox] = [] 0058 for generator in zippedGenerators { 0059 var generator = generator 0060 if let box = generator.next() { 0061 zippedBoxes.append(box) 0062 } 0063 } 0064 0065 0066 // All generators have been enumerated: stop 0067 0068 if zippedBoxes.isEmpty { 0069 break; 0070 } 0071 0072 0073 // Build a render function which extends the rendering context with 0074 // zipped boxes before rendering the tag. 0075 0076 let renderFunction: RenderFunction = { (info) -> Rendering in 0077 var context = zippedBoxes.reduce(info.context) { (context, box) in context.extendedContext(box) } 0078 return try info.tag.render(context) 0079 } 0080 0081 renderFunctions.append(renderFunction) 0082 } 0083 0084 0085 // Return a box of those boxed render functions 0086 0087 return Box(boxable: renderFunctions.map(Box)) 0088 }