-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathByteString.swift
126 lines (109 loc) · 4.28 KB
/
ByteString.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
/// A `ByteString` represents a sequence of bytes.
///
/// This struct provides useful operations for working with buffers of
/// bytes. Conceptually it is just a contiguous array of bytes (UInt8), but it
/// contains methods and default behavor suitable for common operations done
/// using bytes strings.
///
/// This struct *is not* intended to be used for significant mutation of byte
/// strings, we wish to retain the flexibility to micro-optimize the memory
/// allocation of the storage (for example, by inlining the storage for small
/// strings or and by eliminating wasted space in growable arrays). For
/// construction of byte arrays, clients should use the `OutputByteStream` class
/// and then convert to a `ByteString` when complete.
public struct ByteString: ExpressibleByArrayLiteral, Hashable {
/// The buffer contents.
fileprivate var _bytes: [UInt8]
/// Create an empty byte string.
public init() {
_bytes = []
}
/// Create a byte string from a byte array literal.
public init(arrayLiteral contents: UInt8...) {
_bytes = contents
}
/// Create a byte string from an array of bytes.
public init(_ contents: [UInt8]) {
_bytes = contents
}
/// Create a byte string from an byte buffer.
public init<S: Sequence> (_ contents: S) where S.Iterator.Element == UInt8 {
_bytes = [UInt8](contents)
}
/// Create a byte string from the UTF8 encoding of a string.
public init(encodingAsUTF8 string: String) {
_bytes = [UInt8](string.utf8)
}
/// Access the byte string contents as an array.
public var contents: [UInt8] {
return _bytes
}
/// Return the byte string size.
public var count: Int {
return _bytes.count
}
/// Return the string decoded as a UTF8 sequence, if possible.
public var asString: String? {
// FIXME: This is very inefficient, we need a way to pass a buffer. It
// is also wrong if the string contains embedded '\0' characters.
let tmp = _bytes + [UInt8(0)]
return tmp.withUnsafeBufferPointer { ptr in
return String(validatingUTF8: unsafeBitCast(ptr.baseAddress, to: UnsafePointer<CChar>.self))
}
}
/// Return the string decoded as a UTF8 sequence, substituting replacement
/// characters for ill-formed UTF8 sequences.
public var asReadableString: String {
// FIXME: This is very inefficient, we need a way to pass a buffer. It
// is also wrong if the string contains embedded '\0' characters.
let tmp = _bytes + [UInt8(0)]
return tmp.withUnsafeBufferPointer { ptr in
return String(cString: unsafeBitCast(ptr.baseAddress, to: UnsafePointer<CChar>.self))
}
}
}
/// Conform to CustomStringConvertible.
extension ByteString: CustomStringConvertible {
public var description: String {
// For now, default to the "readable string" representation.
return "<ByteString:\"\(asReadableString)\">"
}
}
#if !swift(>=4.2)
extension ByteString {
public var hashValue: Int {
var result = contents.count
for byte in contents {
result = result &* 31 &+ Int(byte)
}
return result
}
}
#endif
/// ByteStreamable conformance for a ByteString.
//extension ByteString: ByteStreamable {
// public func write(to stream: OutputByteStream) {
// stream.write(_bytes)
// }
//}
/// StringLiteralConvertable conformance for a ByteString.
extension ByteString: ExpressibleByStringLiteral {
public typealias UnicodeScalarLiteralType = StringLiteralType
public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType
public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
_bytes = [UInt8](value.utf8)
}
public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
_bytes = [UInt8](value.utf8)
}
public init(stringLiteral value: StringLiteralType) {
_bytes = [UInt8](value.utf8)
}
}