Skip to content

Macros for adding the `copyWith` function to structures. And more.

License

Notifications You must be signed in to change notification settings

VAndrJ/VACopyWith

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VACopyWith

StandWithUkraine Support Ukraine

Language SPM Platform

@CopyWith

Adds an extension with the copyWith function. Works with the default initializer and has some other limitations. For example, the following syntax is not supported:

struct SomeStruct {
    let (a, b): (Int, Int)
}

Example 1:

            
@CopyWith
struct SomeStruct {
    let a: Int
    let b: Bool
}

// expands to

struct SomeStruct {
    let a: Int
    let b: Bool
}

extension SomeStruct {
    func copyWith(
        a: Int? = nil, 
        b: Bool? = nil
    ) -> SomeStruct {
        SomeStruct(
            a: a ?? self.a,
            b: b ?? self.b
        )
    }
}

// usage

let exampleStruct = SomeStruct(a: 1, b: false)
let exampleStructWith10 = exampleStruct.copyWith(a: 10)
let exampleStructWithTrue = exampleStruct.copyWith(b: true)

Example 2:

@CopyWith
public struct SomeStruct {
    let a: String?
    let b: Int
}

// expands to

public struct SomeStruct {
    let a: String?
    let b: Int
}

public extension SomeStruct {
    public enum OR<T> {
        case value(T)
        case `nil`
        case ignored
    }
    func copyWith(
        a: OR<String> = .ignored, 
        b: Int? = nil
    ) -> SomeStruct {
        let a: String? = switch a {
        case let .value(value):
            value
        case .nil:
            nil
        case .ignored:
            self.a
        }
        return SomeStruct(
            a: a,
            b: b ?? self.b
        )
    }
}

// usage

let exampleStruct = SomeStruct(a: "a", b: 0)
let exampleStructWithResetA = exampleStruct.copyWith(a: .nil)
let exampleStructWithNewA = exampleStruct.copyWith(a: .value("some string"))

Here an auxiliary enum is added to simplify working with optional properties and clear syntax.

Example 3:

@CopyWith
struct SomeStruct {
    let id = "const uuidstring ;)"
    let constantProperty = false
    var boolValue = true
    var intValue = 1
    var doubleValue = 1.0
    var stringValue = "a"
    var customValue = MyCustomType(property: 1)
}

// expands to

struct SomeStruct {
    let id = "const uuidstring ;)"
    let constantProperty = false
    var boolValue = true
    var intValue = 1
    var doubleValue = 1.0
    var stringValue = "a"
    var customValue = MyCustomType(property: 1)
}

extension SomeStruct {
    func copyWith(
        boolValue: Bool? = nil,
        intValue: Int? = nil,
        doubleValue: Double? = nil,
        stringValue: String? = nil,
        customValue: MyCustomType? = nil
    ) -> SomeStruct {
        SomeStruct(
            boolValue: boolValue ?? self.boolValue,
            intValue: intValue ?? self.intValue,
            doubleValue: doubleValue ?? self.doubleValue,
            stringValue: stringValue ?? self.stringValue,
            customValue: customValue ?? self.customValue
        )
    }
}

// usage

let exampleStruct = SomeStruct()
let exampleStructWithFalse = exampleStruct.copyWith(boolValue: false)

@MutatedCopy

Adds an extension to a struct with a mutatedCopy function if var fields are present, or to protocol without fields check.

Example 1:

@MutatedCopy
struct SomeStruct: Equatable {
    let id = "const uuidstring ;)"
    var intValue: Int
    var boolValue: Bool
}

// expands to

struct SomeStruct: Equatable {
    let id = "const uuidstring ;)"
    var intValue: Int
    var boolValue: Bool
}

extension SomeStruct {
    func mutatedCopy(configuring: (_ it: inout SomeStruct) throws -> Void) rethrows -> SomeStruct {
        var mutableCopy = self
        try configuring(&mutableCopy)

        return mutableCopy
    }
}

Example 2:

@MutatedCopy
protocol SomeProtocol: Equatable {}

struct SomeStruct: SomeProtocol {
    let id = "const uuidstring ;)"
    var intValue: Int
    var boolValue: Bool
}

// expands to

protocol SomeProtocol: Equatable {}

extension SomeProtocol {
    func mutatedCopy(configuring: (_ it: inout Self) throws -> Void) rethrows -> Self {
        var mutableCopy = self
        try configuring(&mutableCopy)

        return mutableCopy
    }
}

struct SomeStruct: SomeProtocol {
    let id = "const uuidstring ;)"
    var intValue: Int
    var boolValue: Bool
}

// usage

let exampleStruct = SomeStruct(parameter1: 0, parameter2: false)
let exampleStructModified = exampleStruct.mutatedCopy {
    $0.intValue = 42
    $0.boolValue = true
}

@Mutating

Adds an extension to a class with a mutating function if var fields are present, or to protocol without fields check.

Example 1:

@Mutating
class SomeClass {
    var intValue: Int = 0
    var boolValue: Bool = false
}

// expands to

class SomeClass {
    var intValue: Int = 0
    var boolValue: Bool = false
}

extension SomeClass {
    @discardableResult
    func mutating(configuring: (_ it: SomeClass) throws -> Void) rethrows -> SomeClass {
        try configuring(&self)

        return self
    }
}

// usage

let exampleClass = SomeClass().mutating {
    $0.intValue = 42
    $0.boolValue = true
}

Example 2:

@Mutating
protocol SomeProtocol: AnyObject {}

class SomeClass: SomeProtocol {
    var intValue: Int = 0
    var boolValue: Bool = false
}

// expands to
protocol SomeProtocol: AnyObject {}

extension SomeProtocol {
    @discardableResult
    func mutating(configuring: (_ it: Self) throws -> Void) rethrows -> Self {
        try configuring(&self)

        return self
    }
}

class SomeClass: SomeProtocol {
    var intValue: Int = 0
    var boolValue: Bool = false
}

// usage

let exampleClass = SomeClass().mutating {
    $0.intValue = 42
    $0.boolValue = true
}

TBD

  • Tuples.

Author

Volodymyr Andriienko, vandrjios@gmail.com

License

VACopyWith is available under the MIT license. See the LICENSE file for more info.

About

Macros for adding the `copyWith` function to structures. And more.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages