Skip to content

Commit

Permalink
adding more documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
leogdion committed Apr 29, 2024
1 parent c1669ed commit 927cecc
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 24 deletions.
16 changes: 12 additions & 4 deletions Sources/Options/Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,25 @@
public protocol MappedValueCollectionRepresented: MappedValueRepresented
where MappedValueType: Sequence {}

extension Array: MappedValues where Element: Equatable {
public func key(value: Element) throws -> Int {
extension Array: MappedValues where Element: Equatable {}

extension Collection where Element: Equatable, Self: MappedValues {
/// Get the index based on the value passed.
/// - Parameter value: Value to search.
/// - Returns: Index found.
public func key(value: Element) throws -> Self.Index {
guard let index = firstIndex(of: value) else {
throw MappedValueRepresentableError.valueNotFound
}

return index
}

public func value(key: Int) throws -> Element {
guard key < count, key >= 0 else {
/// Gets the value based on the index.
/// - Parameter key: The index.
/// - Returns: The value at index.
public func value(key: Self.Index) throws -> Element {
guard key < endIndex, key >= startIndex else {
throw MappedValueRepresentableError.valueNotFound
}
return self[key]
Expand Down
5 changes: 5 additions & 0 deletions Sources/Options/CodingOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,15 @@

import Foundation

/// Options for how a ``MappedValueRepresentable`` type is encoding and decoded.
public struct CodingOptions: OptionSet, Sendable {
/// Allow decoding from String
public static let allowMappedValueDecoding: CodingOptions = .init(rawValue: 1)

/// Encode the value as a String.
public static let encodeAsMappedValue: CodingOptions = .init(rawValue: 2)

/// Default options.
public static let `default`: CodingOptions =
[.allowMappedValueDecoding, encodeAsMappedValue]

Expand Down
6 changes: 3 additions & 3 deletions Sources/Options/Dictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
public protocol MappedValueDictionaryRepresented: MappedValueRepresented
where MappedValueType == [Int: MappedType] {}

extension Dictionary: MappedValues where Key == Int, Value: Equatable {
public func key(value: Value) throws -> Int {
extension Dictionary: MappedValues where Value: Equatable {
public func key(value: Value) throws -> Key {
let pair = first { $0.value == value }
guard let key = pair?.key else {
throw MappedValueRepresentableError.valueNotFound
Expand All @@ -42,7 +42,7 @@ extension Dictionary: MappedValues where Key == Int, Value: Equatable {
return key
}

public func value(key: Int) throws -> Value {
public func value(key: Key) throws -> Value {
guard let value = self[key] else {
throw MappedValueRepresentableError.valueNotFound
}
Expand Down
35 changes: 31 additions & 4 deletions Sources/Options/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct SocialNetworkSet : Int, OptionSet {
}

let user : User
let networks : SocialNetworks = user.availableNetworks()
let networks : SocialNetworkSet = user.availableNetworks()
```

We can then simply use ``Options()`` macro to generate both these types:
Expand Down Expand Up @@ -103,13 +103,39 @@ enum SocialNetwork : Int {
Now we can use the newly create `SocialNetworkSet` type to store a set of values:

```swift
let networks : SocialNetworks
let networks : SocialNetworkSet
networks = [.aim, .delicious, .googleplus, .windowslive]
```

### Multiple Value Types

With the ``Options()`` macro, we add the ability to encode and decode values not only from their raw Integer value but also from a String. This is useful for when you want to store the values in
With the ``Options()`` macro, we add the ability to encode and decode values not only from their raw value but also from a another type such as a string. This is useful for when you want to store the values in JSON format.

For instance, with a type like `SocialNetwork` we need need to store the value as an Integer:

```json
5
```

However by adding the ``Options()`` macro we can also decode from a String:

```
"googleplus"
```

### Creating an OptionSet

We can also have a new `OptionSet` type created. ``Options()`` create a new `OptionSet` type with the suffix `-Set`. This new `OptionSet` will automatically work with your enum to create a distinct set of values. Additionally it will decode and encode your values as an Array of String. This means the value:

```swift
[.aim, .delicious, .googleplus, .windowslive]
```

is encoded as:

```json
["aim", "delicious", "googleplus", "windowslive"]
```

## Topics

Expand All @@ -122,7 +148,7 @@ With the ``Options()`` macro, we add the ability to encode and decode values not

### Advanced customization

- ``MappedEnum``
- ``CodingOptions``
- ``MappedValues``

### Errors
Expand All @@ -133,3 +159,4 @@ With the ``Options()`` macro, we add the ability to encode and decode values not

- ``MappedValueCollectionRepresented``
- ``MappedValueDictionaryRepresented``
- ``MappedEnum``
49 changes: 41 additions & 8 deletions Sources/Options/EnumSet.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
/// Generic struct for using Enums with RawValue type of Int as an Optionset
/// Generic struct for using Enums with `RawValue`.
///
/// If you have an `enum` such as:
/// ```swift
/// @Options
/// enum SocialNetwork : Int {
/// case digg
/// case aim
/// case bebo
/// case delicious
/// case eworld
/// case googleplus
/// case itunesping
/// case jaiku
/// case miiverse
/// case musically
/// case orkut
/// case posterous
/// case stumbleupon
/// case windowslive
/// case yahoo
/// }
/// ```
/// An ``EnumSet`` could be used to store multiple values as an `OptionSet`:
/// ```swift
/// let socialNetworks : EnumSet<SocialNetwork> =
/// [.digg, .aim, .yahoo, .miiverse]
/// ```
public struct EnumSet<EnumType: RawRepresentable>:
OptionSet, Sendable, ExpressibleByArrayLiteral
where EnumType.RawValue == Int {
where EnumType.RawValue: FixedWidthInteger & Sendable {
public typealias RawValue = EnumType.RawValue

/// Raw Value of the OptionSet
public let rawValue: Int
public let rawValue: RawValue

/// Creates the EnumSet based on the `rawValue`
/// - Parameter rawValue: Integer raw value of the OptionSet
public init(rawValue: Int) {
public init(rawValue: RawValue) {
self.rawValue = rawValue
}

Expand All @@ -25,22 +52,28 @@ public struct EnumSet<EnumType: RawRepresentable>:
}

internal static func cumulativeValue(
basedOnRawValues rawValues: Set<Int>) -> Int {
basedOnRawValues rawValues: Set<RawValue>) -> RawValue {
rawValues.map { 1 << $0 }.reduce(0, |)
}
}

extension FixedWidthInteger {
fileprivate static var one: Self {
1
}
}

extension EnumSet where EnumType: CaseIterable {
internal static func enums(basedOnRawValue rawValue: Int) -> [EnumType] {
internal static func enums(basedOnRawValue rawValue: RawValue) -> [EnumType] {
let cases = EnumType.allCases.sorted { $0.rawValue < $1.rawValue }
var values = [EnumType]()
var current = rawValue
for item in cases {
guard current > 0 else {
break
}
let rawValue = 1 << item.rawValue
if current & rawValue != 0 {
let rawValue = RawValue.one << item.rawValue
if current & rawValue != .zero {
values.append(item)
current -= rawValue
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/Options/Macro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import Foundation

#if swift(>=5.10)
/// Sets an enumeration up to implement

Check notice on line 33 in Sources/Options/Macro.swift

View check run for this annotation

codefactor.io / CodeFactor

Sources/Options/Macro.swift#L33

A doc comment should be attached to a declaration. (orphaned_doc_comment)
/// ``MappedValueRepresentable`` and ``MappedValueRepresented``.

Check notice on line 34 in Sources/Options/Macro.swift

View check run for this annotation

codefactor.io / CodeFactor

Sources/Options/Macro.swift#L34

A doc comment should be attached to a declaration. (orphaned_doc_comment)
@attached(
extension,
conformances: MappedValueRepresentable, MappedValueRepresented,
Expand Down
6 changes: 6 additions & 0 deletions Sources/Options/MappedEnum.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
/// A generic struct for enumerations which allow for additional values attached.
@available(
*,
deprecated,
renamed: "MappedValueRepresentable",
message: "Use `MappedValueRepresentable` with `CodingOptions`."
)
public struct MappedEnum<EnumType: MappedValueRepresentable>: Codable, Sendable
where EnumType.MappedType: Codable {
/// Base Enumeraion value.
Expand Down
4 changes: 4 additions & 0 deletions Sources/Options/MappedValueRepresentable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@
// OTHER DEALINGS IN THE SOFTWARE.
//

/// An enum which has an additional value attached.
/// - Note: ``Options()`` macro will automatically set this up for you.
public protocol MappedValueRepresentable: RawRepresentable, CaseIterable, Sendable {
/// The additional value type.
associatedtype MappedType = String

/// Options for how the enum should be decoded or encoded.
static var codingOptions: CodingOptions {
get
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Options/MappedValueRepresentableError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Foundation
/// An Error thrown when the `MappedType` value or `RawType` value
/// are invalid for an `Enum`.
public enum MappedValueRepresentableError: Error, Sendable {
/// Whenever a value or key cannot be found.
case valueNotFound
}
#else
Expand Down
5 changes: 3 additions & 2 deletions Sources/Options/MappedValueRepresented.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@

/// Protocol which simplifies ``MappedValueRepresentable``by using a ``MappedValues``.
public protocol MappedValueRepresented: MappedValueRepresentable
where RawValue == Int, MappedType: Equatable {
associatedtype MappedValueType: MappedValues<MappedType>
where MappedType: Equatable {
/// A object to lookup values and keys for mapped values.
associatedtype MappedValueType: MappedValues<RawValue, MappedType>
/// An array of the mapped values which lines up with each case.
static var mappedValues: MappedValueType { get }
}
Expand Down
8 changes: 5 additions & 3 deletions Sources/Options/MappedValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@
import Foundation

/// Protocol which provides a method for ``MappedValueRepresented`` to pull values.
public protocol MappedValues<Value> {
public protocol MappedValues<Key, Value> {
/// Raw Value Type
associatedtype Value: Equatable
/// Key Value Type
associatedtype Key: Equatable
/// get the key vased on the value.
func key(value: Value) throws -> Int
func key(value: Value) throws -> Key
/// get the value based on the key/index.
func value(key: Int) throws -> Value
func value(key: Key) throws -> Value
}

0 comments on commit 927cecc

Please sign in to comment.