Skip to content

Commit

Permalink
Implement a Decoded type for error messaging
Browse files Browse the repository at this point in the history
This introduces a `Decoded` type which is similar to a `Result` type.
It has a success state and 2 failure states. One failure state occurs if
there is a type mismatch and the other is for a missing key in the JSON.
This custom type allows us to retain some information about why a
decoding has failed. It also allows us to abstract the return type that
the user wants.

We have defined a global `decode` function for the user to use. It can
return an optional type, ignoring the failure data, or return the
`Decoded` type if the user would like to retain the error information.
Other return types like `Result` could also easily be implemented in a
particular project.

The 2 different error states will function a bit differently. If the
user wants an optional value from the decoding, indicated by `<|?` or
`<||?` the `Decoded` type will allow failure only if the key is missing
and not if the type is a mismatch.
  • Loading branch information
Tony DiPasquale committed Mar 13, 2015
1 parent 3c65ba2 commit 9a2f1b6
Show file tree
Hide file tree
Showing 24 changed files with 192 additions and 74 deletions.
32 changes: 32 additions & 0 deletions Argo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
EA395DCA1A52FC1400EB607E /* root_object.json in Resources */ = {isa = PBXBuildFile; fileRef = EA395DC91A52FC1400EB607E /* root_object.json */; };
EA395DCB1A52FC1400EB607E /* root_object.json in Resources */ = {isa = PBXBuildFile; fileRef = EA395DC91A52FC1400EB607E /* root_object.json */; };
EA4EAF7319DD96330036AE0D /* types_fail_embedded.json in Resources */ = {isa = PBXBuildFile; fileRef = EA4EAF7219DD96330036AE0D /* types_fail_embedded.json */; };
EA8148B61A9E476D00683AFF /* Decoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA8148B51A9E476D00683AFF /* Decoded.swift */; };
EA8148B71A9E476D00683AFF /* Decoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA8148B51A9E476D00683AFF /* Decoded.swift */; };
EA8148B91A9E573300683AFF /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA8148B81A9E573300683AFF /* decode.swift */; };
EA8148BA1A9E573300683AFF /* decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA8148B81A9E573300683AFF /* decode.swift */; };
EABDF68A1A9CD46100B6CC83 /* SwiftDictionaryDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF6891A9CD46100B6CC83 /* SwiftDictionaryDecodingTests.swift */; };
EABDF68B1A9CD46400B6CC83 /* SwiftDictionaryDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF6891A9CD46100B6CC83 /* SwiftDictionaryDecodingTests.swift */; };
EABDF68F1A9CD4EA00B6CC83 /* PListFileReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF68D1A9CD4EA00B6CC83 /* PListFileReader.swift */; };
Expand All @@ -26,6 +30,10 @@
EABDF6921A9CD4EA00B6CC83 /* types.plist in Resources */ = {isa = PBXBuildFile; fileRef = EABDF68E1A9CD4EA00B6CC83 /* types.plist */; };
EABDF6941A9CD4FC00B6CC83 /* PListDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF6931A9CD4FC00B6CC83 /* PListDecodingTests.swift */; };
EABDF6951A9CD4FC00B6CC83 /* PListDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABDF6931A9CD4FC00B6CC83 /* PListDecodingTests.swift */; };
EAC59A0F1A9F74C500BEB5CC /* DecodedOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC59A0E1A9F74C500BEB5CC /* DecodedOperators.swift */; };
EAC59A101A9F74C500BEB5CC /* DecodedOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC59A0E1A9F74C500BEB5CC /* DecodedOperators.swift */; };
EAD8BF621AA0DD3900A11963 /* Box.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = EAEE2F4B1A9FCC9F00DA2846 /* Box.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EAD8BF631AA0DD4100A11963 /* Box.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = EAEE2F4D1A9FCCAA00DA2846 /* Box.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
EAD9FAEB19D0F6930031E006 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAEA19D0F6930031E006 /* Operators.swift */; };
EAD9FAF419D0F74C0031E006 /* StandardTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAF319D0F74C0031E006 /* StandardTypes.swift */; };
EAD9FAF619D0F7900031E006 /* JSONOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FAF519D0F7900031E006 /* JSONOperators.swift */; };
Expand All @@ -45,6 +53,8 @@
EAD9FB1A19D4B23F0031E006 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD9FB1919D4B23F0031E006 /* JSON.swift */; };
EADADCB21A5DB6F600B180EC /* EquatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADADCB11A5DB6F600B180EC /* EquatableTests.swift */; };
EADADCB41A5DB7F800B180EC /* EquatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADADCB11A5DB6F600B180EC /* EquatableTests.swift */; };
EAEE2F4C1A9FCC9F00DA2846 /* Box.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAEE2F4B1A9FCC9F00DA2846 /* Box.framework */; };
EAEE2F4E1A9FCCAA00DA2846 /* Box.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAEE2F4D1A9FCCAA00DA2846 /* Box.framework */; };
F802D4C31A5EE061005E236C /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802D4C21A5EE061005E236C /* NSURL.swift */; };
F802D4C41A5EE172005E236C /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802D4C21A5EE061005E236C /* NSURL.swift */; };
F802D4C61A5EE2D5005E236C /* url.json in Resources */ = {isa = PBXBuildFile; fileRef = F802D4C51A5EE2D5005E236C /* url.json */; };
Expand Down Expand Up @@ -118,6 +128,7 @@
dstSubfolderSpec = 10;
files = (
F87D9D8D1A92676F00C8AF1D /* Runes.framework in CopyFiles */,
EAD8BF621AA0DD3900A11963 /* Box.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -128,6 +139,7 @@
dstSubfolderSpec = 10;
files = (
F87D9D8F1A92677A00C8AF1D /* Runes.framework in CopyFiles */,
EAD8BF631AA0DD4100A11963 /* Box.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -159,10 +171,13 @@
EA395DC61A52F93B00EB607E /* ExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleTests.swift; sourceTree = "<group>"; };
EA395DC91A52FC1400EB607E /* root_object.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = root_object.json; sourceTree = "<group>"; };
EA4EAF7219DD96330036AE0D /* types_fail_embedded.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = types_fail_embedded.json; sourceTree = "<group>"; };
EA8148B51A9E476D00683AFF /* Decoded.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decoded.swift; sourceTree = "<group>"; };
EA8148B81A9E573300683AFF /* decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = decode.swift; sourceTree = "<group>"; };
EABDF6891A9CD46100B6CC83 /* SwiftDictionaryDecodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftDictionaryDecodingTests.swift; sourceTree = "<group>"; };
EABDF68D1A9CD4EA00B6CC83 /* PListFileReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PListFileReader.swift; sourceTree = "<group>"; };
EABDF68E1A9CD4EA00B6CC83 /* types.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = types.plist; sourceTree = "<group>"; };
EABDF6931A9CD4FC00B6CC83 /* PListDecodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PListDecodingTests.swift; sourceTree = "<group>"; };
EAC59A0E1A9F74C500BEB5CC /* DecodedOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodedOperators.swift; sourceTree = "<group>"; };
EAD9FACF19D0EAB50031E006 /* Argo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Argo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EAD9FAD319D0EAB50031E006 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
EAD9FADA19D0EAB60031E006 /* ArgoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ArgoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -185,6 +200,8 @@
EAD9FB1719D49A3E0031E006 /* TestModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestModel.swift; path = ../../../Argo/ArgoTests/Models/TestModel.swift; sourceTree = "<group>"; };
EAD9FB1919D4B23F0031E006 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSON.swift; path = ../../../Argo/Argo/Globals/JSON.swift; sourceTree = "<group>"; };
EADADCB11A5DB6F600B180EC /* EquatableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EquatableTests.swift; sourceTree = "<group>"; };
EAEE2F4B1A9FCC9F00DA2846 /* Box.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Box.framework; sourceTree = "<group>"; };
EAEE2F4D1A9FCCAA00DA2846 /* Box.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Box.framework; sourceTree = "<group>"; };
F802D4C21A5EE061005E236C /* NSURL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURL.swift; sourceTree = "<group>"; };
F802D4C51A5EE2D5005E236C /* url.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = url.json; sourceTree = "<group>"; };
F874B7E91A66BF52004CCE5E /* root_array.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = root_array.json; sourceTree = "<group>"; };
Expand All @@ -205,6 +222,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EAEE2F4C1A9FCC9F00DA2846 /* Box.framework in Frameworks */,
F87D9D8A1A92676100C8AF1D /* Runes.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -222,6 +240,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EAEE2F4E1A9FCCAA00DA2846 /* Box.framework in Frameworks */,
F87D9D8B1A92676400C8AF1D /* Runes.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -319,6 +338,7 @@
children = (
EAD9FAEA19D0F6930031E006 /* Operators.swift */,
EAD9FAF519D0F7900031E006 /* JSONOperators.swift */,
EAC59A0E1A9F74C500BEB5CC /* DecodedOperators.swift */,
);
path = Operators;
sourceTree = "<group>";
Expand All @@ -331,6 +351,8 @@
F8E33FA11A51DE020025A6E5 /* curry.swift */,
F8CBE6621A64508200316FBC /* sequence.swift */,
F8A1ACF71A9CE15200118B29 /* flatReduce.swift */,
EA8148B51A9E476D00683AFF /* Decoded.swift */,
EA8148B81A9E573300683AFF /* decode.swift */,
);
path = Globals;
sourceTree = "<group>";
Expand Down Expand Up @@ -402,6 +424,7 @@
F87D9D841A92675400C8AF1D /* iOS */ = {
isa = PBXGroup;
children = (
EAEE2F4B1A9FCC9F00DA2846 /* Box.framework */,
F87D9D851A92675400C8AF1D /* Runes.framework */,
);
name = iOS;
Expand All @@ -411,6 +434,7 @@
F87D9D861A92675400C8AF1D /* Mac */ = {
isa = PBXGroup;
children = (
EAEE2F4D1A9FCCAA00DA2846 /* Box.framework */,
F87D9D871A92675400C8AF1D /* Runes.framework */,
);
name = Mac;
Expand Down Expand Up @@ -648,12 +672,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EAC59A0F1A9F74C500BEB5CC /* DecodedOperators.swift in Sources */,
F8CBE6671A64521000316FBC /* Dictionary.swift in Sources */,
EA8148B91A9E573300683AFF /* decode.swift in Sources */,
F8CBE6631A64508200316FBC /* sequence.swift in Sources */,
EAD9FB1A19D4B23F0031E006 /* JSON.swift in Sources */,
EAD9FAEB19D0F6930031E006 /* Operators.swift in Sources */,
EAD9FAF619D0F7900031E006 /* JSONOperators.swift in Sources */,
F8A1ACF81A9CE15200118B29 /* flatReduce.swift in Sources */,
EA8148B61A9E476D00683AFF /* Decoded.swift in Sources */,
EAD9FAF919D0F7CA0031E006 /* JSONDecodable.swift in Sources */,
F8E33FA21A51DE020025A6E5 /* curry.swift in Sources */,
EAD9FAF419D0F74C0031E006 /* StandardTypes.swift in Sources */,
Expand Down Expand Up @@ -685,12 +712,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EAC59A101A9F74C500BEB5CC /* DecodedOperators.swift in Sources */,
F89335721A4CE93600B88685 /* StandardTypes.swift in Sources */,
EA8148BA1A9E573300683AFF /* decode.swift in Sources */,
F8CBE6681A64526300316FBC /* Dictionary.swift in Sources */,
F8CBE6641A6450F200316FBC /* sequence.swift in Sources */,
F862E0AA1A519D360093B028 /* JSON.swift in Sources */,
F89335741A4CE93600B88685 /* Operators.swift in Sources */,
F8A1ACF91A9CE34500118B29 /* flatReduce.swift in Sources */,
EA8148B71A9E476D00683AFF /* Decoded.swift in Sources */,
F89335701A4CE92D00B88685 /* JSONDecodable.swift in Sources */,
F89335761A4CE93600B88685 /* JSONOperators.swift in Sources */,
F8E33FA31A51DE510025A6E5 /* curry.swift in Sources */,
Expand Down Expand Up @@ -935,6 +965,7 @@
F89335681A4CE83000B88685 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
Expand Down Expand Up @@ -962,6 +993,7 @@
F89335691A4CE83000B88685 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
Expand Down
12 changes: 12 additions & 0 deletions Argo/Extensions/Dictionary.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Runes

// pure merge for Dictionaries
func +<T, V>(var lhs: [T: V], rhs: [T: V]) -> [T: V] {
var dict = lhs
Expand All @@ -8,3 +10,13 @@ func +<T, V>(var lhs: [T: V], rhs: [T: V]) -> [T: V] {

return dict
}

extension Dictionary {
func map<A>(f: Value -> A) -> [Key: A] {
return reduce(self, [:]) { $0 + [$1.0: f($1.1)] }
}
}

func <^><A, B, C>(f: A -> B, a: [C: A]) -> [C: B] {
return a.map(f)
}
22 changes: 22 additions & 0 deletions Argo/Globals/Decoded.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Box

public enum Decoded<T> {
case Success(Box<T>)
case TypeMismatch(String)
case MissingKey(String)

public var value: T? {
switch self {
case let .Success(box): return box.value
default: return .None
}
}

public static func optional<A>(p: Decoded<A>) -> Decoded<A?> {
switch p {
case let .Success(box): return .Success(Box(.Some(box.value)))
case let .MissingKey(string): return .Success(Box(.None))
case let .TypeMismatch(string): return .TypeMismatch(string)
}
}
}
4 changes: 2 additions & 2 deletions Argo/Globals/JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public extension JSON {
}

extension JSON: JSONDecodable {
public static func decode(j: JSON) -> JSON? {
return j
public static func decode(j: JSON) -> Decoded<JSON> {
return pure(j)
}
}

Expand Down
45 changes: 28 additions & 17 deletions Argo/Globals/StandardTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,64 @@ import Foundation
import Runes

extension String: JSONDecodable {
public static func decode(j: JSON) -> String? {
public static func decode(j: JSON) -> Decoded<String> {
switch j {
case let .String(s): return s
default: return .None
case let .String(s): return pure(s)
default: return typeMismatch("String", j)
}
}
}

extension Int: JSONDecodable {
public static func decode(j: JSON) -> Int? {
public static func decode(j: JSON) -> Decoded<Int> {
switch j {
case let .Number(n): return n as Int
default: return .None
case let .Number(n): return pure(n as Int)
default: return typeMismatch("Int", j)
}
}
}

extension Double: JSONDecodable {
public static func decode(j: JSON) -> Double? {
public static func decode(j: JSON) -> Decoded<Double> {
switch j {
case let .Number(n): return n as Double
default: return .None
case let .Number(n): return pure(n as Double)
default: return typeMismatch("Double", j)
}
}
}

extension Bool: JSONDecodable {
public static func decode(j: JSON) -> Bool? {
public static func decode(j: JSON) -> Decoded<Bool> {
switch j {
case let .Number(n): return n as Bool
default: return .None
case let .Number(n): return pure(n as Bool)
default: return typeMismatch("Bool", j)
}
}
}

extension Float: JSONDecodable {
public static func decode(j: JSON) -> Float? {
public static func decode(j: JSON) -> Decoded<Float> {
switch j {
case let .Number(n): return n as Float
default: return .None
case let .Number(n): return pure(n as Float)
default: return typeMismatch("Float", j)
}
}
}

public func decodeArray<A where A: JSONDecodable, A == A.DecodedType>(value: JSON) -> [A]? {
public func decodeArray<A where A: JSONDecodable, A == A.DecodedType>(value: JSON) -> Decoded<[A]> {
switch value {
case let .Array(a): return sequence(A.decode <^> a)
default: return .None
default: return typeMismatch("Array", value)
}
}

public func decodeObject<A where A: JSONDecodable, A == A.DecodedType>(value: JSON) -> Decoded<[String: A]> {
switch value {
case let .Object(o): return sequence(A.decode <^> o)
default: return typeMismatch("Object", value)
}
}

private func typeMismatch<T>(expectedType: String, object: JSON) -> Decoded<T> {
return .TypeMismatch("\(object) is not a \(expectedType)")
}
15 changes: 15 additions & 0 deletions Argo/Globals/decode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
public func decode<T: JSONDecodable where T == T.DecodedType>(object: AnyObject) -> T? {
return decode(object).value
}

public func decode<T: JSONDecodable where T == T.DecodedType>(object: AnyObject) -> [T]? {
return decode(object).value
}

public func decode<T: JSONDecodable where T == T.DecodedType>(object: AnyObject) -> Decoded<T> {
return T.decode(JSON.parse(object))
}

public func decode<T: JSONDecodable where T == T.DecodedType>(object: AnyObject) -> Decoded<[T]> {
return decodeArray(JSON.parse(object))
}
4 changes: 2 additions & 2 deletions Argo/Globals/flatReduce.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Runes

func flatReduce<S: SequenceType, U>(sequence: S, initial: U, combine: (U, S.Generator.Element) -> U?) -> U? {
return reduce(sequence, initial) { accum, x in
func flatReduce<S: SequenceType, U>(sequence: S, initial: U, combine: (U, S.Generator.Element) -> Decoded<U>) -> Decoded<U> {
return reduce(sequence, pure(initial)) { accum, x in
accum >>- { combine($0, x) }
}
}
10 changes: 8 additions & 2 deletions Argo/Globals/sequence.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import Runes

func sequence<T>(xs: [T?]) -> [T]? {
return reduce(xs, []) { accum, elem in
func sequence<T>(xs: [Decoded<T>]) -> Decoded<[T]> {
return reduce(xs, pure([])) { accum, elem in
return curry(+) <^> accum <*> (pure <^> elem)
}
}

func sequence<T>(xs: [String: Decoded<T>]) -> Decoded<[String: T]> {
return reduce(xs, pure([:])) { accum, elem in
return curry(+) <^> accum <*> ({ [elem.0: $0] } <^> elem.1)
}
}
30 changes: 30 additions & 0 deletions Argo/Operators/DecodedOperators.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Runes
import Box

public func >>-<A, B>(a: Decoded<A>, f: A -> Decoded<B>) -> Decoded<B> {
switch a {
case let .Success(box): return f(box.value)
case let .MissingKey(string): return .MissingKey(string)
case let .TypeMismatch(string): return .TypeMismatch(string)
}
}

public func <^><A, B>(f: A -> B, a: Decoded<A>) -> Decoded<B> {
switch a {
case let .Success(box): return .Success(Box(f(box.value)))
case let .MissingKey(string): return .MissingKey(string)
case let .TypeMismatch(string): return .TypeMismatch(string)
}
}

public func <*><A, B>(f: Decoded<A -> B>, a: Decoded<A>) -> Decoded<B> {
switch f {
case let .Success(box): return box.value <^> a
case let .MissingKey(string): return .MissingKey(string)
case let .TypeMismatch(string): return .TypeMismatch(string)
}
}

public func pure<A>(a: A) -> Decoded<A> {
return .Success(Box(a))
}
Loading

0 comments on commit 9a2f1b6

Please sign in to comment.