# Specta Swift
[](https://crates.io/crates/specta-swift)
[](https://docs.rs/specta-swift)
[](https://opensource.org/licenses/MIT)
A Rust crate for exporting Rust types to Swift, built on top of [Specta](https://github.com/specta-rs/specta). Generate idiomatic Swift code from your Rust type definitions with support for complex unions, generics, and nested structures.
## Features
- ๐ **Zero Runtime Cost** - Compile-time type generation
- ๐ฏ **Idiomatic Swift** - Generates clean, Swift-idiomatic code
- ๐ **Complex Unions** - Full support for Rust enums with all variant types
- ๐งฌ **Generics** - Single and multiple generic type parameters
- ๐ **Recursive Types** - Self-referencing and circular type definitions
- โ๏ธ **Highly Configurable** - Naming conventions, indentation styles, optional syntax
- ๐ฆ **Type Safety** - Leverages Specta's robust type introspection
- ๐งช **Well Tested** - Comprehensive test suite with snapshot testing
- ๐ **Special Types** - Built-in support for Duration with helper structs
- ๐ **Documentation** - Preserves and formats Rust doc comments in Swift
- ๐ง **Custom Codable** - Automatic generation of custom Codable implementations
- ๐จ **Protocol Conformance** - Support for additional Swift protocols
- ๐ **File Export** - Direct export to Swift files with custom headers
## Quick Start
Add `specta-swift` and `specta-serde` to your `Cargo.toml`:
```toml
[dependencies]
specta = { version = "2.0", features = ["derive"] }
specta-serde = "0.0.12"
specta-swift = "0.1"
```
Define your Rust types:
```rust
use specta::{Type, Types};
use specta_swift::Swift;
#[derive(Type)]
struct User {
id: u32,
name: String,
email: Option<String>,
role: UserRole,
}
#[derive(Type)]
enum UserRole {
Guest,
User { permissions: Vec<String> },
Admin { level: u8, department: String },
}
#[derive(Type)]
enum ApiResult<T> {
Success { data: T, status: u16 },
Error { message: String, code: u32 },
Loading { progress: f32 },
}
```
Generate Swift code:
```rust
fn main() {
let types = Types::default()
.register::<User>()
.register::<UserRole>()
.register::<ApiResult<String>>();
let swift = Swift::default();
swift
.export_to("./Types.swift", &types, specta_serde::format)
.unwrap();
}
```
This generates:
```swift
// This file has been generated by Specta. DO NOT EDIT.
import Foundation
enum ApiResult<T>: Codable {
case success(data: T, status: UInt16)
case error(message: String, code: UInt32)
case loading(progress: Float)
}
struct User: Codable {
let id: UInt32
let name: String
let email: String?
let role: UserRole
}
enum UserRole: Codable {
case guest
case user(permissions: [String])
case admin(level: UInt8, department: String)
}
```
## Advanced Features
### Complex Union Types
Specta Swift supports all Rust enum variant types:
```rust
#[derive(Type)]
enum ComplexUnion {
// Unit variant
None,
// Tuple variant
Tuple(String, u32, bool),
// Named fields variant
NamedFields {
id: u32,
name: String,
active: bool,
},
// Nested struct variant
UserStruct(User),
// Nested enum variant
UserType(UserType),
// Complex nested structure
Complex {
user: User,
metadata: Vec<String>,
settings: Option<Admin>,
},
}
```
Generates:
```swift
enum ComplexUnion: Codable {
case none
case tuple(String, UInt32, Bool)
case namedfields(id: UInt32, name: String, active: Bool)
case userstruct(User)
case usertype(UserType)
case complex(user: User, metadata: [String], settings: Admin?)
}
```
### Generic Types
Full support for generic types with multiple parameters:
```rust
#[derive(Type)]
enum DatabaseResult<T, E> {
Ok { data: T, affected_rows: u64 },
Err { error: E, query: String },
ConnectionError { host: String, port: u16 },
}
```
### Recursive Types
Self-referencing types are fully supported:
```rust
#[derive(Type)]
enum Shape {
None,
Point(f64, f64),
Circle { center: Point, radius: f64 },
Complex { shapes: Vec<Shape>, metadata: Option<String> },
}
```
## Configuration
### Naming Conventions
```rust
use specta_swift::{Swift, NamingConvention};
// PascalCase (default)
let swift = Swift::default();
// camelCase
let swift = Swift::new().naming(NamingConvention::CamelCase);
// snake_case
let swift = Swift::new().naming(NamingConvention::SnakeCase);
```
### Optional Styles
```rust
use specta_swift::{Swift, OptionalStyle};
// T? syntax (default)
let swift = Swift::default();
// Optional<T> syntax
let swift = Swift::new().optionals(OptionalStyle::Optional);
```
### Indentation Styles
```rust
use specta_swift::{Swift, IndentStyle};
// 4 spaces (default)
let swift = Swift::default();
// 2 spaces
let swift = Swift::new().indent(IndentStyle::Spaces(2));
// Tabs
let swift = Swift::new().indent(IndentStyle::Tabs);
```
### Custom Headers
```rust
let swift = Swift::new()
.header("// Generated by MyApp v2.0\n// Custom header with app info\n// DO NOT EDIT MANUALLY")
.naming(NamingConvention::SnakeCase);
```
### Additional Protocols
```rust
let swift = Swift::new()
.add_protocol("Equatable")
.add_protocol("Hashable")
.add_protocol("CustomStringConvertible");
```
### Serde Integration
```rust
let swift = Swift::new()
.add_protocol("CustomDebugStringConvertible");
let output = swift.export(&types, specta_serde::format).unwrap();
```
## Type Mapping
| `i8`, `i16`, `i32`, `i64` | `Int8`, `Int16`, `Int32`, `Int64` | Signed integers |
| `u8`, `u16`, `u32`, `u64` | `UInt8`, `UInt16`, `UInt32`, `UInt64` | Unsigned integers |
| `f32`, `f64` | `Float`, `Double` | Floating point numbers |
| `bool` | `Bool` | Boolean values |
| `char` | `Character` | Single Unicode character |
| `String` | `String` | UTF-8 strings |
| `Option<T>` | `T?` or `Optional<T>` | Optional values (configurable) |
| `Vec<T>` | `[T]` | Arrays |
| `Vec<Vec<T>>` | `[[T]]` | Nested arrays |
| `HashMap<K, V>` | `[K: V]` | Dictionaries |
| `(T, U)` | `(T, U)` | Tuples |
| `std::time::Duration` | `RustDuration` + helper | With automatic helper struct |
| `struct` | `struct` | Structures |
| `enum` | `enum` | Enums with custom Codable |
## Special Features
### Duration Support
`std::time::Duration` types are automatically converted to a `RustDuration` helper struct:
```rust
#[derive(Type)]
struct Metrics {
processing_time: Duration,
timeout: Duration,
}
```
Generates:
```swift
// MARK: - Duration Helper
public struct RustDuration: Codable {
public let secs: UInt64
public let nanos: UInt32
public var timeInterval: TimeInterval {
return Double(secs) + Double(nanos) / 1_000_000_000.0
}
}
public struct Metrics: Codable {
public let processingTime: RustDuration
public let timeout: RustDuration
}
```
### Documentation Support
Rust doc comments are preserved and formatted for Swift:
```rust
/// A comprehensive user account
///
/// This struct represents a complete user account with all necessary
/// information for authentication and personalization.
///
/// # Security Notes
/// - The password field should never be logged
/// - All timestamps are in UTC
#[derive(Type)]
struct User {
/// Unique identifier
id: u32,
/// User's display name
name: String,
}
```
Generates:
```swift
/// A comprehensive user account
///
/// This struct represents a complete user account with all necessary
/// information for authentication and personalization.
///
/// # Security Notes
/// - The password field should never be logged
/// - All timestamps are in UTC
public struct User: Codable {
/// Unique identifier
public let id: UInt32
/// User's display name
public let name: String
}
```
## Examples
Check out the `examples/` directory for comprehensive examples:
- `basic_types.rs` - Basic primitive types and their Swift equivalents
- `advanced_unions.rs` - Complex enum scenarios and custom Codable implementations
- `configuration_options.rs` - All Swift exporter configuration settings
- `special_types.rs` - Duration types and special type handling
- `string_enums.rs` - String enums and custom Codable patterns
- `comprehensive_demo.rs` - Complete feature showcase (28 types!)
- `simple_usage.rs` - Quick start example
- `comments_example.rs` - Documentation and comment support
Run any example:
```bash
cargo run --example basic_types
cargo run --example comprehensive_demo
```
Generated Swift files are saved to `examples/generated/` for inspection.
## Testing
Run the test suite:
```bash
cargo test
```
The test suite includes:
- Basic type generation tests
- Comprehensive union type tests
- Advanced recursive type tests
- Duration type mapping tests
- Custom Codable implementation tests
- Configuration option tests
- Snapshot testing for generated code
- String enum handling tests
- Generic type parameter tests
## Contributing
Contributions are welcome! Please see the main [Specta repository](https://github.com/specta-rs/specta) for contribution guidelines.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Related Projects
- [Specta](https://github.com/specta-rs/specta) - Core type introspection library
- [Specta TypeScript](https://github.com/specta-rs/specta/tree/main/specta-typescript) - TypeScript exporter
- [Specta Go](https://github.com/specta-rs/specta/tree/main/specta-go) - Go exporter