Skip to content

Commit

Permalink
doc: added sample usage tutorials
Browse files Browse the repository at this point in the history
  • Loading branch information
soumyamahunt committed Jan 9, 2024
1 parent a28bb9c commit 2670fde
Show file tree
Hide file tree
Showing 65 changed files with 855 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .github/config/spellcheck-wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ vscode
watchOS
www
typealias
customizable
enum
enums
72 changes: 69 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MetaCodable

[![API Docs](http://img.shields.io/badge/Read_the-docs-2196f3.svg)](https://swiftpackageindex.com/SwiftyLab/MetaCodable/main/documentation/metacodable)
[![API Docs](http://img.shields.io/badge/Read_the-docs-2196f3.svg)](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/metacodable)
[![Swift Package Manager Compatible](https://img.shields.io/github/v/tag/SwiftyLab/MetaCodable?label=SPM&color=orange)](https://badge.fury.io/gh/SwiftyLab%2FMetaCodable)
[![Swift](https://img.shields.io/badge/Swift-5.9+-orange)](https://img.shields.io/badge/Swift-5-DE5D43)
[![Platforms](https://img.shields.io/badge/Platforms-all-sucess)](https://img.shields.io/badge/Platforms-all-sucess)
Expand Down Expand Up @@ -229,13 +229,79 @@ Library provides following helpers that address common custom decoding/encoding
- Custom Date decoding/encoding with UNIX timestamp (`Since1970DateCoder`) or date formatters (`DateCoder`, `ISO8601DateCoder`).
- `Base64Coder` to decode/encode data in base64 string representation.

And more, see the full documentation for [`HelperCoders`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/main/documentation/helpercoders) for more details.
And more, see the full documentation for [`HelperCoders`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/helpercoders) for more details.

You can even create your own by conforming to `HelperCoder`.

</details>

See the full documentation for [`MetaCodable`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/main/documentation/metacodable) and [`HelperCoders`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/main/documentation/helpercoders), for API details and advanced use cases.
<details>
<summary>Represent data with variations in the form of external/internal/adjacent tagging, with single enum with each case as a variation.</summary>

i.e. while `Swift` compiler only generates implementation assuming external tagged enums, only following data:

```json
[
{
"load": {
"key": "MyKey"
}
},
{
"store": {
"key": "MyKey",
"value": 42
}
}
]
```

can be represented by following `enum` with current compiler implementation:

```swift
enum Command {
case load(key: String)
case store(key: String, value: Int)
}
```

while `MetaCodable` allows data in both of the following format to be represented by above `enum` as well:

```json
[
{
"type": "load",
"key": "MyKey"
},
{
"type": "store",
"key": "MyKey",
"value": 42
}
]
```

```json
[
{
"type": "load",
"content": {
"key": "MyKey"
}
},
{
"type": "store",
"content": {
"key": "MyKey",
"value": 42
}
}
]
```

</details>

See the full documentation for [`MetaCodable`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/metacodable) and [`HelperCoders`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/helpercoders), for API details and advanced use cases.
Also, [see the limitations](Sources/MetaCodable/MetaCodable.docc/Limitations.md).

## Contributing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct EnumCaseVariableDeclSyntax: MemberGroupSyntax, AttributableDeclSyntax {
/// The `Variable` type this syntax represents.
///
/// Represents basic enum-case variable decoding/encoding data.
typealias Variable = EnumCaseVariable
typealias Variable = BasicEnumCaseVariable

/// The actual variable syntax.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ final class CodingKeysMap {
/// `add(forKeys:field:context:)`
/// method.
private var data: OrderedDictionary<String, Case> = [:]
/// The `CodingKey`s that have been used.
///
/// Represents these `CodingKey`s have been used
/// in generated code syntax and must be present as case
/// in generated `CodingKey` enum declaration.
private var usedKeys: Set<String> = []

/// Creates a new case-map with provided enum name.
///
Expand Down Expand Up @@ -116,13 +122,17 @@ final class CodingKeysMap {

/// The case name token syntax available for a key.
///
/// Adds key to the list of used keys, as this method is invoked to use
/// key in generated code syntax.
///
/// - Parameter key: The key to look up against.
/// - Returns: The token syntax for case name stored against
/// a key if exists. Otherwise `nil` returned.
///
/// - Note: Should only be used after case names generated
/// or all the keys for a particular type.
func `case`(forKey key: String) -> TokenSyntax? {
usedKeys.insert(key)
return data[key]?.token
}

Expand All @@ -132,6 +142,8 @@ final class CodingKeysMap {
/// The generated enum is a raw enum of `String` type
/// and confirms to `CodingKey`.
///
/// Only keys used in generated code syntax is present in this enum.
///
/// - Parameter context: The macro expansion context.
/// - Returns: The generated enum declaration syntax.
func decl(in context: some MacroExpansionContext) -> EnumDeclSyntax? {
Expand All @@ -141,7 +153,7 @@ final class CodingKeysMap {
InheritedTypeSyntax(type: "CodingKey" as TypeSyntax)
}
return EnumDeclSyntax(name: typeName, inheritanceClause: clause) {
for (key, `case`) in data {
for (key, `case`) in data where usedKeys.contains(key) {
"case \(`case`.token) = \(literal: key)" as DeclSyntax
}
}
Expand Down
1 change: 1 addition & 0 deletions Sources/MetaCodable/Codable/Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
/// * Use ``Default(_:)`` to provide default value when decoding fails.
/// * Use ``CodedAs(_:)`` to provided custom value for enum cases.
/// * Use ``CodedAt(_:)`` to provide enum-case identifier tag path.
/// * Use ``CodedAs()`` to provide enum-case identifier tag type.
/// * Use ``ContentAt(_:_:)`` to provided enum-case content path.
/// * Use ``IgnoreCoding()``, ``IgnoreDecoding()`` and
/// ``IgnoreEncoding()`` to ignore specific properties/cases from
Expand Down
11 changes: 8 additions & 3 deletions Sources/MetaCodable/CodedAs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
/// when generating final implementations.
///
/// - Important: The value type must be `String` when used in
/// externally tagged enums.
/// externally tagged enums, and internally/adjacently tagged enums
/// without type specified with ``CodedAs()`` macro. When used
/// along with ``CodedAs()`` macro, both the generic type must be same.
@attached(peer)
@available(swift 5.9)
public macro CodedAs<T: Codable>(_ value: T) =
public macro CodedAs<T: Codable & Equatable>(_ value: T) =
#externalMacro(module: "CodableMacroPlugin", type: "CodedAs")

/// Provides the identifier actual type for internally/adjacently tagged enums.
Expand Down Expand Up @@ -56,7 +58,10 @@ public macro CodedAs<T: Codable>(_ value: T) =
/// will be used for comparison. If the type here conforms to
/// `ExpressibleByStringLiteral` and can be represented by case name
/// as `String` literal then no need to provide value with ``CodedAs(_:)``.
///
/// - Important: This attribute must be used combined with ``Codable()``
/// and ``CodedAt(_:)``.
@attached(peer)
@available(swift 5.9)
public macro CodedAs<T: Codable>() =
public macro CodedAs<T: Codable & Equatable>() =
#externalMacro(module: "CodableMacroPlugin", type: "CodedAs")
8 changes: 7 additions & 1 deletion Sources/MetaCodable/CodedBy.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// Indicates the field needs to be decoded and encoded by
/// Indicates the field/enum identifier needs to be decoded and encoded by
/// the provided `helper` instance.
///
/// An instance confirming to ``HelperCoder`` can be provided
Expand All @@ -7,6 +7,9 @@
/// sequence from JSON ignoring invalid data matches instead of throwing error
/// (failing decoding of entire sequence).
///
/// For enums, applying this attribute means ``HelperCoder`` will be used to
/// decode and encode identifier value in internally or adjacently tagged enums.
///
/// - Parameter helper: The value that performs decoding and encoding.
///
/// - Note: This macro on its own only validates if attached declaration
Expand All @@ -15,6 +18,9 @@
///
/// - Important: The `helper`'s ``HelperCoder/Coded``
/// associated type must be the same as field type.
///
/// - Important: This attribute must be used combined with ``Codable()``
/// and ``CodedAt(_:)`` when applying to enums.
@attached(peer)
@available(swift 5.9)
public macro CodedBy<T: HelperCoder>(_ helper: T) =
Expand Down
3 changes: 3 additions & 0 deletions Sources/MetaCodable/ContentAt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
/// - Note: This macro on its own only validates if attached declaration
/// is a variable declaration. ``Codable()`` macro uses this macro
/// when generating final implementations.
///
/// - Important: This attribute must be used combined with ``Codable()``
/// and ``CodedAt(_:)``.
@attached(peer)
@available(swift 5.9)
public macro ContentAt(_ path: StaticString, _: StaticString...) =
Expand Down
1 change: 1 addition & 0 deletions Sources/MetaCodable/HelperCoders/LossySequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ where S: Codable, S.Element: Codable {
}

/// A sequence type that can be initialized from another sequence.
@_documentation(visibility:internal)
public protocol SequenceInitializable: Sequence {
/// Creates a new instance of a sequence containing the elements of
/// provided sequence.
Expand Down
6 changes: 5 additions & 1 deletion Sources/MetaCodable/MetaCodable.docc/Limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Currently all the limitations of this library and possible workarounds and futur

### Why strict typing is necessary?

`Swift` doesn't provide any type inference data, so to know type of variables ``Codable()`` needs types to be explicitly specified in the code. i.e. following code will not work and will cause error while macro expansion:
`Swift` compiler doesn't provide any type inference data to macros, so to know type of variables ``Codable()`` needs types to be explicitly specified in the code. i.e. following code will not work and will cause error while macro expansion:

```swift
@Codable
Expand Down Expand Up @@ -61,6 +61,10 @@ enum SomeEnum {
}
```

### Why `enum`s with raw value aren't supported?

`Swift` compiler by default generates `Codable` conformance for `enum`s with raw value and `MetaCodable` has nothing extra to add for these type of `enum`s. Hence, in this case the default compiler generated implementation can be used.

### Why `actor` conformance to `Encodable` not generated?

For `actor`s ``Codable()`` generates `Decodable` conformance, while `Encodable` conformance isn't generated, only `encode(to:)` method implementation is generated which is isolated to `actor`.
Expand Down
6 changes: 6 additions & 0 deletions Sources/MetaCodable/MetaCodable.docc/MetaCodable.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ Supercharge `Swift`'s `Codable` implementations with macros.

## Topics

### Essentials

- <doc:/tutorials/Usage>
- <doc:Limitations>

### Macros

- ``Codable()``
Expand All @@ -59,6 +64,7 @@ Supercharge `Swift`'s `Codable` implementations with macros.
- ``CodedIn(_:)``
- ``Default(_:)``
- ``CodedBy(_:)``
- ``CodedAs()``
- ``CodedAs(_:)``
- ``ContentAt(_:_:)``
- ``IgnoreCoding()``
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@Codable
enum Command {
case load
case store
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@Codable
enum Command {
case load(key: String)
case store(key: String, value: Int)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@Codable
enum Command {
case load(_ key: String)
case store(key: String, value: Int)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@Codable
enum Command {
@CodedAs("load")
case loads(_ key: String)
case store(key: String, value: Int)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@Codable
enum Command {
@CodedAs("load")
case loads(_ key: String)
case store(StoredData)

struct StoredData {
let key: String
let value: Int
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@Codable
enum Command {
@CodedAs("load")
case loads(_ key: String)
case store(StoredData)
@IgnoreCoding
case dumpToDisk

struct StoredData {
let key: String
let value: Int
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@Codable
enum Command {
@CodedAs("load")
case loads(_ key: String)
case store(StoredData)
case execute(filePath: String)
@CodingKeys(.snake_case)
case send(localData: String)
@IgnoreCoding
case dumpToDisk

struct StoredData {
let key: String
let value: Int
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@Codable
@CodedAt("type")
enum Command {
case load(key: String)
case store(key: String, value: Int)
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@Codable
@CodedAt("type")
@CodedAs<Int>
enum Command {
case load(key: String)
case store(key: String, value: Int)
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@Codable
@CodedAt("type")
@CodedAs<Int>
enum Command {
@CodedAs(0)
case load(key: String)
@CodedAs(1)
case store(key: String, value: Int)
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@Codable
@CodedAt("type")
@ContentAt("content")
enum Command {
case load(key: String)
case store(key: String, value: Int)
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@Codable
@CodedAt("type")
@ContentAt("content")
enum Command {
case load(key: String)
case store(key: String, value: Int)
case ignore(count: Int = 1)
@IgnoreCodingInitialized
case dumpToDisk(info: Int = 0)
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2670fde

Please sign in to comment.