Section 10/111 menit

10. Real Use Cases

10. Real Use Cases

Use Case 1: Image Processing Pipeline

swift
import Foundation
import CoreImage

// Large image processing dengan ownership yang jelas
struct ProcessableImage {
    var cgImage: CGImage
    var metadata: [String: Any]
    
    var sizeInBytes: Int {
        cgImage.width * cgImage.height * cgImage.bitsPerPixel / 8
    }
}

struct ImagePipeline {
    
    // Hanya inspect — borrowing
    static func analyze(image: borrowing ProcessableImage) -> ImageAnalysis {
        let brightness = computeBrightness(image.cgImage)
        let sharpness = computeSharpness(image.cgImage)
        return ImageAnalysis(brightness: brightness, sharpness: sharpness, size: image.sizeInBytes)
    }
    
    // Transform — consuming + hasilkan baru
    static func resize(
        _ image: consuming ProcessableImage,
        to size: CGSize
    ) -> ProcessableImage {
        let resizedCG = resizeCGImage(image.cgImage, to: size)
        return ProcessableImage(
            cgImage: resizedCG,
            metadata: image.metadata  // metadata di-copy (kecil, OK)
        )
    }
    
    static func applyFilter(
        _ image: consuming ProcessableImage,
        filter: CIFilter
    ) -> ProcessableImage {
        let ciImage = CIImage(cgImage: image.cgImage)
        filter.setValue(ciImage, forKey: kCIInputImageKey)
        let outputCI = filter.outputImage!
        let outputCG = CIContext().createCGImage(outputCI, from: outputCI.extent)!
        return ProcessableImage(cgImage: outputCG, metadata: image.metadata)
    }
    
    // Consuming final step
    static func export(
        _ image: consuming ProcessableImage,
        format: ExportFormat,
        quality: Double
    ) -> Data {
        switch format {
        case .jpeg: return encodeJPEG(image.cgImage, quality: quality)
        case .png: return encodePNG(image.cgImage)
        case .webp: return encodeWebP(image.cgImage, quality: quality)
        }
    }
}

// Penggunaan:
func processUserAvatar(original: ProcessableImage) async -> Data {
    // Analyze dulu (borrowing — tidak berubah)
    let analysis = ImagePipeline.analyze(image: original)
    
    // Proses (consuming pipeline)
    let processed = ImagePipeline
        .resize(original, to: CGSize(width: 256, height: 256))  // original di-consume
        // original tidak bisa dipakai lagi setelah ini ↑
        
    let filtered: ProcessableImage
    if analysis.sharpness < 0.5 {
        filtered = ImagePipeline.applyFilter(processed, filter: sharpenFilter)
    } else {
        filtered = processed  // move — tidak ada copy
    }
    
    return ImagePipeline.export(filtered, format: .webp, quality: 0.85)
}

struct ImageAnalysis { var brightness, sharpness: Double; var size: Int }
enum ExportFormat { case jpeg, png, webp }

func computeBrightness(_ image: CGImage) -> Double { 0.5 }
func computeSharpness(_ image: CGImage) -> Double { 0.7 }
func resizeCGImage(_ image: CGImage, to size: CGSize) -> CGImage { image }
func encodeJPEG(_ image: CGImage, quality: Double) -> Data { Data() }
func encodePNG(_ image: CGImage) -> Data { Data() }
func encodeWebP(_ image: CGImage, quality: Double) -> Data { Data() }
let sharpenFilter = CIFilter()

Use Case 2: Query Builder dengan consuming

swift
// SQL/NoSQL query builder yang type-safe dan zero-copy
struct QueryBuilder {
    private var table: String
    private var conditions: [String] = []
    private var orderByClause: String?
    private var limitCount: Int?
    private var selectColumns: [String] = ["*"]
    
    init(table: String) {
        self.table = table
    }
    
    // consuming: setiap step menghasilkan builder baru
    consuming func select(_ columns: String...) -> QueryBuilder {
        var builder = self
        builder.selectColumns = columns
        return builder
    }
    
    consuming func `where`(_ condition: String) -> QueryBuilder {
        var builder = self
        builder.conditions.append(condition)
        return builder
    }
    
    consuming func orderBy(_ column: String, ascending: Bool = true) -> QueryBuilder {
        var builder = self
        builder.orderByClause = "\(column) \(ascending ? "ASC" : "DESC")"
        return builder
    }
    
    consuming func limit(_ count: Int) -> QueryBuilder {
        var builder = self
        builder.limitCount = count
        return builder
    }
    
    // Terminal operation — consuming builder, menghasilkan SQL string
    consuming func toSQL() -> String {
        var sql = "SELECT \(selectColumns.joined(separator: ", ")) FROM \(table)"
        if !conditions.isEmpty {
            sql += " WHERE " + conditions.joined(separator: " AND ")
        }
        if let order = orderByClause {
            sql += " ORDER BY \(order)"
        }
        if let limit = limitCount {
            sql += " LIMIT \(limit)"
        }
        return sql
    }
}

// Penggunaan — ergonomis dan type-safe
let query = QueryBuilder(table: "users")
    .select("id", "name", "email")
    .where("active = true")
    .where("age >= 18")
    .orderBy("created_at", ascending: false)
    .limit(10)
    .toSQL()

// query = "SELECT id, name, email FROM users WHERE active = true AND age >= 18 ORDER BY created_at DESC LIMIT 10"

Use Case 3: Data Serializer dengan borrowing

swift
// High-performance serializer — borrowing untuk semua input
struct BinarySerializer {
    private var buffer: [UInt8] = []
    
    // Semua encode methods: borrowing — tidak perlu copy input
    mutating func encode(string: borrowing String) {
        let bytes = Array(string.utf8)
        encode(uint32: UInt32(bytes.count))
        buffer.append(contentsOf: bytes)
    }
    
    mutating func encode(uint32 value: borrowing UInt32) {
        withUnsafeBytes(of: value.bigEndian) { buffer.append(contentsOf: $0) }
    }
    
    mutating func encode(data: borrowing Data) {
        encode(uint32: UInt32(data.count))
        buffer.append(contentsOf: data)
    }
    
    mutating func encode(array: borrowing [String]) {
        encode(uint32: UInt32(array.count))
        for item in array {
            encode(string: item)  // borrow setiap item
        }
    }
    
    // consuming: hasilkan final Data
    consuming func finalize() -> Data {
        Data(buffer)
    }
}

struct UserMessage {
    var id: String
    var content: String
    var attachments: [String]
    var timestamp: UInt32
}

// Serialize tanpa copy UserMessage
func serialize(message: borrowing UserMessage) -> Data {
    var serializer = BinarySerializer()
    serializer.encode(string: message.id)
    serializer.encode(string: message.content)
    serializer.encode(array: message.attachments)
    serializer.encode(uint32: message.timestamp)
    return serializer.finalize()
}

// Penggunaan — message tidak di-copy
let message = UserMessage(id: "msg_123", content: "Hello!", attachments: [], timestamp: 1234567890)
let serialized = serialize(message: message)  // borrowing — tidak ada copy
// message masih valid di sini
print(message.id)  // ✅ OK