@@ -46,79 +46,6 @@ final public class BSONSerialization {
4646
4747 }
4848
49- /** The BSON Serialization errors enum. */
50- public enum BSONSerializationError : Error {
51- /** The given data/stream contains too few bytes to be a valid bson doc. */
52- case dataTooSmall
53- /** The given data size is not the one declared by the bson doc. */
54- case dataLengthDoNotMatch
55-
56- /** The length of the bson doc is invalid. */
57- case invalidLength
58- /**
59- An invalid element was found.
60- The element is given in argument to this enum case. */
61- case invalidElementType( UInt8 )
62-
63- /** Found an invalid bool value (given in arg). */
64- case invalidBooleanValue( UInt8 )
65-
66- /**
67- Asked to read an invalid string for the required encoding.
68- The original data that has been tried to be parsed is given in arg of this error. */
69- case invalidString( Data )
70- /**
71- Invalid end of BSON string found.
72- Expected `NULL` (`0`), but found the bytes given in argument to this enum case (if `nil`, no data can be read after the string). */
73- case invalidEndOfString( UInt8 ? )
74-
75- /**
76- An invalid key was found in an array:
77- Keys must be integers, sorted in ascending order from `0` to `n-1` (where `n = number of elements in the array`).
78-
79- - Note: Not so sure the increments from one element to the next should necessarily be of one…
80- The doc is pretty vague on the subject.
81- It says:
82- ```text
83- […] with integer values for the keys, starting with 0 and continuing sequentially.
84- […] The keys must be in ascending numerical order.
85- ``` */
86- case invalidArrayKey( currentKey: String , previousKey: String ? )
87-
88- /** Found an invalid regular expression options value (the complete options and the faulty character are given in arg). */
89- case invalidRegularExpressionOptions( options: String , invalidCharacter: Character )
90- /** Found an invalid regular expression value (the regular expression and the parsing error are given in arg). */
91- case invalidRegularExpression( pattern: String , error: Error )
92-
93- /**
94- The JS with scope element gives the raw data length in its definition.
95- If the given length does not match the decoded length, this error is thrown.
96- The expected and actual length are given in the error. */
97- case invalidJSWithScopeLength( expected: Int , actual: Int )
98-
99- /** An error occurred writing the stream. */
100- case cannotWriteToStream( streamError: Error ? )
101-
102- /**
103- An invalid BSON object was given to be serialized.
104- The invalid element is passed in argument to this error. */
105- case invalidBSONObject( invalidElement: Any )
106- /**
107- Tried to serialize an unserializable string (using the C representation).
108- This is due to the fact that the `\0` char can be used in a valid UTF8 string.
109- (Note: the characters `\254` and `\255` can NEVER be used in a valid UTF8 string.
110- Why were they not the separator?)
111-
112- Usually, the BSON strings represented using the C representation are dictionary keys.
113- But they can also be the components of a regexp. */
114- case unserializableCString( String )
115-
116- /** Cannot allocate memory (either with `malloc` or `UnsafePointer.alloc()`). */
117- case cannotAllocateMemory( Int )
118- /** An internal error occurred rendering the serialization impossible. */
119- case internalError
120- }
121-
12249 /**
12350 Serialize the given data into a dictionary with String keys, object values.
12451
@@ -128,9 +55,9 @@ final public class BSONSerialization {
12855 - Returns: The serialized BSON data. */
12956 public class func bsonObject( with data: Data , options opt: ReadingOptions = [ ] ) throws -> BSONDoc {
13057 /* Let’s check whether the length of the data correspond to the length declared in the data. */
131- guard data. count >= 5 else { throw BSONSerializationError . dataTooSmall}
58+ guard data. count >= 5 else { throw Err . dataTooSmall}
13259 let length32 = data. withUnsafeBytes { $0. load ( as: Int32 . self) }
133- guard Int ( length32) == data. count else { throw BSONSerializationError . dataLengthDoNotMatch}
60+ guard Int ( length32) == data. count else { throw Err . dataLengthDoNotMatch}
13461
13562 let bufferedData = DataReader ( data: data)
13663 return try bsonObject ( with: bufferedData, options: opt)
@@ -167,7 +94,7 @@ final public class BSONSerialization {
16794
16895 streamReader. readSizeLimit = initialReadPosition + MemoryLayout< Int32> . size
16996 let length32 : Int32 = try streamReader. readType ( )
170- guard length32 >= 5 else { throw BSONSerializationError . dataTooSmall}
97+ guard length32 >= 5 else { throw Err . dataTooSmall}
17198
17299 let length = Int ( length32)
173100 streamReader. readSizeLimit = initialReadPosition + length
@@ -176,7 +103,7 @@ final public class BSONSerialization {
176103
177104 var isAtEnd = false
178105 while !isAtEnd {
179- guard streamReader. currentReadPosition - initialReadPosition <= length else { throw BSONSerializationError . invalidLength}
106+ guard streamReader. currentReadPosition - initialReadPosition <= length else { throw Err . invalidLength}
180107
181108 let currentElementType : UInt8 = try streamReader. readType ( )
182109 guard currentElementType != BSONElementType . endOfDocument. rawValue else {
@@ -195,7 +122,7 @@ final public class BSONSerialization {
195122 switch valAsInt8 {
196123 case 1 : try decodeCallback ( key, true ) ; ret [ key] = true
197124 case 0 : try decodeCallback ( key, false ) ; ret [ key] = false
198- default : throw BSONSerializationError . invalidBooleanValue ( valAsInt8)
125+ default : throw Err . invalidBooleanValue ( valAsInt8)
199126 }
200127
201128 case . int32Bits? where MemoryLayout< Int> . size == MemoryLayout< Int32> . size:
@@ -247,12 +174,12 @@ final public class BSONSerialization {
247174 case " l " : ( /* Make \w, \W, etc. locale dependent. (Unsupported, or most likely default unremovable behaviour…) */)
248175 case " s " : foundationOptions. insert ( . dotMatchesLineSeparators) /* Dotall mode (`.` matches everything). Not sure if this option is enough. */
249176 case " u " : foundationOptions. insert ( . useUnicodeWordBoundaries) /* Make \w, \W, etc. match unicode. */
250- default : throw BSONSerializationError . invalidRegularExpressionOptions ( options: options, invalidCharacter: c)
177+ default : throw Err . invalidRegularExpressionOptions ( options: options, invalidCharacter: c)
251178 }
252179 }
253180 let val : NSRegularExpression
254181 do { val = try NSRegularExpression ( pattern: pattern, options: foundationOptions) }
255- catch { throw BSONSerializationError . invalidRegularExpression ( pattern: pattern, error: error) }
182+ catch { throw Err . invalidRegularExpression ( pattern: pattern, error: error) }
256183
257184 try decodeCallback ( key, val)
258185 ret [ key] = val
@@ -271,7 +198,7 @@ final public class BSONSerialization {
271198 var val = [ Any? ] ( )
272199 var prevKey : String ? = nil
273200 _ = try bsonObject ( with: streamReader, options: opt, initialReadPosition: streamReader. currentReadPosition, decodeCallback: { subkey, subval in
274- guard String ( val. count) == subkey else { throw BSONSerializationError . invalidArrayKey ( currentKey: subkey, previousKey: prevKey) }
201+ guard String ( val. count) == subkey else { throw Err . invalidArrayKey ( currentKey: subkey, previousKey: prevKey) }
275202 val. append ( subval)
276203 prevKey = subkey
277204 } )
@@ -310,7 +237,7 @@ final public class BSONSerialization {
310237 let valSize : Int32 = try streamReader. readType ( )
311238 let jsCode = try streamReader. readBSONString ( encoding: . utf8)
312239 let scope = try bsonObject ( with: streamReader, options: opt, initialReadPosition: streamReader. currentReadPosition)
313- guard streamReader. currentReadPosition - valStartPosition == Int ( valSize) else { throw BSONSerializationError . invalidJSWithScopeLength ( expected: Int ( valSize) , actual: streamReader. currentReadPosition - valStartPosition) }
240+ guard streamReader. currentReadPosition - valStartPosition == Int ( valSize) else { throw Err . invalidJSWithScopeLength ( expected: Int ( valSize) , actual: streamReader. currentReadPosition - valStartPosition) }
314241 let val = JavascriptWithScope ( javascript: jsCode, scope: scope)
315242 try decodeCallback ( key, val)
316243 ret [ key] = val
@@ -341,11 +268,11 @@ final public class BSONSerialization {
341268 try decodeCallback ( key, val)
342269 ret [ key] = val
343270
344- case nil : throw BSONSerializationError . invalidElementType ( currentElementType)
271+ case nil : throw Err . invalidElementType ( currentElementType)
345272 case . endOfDocument? : fatalError ( ) /* Guarded before the switch */
346273 }
347274 }
348- guard streamReader. currentReadPosition - initialReadPosition == length else { throw BSONSerializationError . invalidLength}
275+ guard streamReader. currentReadPosition - initialReadPosition == length else { throw Err . invalidLength}
349276 return ret
350277 }
351278
@@ -362,7 +289,7 @@ final public class BSONSerialization {
362289 } )
363290
364291 guard let nsdata = stream. property ( forKey: Stream . PropertyKey. dataWrittenToMemoryStreamKey) as? NSData else {
365- throw BSONSerializationError . internalError
292+ throw Err . internalError
366293 }
367294
368295 var data = Data ( referencing: nsdata)
@@ -706,7 +633,7 @@ final public class BSONSerialization {
706633 size += 12
707634
708635 case let unknown? :
709- throw BSONSerializationError . invalidBSONObject ( invalidElement: unknown )
636+ throw Err . invalidBSONObject ( invalidElement: unknown )
710637 }
711638
712639 return ( size, subSizes)
@@ -829,20 +756,7 @@ final public class BSONSerialization {
829756
830757 var type = bin. binaryTypeAsInt
831758 size += try write ( value: & type, toStream: stream)
832-
833- /* Writing a 0-length data seems to make next writes to the stream fail. */
834- if bin. data. count > 0 {
835- /* Note: Joe says we can bind the memory (or even assume it’s already bound) to UInt8
836- * because the memory will be immutable in the closure, and thus cannot be aliased.
837- * https://twitter.com/jckarter/status/1142446184700624896 */
838- let written = bin. data. withUnsafeBytes { ( bytes: UnsafeRawBufferPointer ) -> Int in
839- let boundBytes = bytes. bindMemory ( to: UInt8 . self)
840- assert ( bin. data. count == boundBytes. count, " INTERNAL ERROR " )
841- return stream. write ( boundBytes. baseAddress!, maxLength: boundBytes. count)
842- }
843- guard written == bin. data. count else { throw BSONSerializationError . cannotWriteToStream ( streamError: stream. streamError) }
844- size += written
845- }
759+ size += try bin. data. withUnsafeBytes { try stream. write ( dataPtr: $0) }
846760
847761 case var val as MongoObjectId :
848762 size += try write ( elementType: . objectId, toStream: stream)
@@ -886,7 +800,7 @@ final public class BSONSerialization {
886800 size += try write ( value: & bytes, toStream: stream)
887801
888802 case let unknown? :
889- throw BSONSerializationError . invalidBSONObject ( invalidElement: unknown)
803+ throw Err . invalidBSONObject ( invalidElement: unknown)
890804 }
891805
892806 return size
@@ -955,21 +869,10 @@ final public class BSONSerialization {
955869 private class func write( CEncodedString str: String, toStream stream: OutputStream) throws -> Int {
956870 var written = 0
957871
958- /* Apparently writing 0 bytes to the stream will f**ck it up… */
959- if str. count > 0 {
960- /* Let’s get the UTF8 bytes of the string. */
961- let bytes = [ UInt8] ( str. utf8)
962- assert ( bytes. count > 0 , " How on earth a non-empty string has 0 UTF-8 bytes? " )
963- guard !bytes. contains ( 0 ) else { throw BSONSerializationError . unserializableCString ( str) }
964-
965- let curWrite = bytes. withUnsafeBufferPointer { p -> Int in
966- assert ( p. count == bytes. count)
967- return stream. write ( p. baseAddress!, maxLength: p. count)
968- }
969-
970- guard curWrite == bytes. count else { throw BSONSerializationError . cannotWriteToStream ( streamError: stream. streamError) }
971- written += curWrite
972- }
872+ /* Let’s get the UTF8 bytes of the string. */
873+ let bytes = [ UInt8] ( str. utf8)
874+ guard !bytes. contains ( 0 ) else { throw Err . unserializableCString ( str) }
875+ written += try bytes. withUnsafeBufferPointer { try stream. write ( dataPtr: UnsafeRawBufferPointer ( $0) ) }
973876
974877 var zero : Int8 = 0
975878 written += try write ( value: & zero, toStream: stream)
@@ -984,19 +887,9 @@ final public class BSONSerialization {
984887 /* Let’s write the size of the string to the stream. */
985888 written += try write ( value: & strLength, toStream: stream)
986889
987- /* Apparently writing 0 bytes to the stream will f**ck it up… */
988- if str. count > 0 {
989- /* Let’s get the UTF8 bytes of the string. */
990- let bytes = [ UInt8] ( str. utf8)
991- assert ( bytes. count > 0 , " How on earth a non-empty string has 0 UTF-8 bytes? " )
992- let curWrite = bytes. withUnsafeBufferPointer { p -> Int in
993- assert ( p. count == bytes. count)
994- return stream. write ( p. baseAddress!, maxLength: p. count)
995- }
996-
997- guard curWrite == bytes. count else { throw BSONSerializationError . cannotWriteToStream ( streamError: stream. streamError) }
998- written += curWrite
999- }
890+ /* Let’s get the UTF8 bytes of the string. */
891+ let bytes = [ UInt8] ( str. utf8)
892+ written += try bytes. withUnsafeBufferPointer { try stream. write ( dataPtr: UnsafeRawBufferPointer ( $0) ) }
1000893
1001894 var zero : Int8 = 0
1002895 written += try write ( value: & zero, toStream: stream)
@@ -1012,11 +905,7 @@ final public class BSONSerialization {
1012905 /* We cannot use withMemoryRebound because the doc says this method can only be used if the new type have the same size and stride as the original pointer’s type.
1013906 * So instead we have to convert the pointer to a raw pointer and bind the raw pointer’s memory to UInt8. */
1014907 let rawPointer = UnsafeRawPointer ( pointer)
1015- let uint8Pointer = rawPointer. bindMemory ( to: UInt8 . self, capacity: size)
1016- guard stream. write ( uint8Pointer, maxLength: size) == size else {
1017- throw BSONSerializationError . cannotWriteToStream ( streamError: stream. streamError)
1018- }
1019- return size
908+ return try stream. write ( dataPtr: UnsafeRawBufferPointer ( start: rawPointer, count: size) )
1020909 } )
1021910 }
1022911
@@ -1054,7 +943,7 @@ private extension StreamReader {
1054943
1055944 /* This String init fails if the data is invalid for the given encoding. */
1056945 guard let str = String ( data: data, encoding: encoding) else {
1057- throw BSONSerialization . BSONSerializationError . invalidString ( data)
946+ throw Err . invalidString ( data)
1058947 }
1059948
1060949 return str
@@ -1072,13 +961,13 @@ private extension StreamReader {
1072961 let strData = try readData ( size: Int ( stringSize- 1 ) )
1073962 assert ( strData. count == Int ( stringSize- 1 ) )
1074963 guard let str = String ( data: strData, encoding: encoding) else {
1075- throw BSONSerialization . BSONSerializationError . invalidString ( strData)
964+ throw Err . invalidString ( strData)
1076965 }
1077966
1078967 /* Reading the last byte and checking it is indeed 0. */
1079968 try readData ( size: 1 , { null in
1080969 assert ( null. count == 1 )
1081- guard null. first == 0 else { throw BSONSerialization . BSONSerializationError . invalidEndOfString ( null. first) }
970+ guard null. first == 0 else { throw Err . invalidEndOfString ( null. first) }
1082971 } )
1083972
1084973 return str
0 commit comments