Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit 509d5b4

Browse files
authored
Merge pull request #3 from tjanela/feature/stream-decoder
JSONParser that parses from InputStream
2 parents c015c65 + e8bda5b commit 509d5b4

File tree

6 files changed

+795
-7
lines changed

6 files changed

+795
-7
lines changed

MonadicJSON.xcodeproj/project.pbxproj

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
E2305766244B3CE7008A81AB /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2305765244B3CE7008A81AB /* JSONParserStream.swift */; };
11+
E2305767244B3D4F008A81AB /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2305765244B3CE7008A81AB /* JSONParserStream.swift */; };
12+
E2305768244B3D50008A81AB /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2305765244B3CE7008A81AB /* JSONParserStream.swift */; };
13+
E2305769244B3D54008A81AB /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2305765244B3CE7008A81AB /* JSONParserStream.swift */; };
14+
E28845112459B90500C8AF37 /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E288450E2459B8D800C8AF37 /* JSONParserStream.swift */; };
15+
E28845122459B90600C8AF37 /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E288450E2459B8D800C8AF37 /* JSONParserStream.swift */; };
16+
E28845132459B90700C8AF37 /* JSONParserStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E288450E2459B8D800C8AF37 /* JSONParserStream.swift */; };
1017
F81130C7226FEACF00D1D24E /* Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81130C5226FEAA000D1D24E /* Speed.swift */; };
1118
F81130C8226FEAD000D1D24E /* Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81130C5226FEAA000D1D24E /* Speed.swift */; };
1219
F81130C9226FEAD100D1D24E /* Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81130C5226FEAA000D1D24E /* Speed.swift */; };
@@ -107,6 +114,8 @@
107114
/* End PBXCopyFilesBuildPhase section */
108115

109116
/* Begin PBXFileReference section */
117+
E2305765244B3CE7008A81AB /* JSONParserStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONParserStream.swift; sourceTree = "<group>"; };
118+
E288450E2459B8D800C8AF37 /* JSONParserStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONParserStream.swift; sourceTree = "<group>"; };
110119
F81130C5226FEAA000D1D24E /* Speed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Speed.swift; sourceTree = "<group>"; };
111120
F85A3A402267F75100E79C11 /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/Mac/SwiftCheck.framework; sourceTree = "<group>"; };
112121
F85A3A442267F7CD00E79C11 /* JSONParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = "<group>"; };
@@ -232,6 +241,7 @@
232241
F85A6D272266E99600F4581F /* JSON.swift */,
233242
F85A6D292266E99A00F4581F /* JSONDecoder.swift */,
234243
F85A6D2B2266E99E00F4581F /* JSONParser.swift */,
244+
E2305765244B3CE7008A81AB /* JSONParserStream.swift */,
235245
);
236246
path = Sources;
237247
sourceTree = "<group>";
@@ -244,6 +254,7 @@
244254
F8A1D399226EA21600B7E17C /* FreeLiterals.swift */,
245255
F8A1D3A6226EA6F300B7E17C /* FreeFunctions.swift */,
246256
F85A3A442267F7CD00E79C11 /* JSONParser.swift */,
257+
E288450E2459B8D800C8AF37 /* JSONParserStream.swift */,
247258
F81130C5226FEAA000D1D24E /* Speed.swift */,
248259
F8A1D3A2226EA62900B7E17C /* Types.swift */,
249260
);
@@ -421,7 +432,7 @@
421432
isa = PBXProject;
422433
attributes = {
423434
LastSwiftUpdateCheck = 1020;
424-
LastUpgradeCheck = 1020;
435+
LastUpgradeCheck = 1140;
425436
TargetAttributes = {
426437
F85A3A4B22682BCB00E79C11 = {
427438
CreatedOnToolsVersion = 10.2;
@@ -453,6 +464,7 @@
453464
hasScannedForEncodings = 0;
454465
knownRegions = (
455466
en,
467+
Base,
456468
);
457469
mainGroup = F85A6D002266E81200F4581F;
458470
productRefGroup = F85A6D0D2266E84D00F4581F /* Products */;
@@ -529,6 +541,7 @@
529541
files = (
530542
F85A3A6522682C0700E79C11 /* JSON.swift in Sources */,
531543
F85A3A6422682C0400E79C11 /* JSONDecoder.swift in Sources */,
544+
E2305767244B3D4F008A81AB /* JSONParserStream.swift in Sources */,
532545
F85A3A6322682C0200E79C11 /* JSONParser.swift in Sources */,
533546
);
534547
runOnlyForDeploymentPostprocessing = 0;
@@ -541,6 +554,7 @@
541554
F85A3A6622682C0D00E79C11 /* JSONParser.swift in Sources */,
542555
F8A1D3A0226EA50D00B7E17C /* Extensions.swift in Sources */,
543556
F81130C8226FEAD000D1D24E /* Speed.swift in Sources */,
557+
E28845122459B90600C8AF37 /* JSONParserStream.swift in Sources */,
544558
F8A1D39C226EA22700B7E17C /* FreeLiterals.swift in Sources */,
545559
F8A1D3A4226EA62900B7E17C /* Types.swift in Sources */,
546560
);
@@ -552,6 +566,7 @@
552566
files = (
553567
F85A3ABC226834BF00E79C11 /* JSONDecoder.swift in Sources */,
554568
F85A3AB9226834B900E79C11 /* JSONParser.swift in Sources */,
569+
E2305769244B3D54008A81AB /* JSONParserStream.swift in Sources */,
555570
F85A3ABB226834BF00E79C11 /* JSON.swift in Sources */,
556571
);
557572
runOnlyForDeploymentPostprocessing = 0;
@@ -562,6 +577,7 @@
562577
files = (
563578
F85A3ABE226834C000E79C11 /* JSONDecoder.swift in Sources */,
564579
F85A3ABA226834BA00E79C11 /* JSONParser.swift in Sources */,
580+
E2305768244B3D50008A81AB /* JSONParserStream.swift in Sources */,
565581
F85A3ABD226834C000E79C11 /* JSON.swift in Sources */,
566582
);
567583
runOnlyForDeploymentPostprocessing = 0;
@@ -574,6 +590,7 @@
574590
F85A3AB8226834B600E79C11 /* JSONParser.swift in Sources */,
575591
F8A1D3A1226EA50D00B7E17C /* Extensions.swift in Sources */,
576592
F81130C9226FEAD100D1D24E /* Speed.swift in Sources */,
593+
E28845132459B90700C8AF37 /* JSONParserStream.swift in Sources */,
577594
F8A1D39D226EA22800B7E17C /* FreeLiterals.swift in Sources */,
578595
F8A1D3A5226EA62900B7E17C /* Types.swift in Sources */,
579596
);
@@ -585,6 +602,7 @@
585602
files = (
586603
F85A6D2A2266E99A00F4581F /* JSONDecoder.swift in Sources */,
587604
F85A6D282266E99600F4581F /* JSON.swift in Sources */,
605+
E2305766244B3CE7008A81AB /* JSONParserStream.swift in Sources */,
588606
F85A6D2C2266E99E00F4581F /* JSONParser.swift in Sources */,
589607
);
590608
runOnlyForDeploymentPostprocessing = 0;
@@ -597,6 +615,7 @@
597615
F85A3A462267F7D000E79C11 /* JSONParser.swift in Sources */,
598616
F8A1D39F226EA50D00B7E17C /* Extensions.swift in Sources */,
599617
F81130C7226FEACF00D1D24E /* Speed.swift in Sources */,
618+
E28845112459B90500C8AF37 /* JSONParserStream.swift in Sources */,
600619
F8A1D39B226EA22600B7E17C /* FreeLiterals.swift in Sources */,
601620
F8A1D3A3226EA62900B7E17C /* Types.swift in Sources */,
602621
);
@@ -655,7 +674,7 @@
655674
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
656675
CLANG_WARN_UNREACHABLE_CODE = YES;
657676
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
658-
CODE_SIGN_IDENTITY = "iPhone Developer";
677+
CODE_SIGN_IDENTITY = "";
659678
CODE_SIGN_STYLE = Automatic;
660679
COPY_PHASE_STRIP = NO;
661680
CURRENT_PROJECT_VERSION = 1;
@@ -736,7 +755,7 @@
736755
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
737756
CLANG_WARN_UNREACHABLE_CODE = YES;
738757
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
739-
CODE_SIGN_IDENTITY = "iPhone Developer";
758+
CODE_SIGN_IDENTITY = "";
740759
CODE_SIGN_STYLE = Automatic;
741760
COPY_PHASE_STRIP = NO;
742761
CURRENT_PROJECT_VERSION = 1;
@@ -1390,12 +1409,64 @@
13901409
F85A6D052266E81200F4581F /* Debug */ = {
13911410
isa = XCBuildConfiguration;
13921411
buildSettings = {
1412+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
1413+
CLANG_WARN_BOOL_CONVERSION = YES;
1414+
CLANG_WARN_COMMA = YES;
1415+
CLANG_WARN_CONSTANT_CONVERSION = YES;
1416+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
1417+
CLANG_WARN_EMPTY_BODY = YES;
1418+
CLANG_WARN_ENUM_CONVERSION = YES;
1419+
CLANG_WARN_INFINITE_RECURSION = YES;
1420+
CLANG_WARN_INT_CONVERSION = YES;
1421+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
1422+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
1423+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
1424+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
1425+
CLANG_WARN_STRICT_PROTOTYPES = YES;
1426+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
1427+
CLANG_WARN_UNREACHABLE_CODE = YES;
1428+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
1429+
ENABLE_STRICT_OBJC_MSGSEND = YES;
1430+
ENABLE_TESTABILITY = YES;
1431+
GCC_NO_COMMON_BLOCKS = YES;
1432+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
1433+
GCC_WARN_ABOUT_RETURN_TYPE = YES;
1434+
GCC_WARN_UNDECLARED_SELECTOR = YES;
1435+
GCC_WARN_UNINITIALIZED_AUTOS = YES;
1436+
GCC_WARN_UNUSED_FUNCTION = YES;
1437+
GCC_WARN_UNUSED_VARIABLE = YES;
1438+
ONLY_ACTIVE_ARCH = YES;
13931439
};
13941440
name = Debug;
13951441
};
13961442
F85A6D062266E81200F4581F /* Release */ = {
13971443
isa = XCBuildConfiguration;
13981444
buildSettings = {
1445+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
1446+
CLANG_WARN_BOOL_CONVERSION = YES;
1447+
CLANG_WARN_COMMA = YES;
1448+
CLANG_WARN_CONSTANT_CONVERSION = YES;
1449+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
1450+
CLANG_WARN_EMPTY_BODY = YES;
1451+
CLANG_WARN_ENUM_CONVERSION = YES;
1452+
CLANG_WARN_INFINITE_RECURSION = YES;
1453+
CLANG_WARN_INT_CONVERSION = YES;
1454+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
1455+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
1456+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
1457+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
1458+
CLANG_WARN_STRICT_PROTOTYPES = YES;
1459+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
1460+
CLANG_WARN_UNREACHABLE_CODE = YES;
1461+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
1462+
ENABLE_STRICT_OBJC_MSGSEND = YES;
1463+
GCC_NO_COMMON_BLOCKS = YES;
1464+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
1465+
GCC_WARN_ABOUT_RETURN_TYPE = YES;
1466+
GCC_WARN_UNDECLARED_SELECTOR = YES;
1467+
GCC_WARN_UNINITIALIZED_AUTOS = YES;
1468+
GCC_WARN_UNUSED_FUNCTION = YES;
1469+
GCC_WARN_UNUSED_VARIABLE = YES;
13991470
};
14001471
name = Release;
14011472
};

Sources/JSONDecoder.swift

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ open class MonadicJSONDecoder {
9494
let leadingUnderscoreRange = stringKey.startIndex..<firstNonUnderscore
9595
let trailingUnderscoreRange = stringKey.index(after: lastNonUnderscore)..<stringKey.endIndex
9696

97-
var components = stringKey[keyRange].split(separator: "_")
97+
let components = stringKey[keyRange].split(separator: "_")
9898
let joinedString : String
9999
if components.count == 1 {
100100
// No underscores in key, leave the word as is - maybe already camel cased
@@ -153,10 +153,18 @@ open class MonadicJSONDecoder {
153153
keyDecodingStrategy: keyDecodingStrategy,
154154
userInfo: userInfo)
155155
}
156+
157+
let useStream: Bool
156158

157159
// MARK: - Constructing a JSON Decoder
158160
/// Initializes `self` with default strategies.
159-
public init() {}
161+
public init() {
162+
useStream = false
163+
}
164+
165+
public init(useStream: Bool) {
166+
self.useStream = true
167+
}
160168

161169
// MARK: - Decoding Values
162170
/// Decodes a top-level value of the given type from the given JSON representation.
@@ -167,15 +175,44 @@ open class MonadicJSONDecoder {
167175
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid JSON.
168176
/// - throws: An error if any value throws an error during decoding.
169177
open func decode<T : Decodable>(_ type: T.Type, from data: Data) throws -> T {
170-
switch JSONParser.parse(data: data) {
178+
if useStream {
179+
let stream = InputStream(data: data)
180+
stream.open()
181+
defer { stream.close() }
182+
return try decode(type, from: stream)
183+
} else {
184+
switch JSONParser.parse(data: data) {
185+
case let .failure(error):
186+
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: error))
187+
case let .success(topLevel):
188+
let decoder = _JSONDecoder(referencing: topLevel, options: self.options)
189+
guard let value = try decoder.unbox(topLevel, as: type) else {
190+
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: [], debugDescription: "The given data did not contain a top-level value."))
191+
}
192+
193+
return value
194+
}
195+
}
196+
197+
}
198+
199+
// MARK: - Decoding Values
200+
/// Decodes a top-level value of the given type from the given JSON representation.
201+
///
202+
/// - parameter type: The type of the value to decode.
203+
/// - parameter stream: The **open** input stream to decode from.
204+
/// - returns: A value of the requested type.
205+
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid JSON.
206+
/// - throws: An error if any value throws an error during decoding.
207+
open func decode<T : Decodable>(_ type: T.Type, from stream: InputStream) throws -> T {
208+
switch JSONParser.parse(stream: stream) {
171209
case let .failure(error):
172210
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: error))
173211
case let .success(topLevel):
174212
let decoder = _JSONDecoder(referencing: topLevel, options: self.options)
175213
guard let value = try decoder.unbox(topLevel, as: type) else {
176214
throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: [], debugDescription: "The given data did not contain a top-level value."))
177215
}
178-
179216
return value
180217
}
181218
}

0 commit comments

Comments
 (0)