Skip to content

swift macros and other error related helper code 🫡

License

Notifications You must be signed in to change notification settings

walteh/swift-err

Repository files navigation

swift-err

swift-err is a Swift package that provides convenient error handling macros for Swift projects, allowing for more expressive and type-safe error handling.

Features

  • @err function macro to access thrown errors in guard else statements
  • @err_traced includes trace information in thrown errors (file, line, function)
  • Works with any function that can throw, including async functions

Example

@err
func throwsExample() throws async -> String {
    guard let result = try await someThrowingFunction() else {
        throw err // "err" is the error thrown by someThrowingFunction
    }
    return result
}

@err
func resultExample() async -> Result<String, Error> {
    guard let result = await someResultFunction().get() else {
        return .failure(err) // "err" is the error thrown by someResultFunction
    }
    return .success(result)
}

Installation

Add the following dependency to your Package.swift file:

.package(url: "https://github.com/walteh/swift-err.git", branch: "main")

Then, add "Err" to your target's dependencies:

.target(name: "YourTarget", dependencies: ["Err"]),

Usage

Basic Error Handling

Use the @err macro to simplify error handling in your functions:

// Without @err macro
func resultWithoutErrMacro() async -> Result<String, Error> {
    guard let res = try? await myThrowingAsyncFunc(12) else {
        // ⚠️ We have no idea what the error is
        return .failure(UnknownError())
    }
    return .success("\(res)")
}

// With @err macro
@err
func resultWithErrMacro() async -> Result<String, Error> {
    guard let res = try await myThrowingAsyncFunc(12) else {
        // ✅ "err" is the error thrown by myThrowingAsyncFunc
        switch err {
        case is ValidBusinessError:
            return .success("operation already completed")
        default:
            return .failure(err) // or "throw err" if you want to rethrow
        }
    }
    return .success("\(res)")
}

Traced Error Handling

For more detailed error tracing, use the @err_traced macro. This wraps the error with the location (file, line, and function) where the error was triggered.

@err_traced
func tracedExample() throws -> String {
    guard let result = try someThrowingFunction() else {
        throw err // This error will include trace information
    }
    return result
}

How It Works

The @err and @err_traced macros expand to code that captures the error from throwing expressions. Here's a simplified view of what the macro expansion looks like:

// Original code with @err macro
@err
func example() throws -> String {
    guard let result = try someThrowingFunction() else {
        throw err
    }
    return result
}

func example() throws -> String {
    guard let result = someResultFunction().get() else {
        throw err
    }
    return result
}

// Expanded code (simplified)
func example() throws -> String {
    var ___err: Error? = nil
    guard let result = Result.___err___create(catching: {
        try someThrowingFunction()
    }).___to(&___err) else {
        let err = ___err!
        throw err
    }
    return result
}

This expansion allows you to use err in your guard statements to access the thrown error, enabling more expressive error handling.

Testing

The package includes comprehensive unit tests. Run the tests using:

swift test

Requirements

  • Swift 6.0+

License

This project is licensed under the Apache License 2.0.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

About

swift macros and other error related helper code 🫡

Topics

Resources

License

Stars

Watchers

Forks

Languages