Swiftpack.co - App-Maker-Software/TypeWrapper as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
App-Maker-Software/TypeWrapper
A better solution than dealing with Any.Type directly
.package(url: "https://github.com/App-Maker-Software/TypeWrapper.git", from: "1.2.3")

Type Wrapper

A better solution than dealing with Any.Type directly. This library was made for App Maker's Swift interpreter.

Using TypeWrapper allows you to put complex types (such a generics or protocols with associate types) into a simple wrapper allowing you to still attempt to use underlying methods. This allows us to do robust work with types without the concrete type.

Example from SwiftUI

If we have a type Any, we can't know how to call shared methods on the protocol View.

var someView: Any = SwiftUI.Text("hello world")
if condition {
    someView = SwiftUI.Button("click me") { print("clicked") }
}
let redView = someView.foregroundColor(.red) // ❌ impossible to call without a cast...and we don't know if we have a button or a text

Solution with TypeWrapper:

// setup
extension TypeWrapper {
    func makeRed(_ someView: Any) throws -> AnyWithTypeWrapper {
        try self.attempt {
            ($0 as? _SwiftUIView)?.onReceive(input: someView)
        }
    }
}
protocol _SwiftUIView {
    func onReceive(input: Any) -> AnyWithTypeWrapper
}
extension AttemptIfConformsStruct: _SwiftUIView where Wrapped: View {
    public func onReceive(input: Any) -> AnyWithTypeWrapper {
        let view = input as! Wrapped
        let redView = view.foregroundColor(.red)
        return addTypeWrapper(redView)
    }
}


// usage
var anyWithTypeWrapper: AnyWithTypeWrapper = addTypeWrapper(SwiftUI.Text("hello world"))
if condition {
    anyWithTypeWrapper = addTypeWrapper(SwiftUI.Button("click me") { print("clicked") })
}
anyWithTypeWrapper = try anyWithTypeWrapper.typeWrapper.makeRed(anyWithTypeWrapper.any) // ✅ works no matter what type we put in...as long as it conforms to View
print(anyWithTypeWrapper.any) // raw value
print(anyWithTypeWrapper.typeWrapper) // type wrapper

You can see how this can be useful if you have an array of things of type View and you want to make changes without using AnyView:

var array: [AnyWithTypeWrapper] = ...

// make them all red without use of "AnyView"
for i in 0..<array.count {
    let el = array[i]
    array[i] = try el.typeWrapper.makeRed(el.any)
}

Generics

Let's say we have this generic type:

public struct Example<T: FloatingPoint & ExpressibleByFloatLiteral> {
    let floatingPointValue: T
}

Usually we would need a type eraser if we'd want to work with different concrete implementations, but with TypeWrapper we can get around that. First we register our generic values:

extension Example: Register1Generic {
    public typealias Generic0 = T
}

Here we used Register1Generic, because we have one generic...but we could have also done Register2Generics or even Register5Generics which would give us more typealiases to map to our generic types. Then to implement a method for TypeWrapper, we do the following:

extension TypeWrapper {
    func add12Point4ToGenericType(_ any: Any) throws -> AnyWithTypeWrapper {
        try self.attempt {
            ($0 as? _CustomTypeWithGenericFloatingPoint)?.onReceive(input: any)
        }
    }
}
protocol _Example {
    func onReceive(input: Any) throws -> AnyWithTypeWrapper
}
extension AttemptIfConformsStruct: _Example where Wrapped == Example<Generics.Generic0>, Generics.Generic0: FloatingPoint & ExpressibleByFloatLiteral {
    public func onReceive(input: Any) throws -> AnyWithTypeWrapper {
        let floatingPointValue = (input as! Wrapped).floatingPointValue
        let twelvePoint4: Generics.Generic0 = 12.4
        let result = floatingPointValue + twelvePoint4
        return addTypeWrapper(result)
    }
}

Example Implementations

Goto the example implementations folder to see how to easily implement this for a type you wish to wrap in your code.

Sources

Implementation inspired by: https://forums.swift.org/t/test-if-a-type-conforms-to-a-non-existential-protocol/35479/40

GitHub

link
Stars: 0
Last commit: 2 weeks ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.

Submit a free job ad (while I'm testing this). The analytics numbers for this website are here.

Release Notes

1.0.0
4 weeks ago

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics