Skip to content

Commit 6aa85be

Browse files
committed
TSCBasic: deprecate <<< operator
Since TSCBasic has become a kitchen sink for multiple types and functions, it's important to be able to selectively import those. It is done by `import struct` and similar statements. Unfortunately, this doesn't work for operators, which means you have to import the whole module when you need access just to a single operator. This inadvertently pollutes the environment of available symbols, which is undesirable. By deprecating the operator and adding a `send(_:)` function on `WritableByteStream` we allow selectively importing this functionality.
1 parent 22c4a91 commit 6aa85be

20 files changed

+230
-195
lines changed

Sources/TSCBasic/DiagnosticsEngine.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,11 @@ public final class DiagnosticsEngine: CustomStringConvertible {
148148

149149
public var description: String {
150150
let stream = BufferedOutputByteStream()
151-
stream <<< "["
151+
stream.send("[")
152152
for diag in diagnostics {
153-
stream <<< diag.description <<< ", "
153+
stream.send(diag.description).send(", ")
154154
}
155-
stream <<< "]"
155+
stream.send("]")
156156
return stream.bytes.description
157157
}
158158
}

Sources/TSCBasic/FileSystem.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ private struct LocalFileSystem: FileSystem {
458458
}
459459
break
460460
}
461-
data <<< tmpBuffer[0..<n]
461+
data.send(tmpBuffer[0..<n])
462462
}
463463

464464
return data.bytes

Sources/TSCBasic/JSON.swift

+17-17
Original file line numberDiff line numberDiff line change
@@ -126,41 +126,41 @@ extension JSON: ByteStreamable {
126126
let shouldIndent = indent != nil
127127
switch self {
128128
case .null:
129-
stream <<< "null"
129+
stream.send("null")
130130
case .bool(let value):
131-
stream <<< Format.asJSON(value)
131+
stream.send(Format.asJSON(value))
132132
case .int(let value):
133-
stream <<< Format.asJSON(value)
133+
stream.send(Format.asJSON(value))
134134
case .double(let value):
135135
// FIXME: What happens for NaN, etc.?
136-
stream <<< Format.asJSON(value)
136+
stream.send(Format.asJSON(value))
137137
case .string(let value):
138-
stream <<< Format.asJSON(value)
138+
stream.send(Format.asJSON(value))
139139
case .array(let contents):
140-
stream <<< "[" <<< (shouldIndent ? "\n" : "")
140+
stream.send("[").send(shouldIndent ? "\n" : "")
141141
for (i, item) in contents.enumerated() {
142-
if i != 0 { stream <<< "," <<< (shouldIndent ? "\n" : " ") }
143-
stream <<< indentStreamable(offset: 2)
142+
if i != 0 { stream.send(",").send(shouldIndent ? "\n" : " ") }
143+
stream.send(indentStreamable(offset: 2))
144144
item.write(to: stream, indent: indent.flatMap({ $0 + 2 }))
145145
}
146-
stream <<< (shouldIndent ? "\n" : "") <<< indentStreamable() <<< "]"
146+
stream.send(shouldIndent ? "\n" : "").send(indentStreamable()).send("]")
147147
case .dictionary(let contents):
148148
// We always output in a deterministic order.
149-
stream <<< "{" <<< (shouldIndent ? "\n" : "")
149+
stream.send("{").send(shouldIndent ? "\n" : "")
150150
for (i, key) in contents.keys.sorted().enumerated() {
151-
if i != 0 { stream <<< "," <<< (shouldIndent ? "\n" : " ") }
152-
stream <<< indentStreamable(offset: 2) <<< Format.asJSON(key) <<< ": "
151+
if i != 0 { stream.send(",").send(shouldIndent ? "\n" : " ") }
152+
stream.send(indentStreamable(offset: 2)).send(Format.asJSON(key)).send(": ")
153153
contents[key]!.write(to: stream, indent: indent.flatMap({ $0 + 2 }))
154154
}
155-
stream <<< (shouldIndent ? "\n" : "") <<< indentStreamable() <<< "}"
155+
stream.send(shouldIndent ? "\n" : "").send(indentStreamable()).send("}")
156156
case .orderedDictionary(let contents):
157-
stream <<< "{" <<< (shouldIndent ? "\n" : "")
157+
stream.send("{").send(shouldIndent ? "\n" : "")
158158
for (i, item) in contents.enumerated() {
159-
if i != 0 { stream <<< "," <<< (shouldIndent ? "\n" : " ") }
160-
stream <<< indentStreamable(offset: 2) <<< Format.asJSON(item.key) <<< ": "
159+
if i != 0 { stream.send(",").send(shouldIndent ? "\n" : " ") }
160+
stream.send(indentStreamable(offset: 2)).send(Format.asJSON(item.key)).send(": ")
161161
item.value.write(to: stream, indent: indent.flatMap({ $0 + 2 }))
162162
}
163-
stream <<< (shouldIndent ? "\n" : "") <<< indentStreamable() <<< "}"
163+
stream.send(shouldIndent ? "\n" : "").send(indentStreamable()).send("}")
164164
}
165165
}
166166
}

Sources/TSCBasic/Process.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ public final class Process {
389389
outputRedirection: outputRedirection,
390390
startNewProcessGroup: startNewProcessGroup,
391391
loggingHandler: verbose ? { message in
392-
stdoutStream <<< message <<< "\n"
392+
stdoutStream.send(message).send("\n")
393393
stdoutStream.flush()
394394
} : nil
395395
)
@@ -1276,13 +1276,13 @@ extension ProcessResult.Error: CustomStringConvertible {
12761276
let stream = BufferedOutputByteStream()
12771277
switch result.exitStatus {
12781278
case .terminated(let code):
1279-
stream <<< "terminated(\(code)): "
1279+
stream.send("terminated(\(code)): ")
12801280
#if os(Windows)
12811281
case .abnormal(let exception):
1282-
stream <<< "abnormal(\(exception)): "
1282+
stream.send("abnormal(\(exception)): ")
12831283
#else
12841284
case .signalled(let signal):
1285-
stream <<< "signalled(\(signal)): "
1285+
stream.send("signalled(\(signal)): ")
12861286
#endif
12871287
}
12881288

@@ -1292,15 +1292,15 @@ extension ProcessResult.Error: CustomStringConvertible {
12921292
if args.first == "sandbox-exec", args.count > 3 {
12931293
args = args.suffix(from: 3).map({$0})
12941294
}
1295-
stream <<< args.map({ $0.spm_shellEscaped() }).joined(separator: " ")
1295+
stream.send(args.map({ $0.spm_shellEscaped() }).joined(separator: " "))
12961296

12971297
// Include the output, if present.
12981298
if let output = try? result.utf8Output() + result.utf8stderrOutput() {
12991299
// We indent the output to keep it visually separated from everything else.
13001300
let indentation = " "
1301-
stream <<< " output:\n" <<< indentation <<< output.replacingOccurrences(of: "\n", with: "\n" + indentation)
1301+
stream.send(" output:\n").send(indentation).send(output.replacingOccurrences(of: "\n", with: "\n" + indentation))
13021302
if !output.hasSuffix("\n") {
1303-
stream <<< "\n"
1303+
stream.send("\n")
13041304
}
13051305
}
13061306

@@ -1333,7 +1333,7 @@ extension FileHandle: WritableByteStream {
13331333
extension Process {
13341334
@available(*, deprecated)
13351335
fileprivate static func logToStdout(_ message: String) {
1336-
stdoutStream <<< message <<< "\n"
1336+
stdoutStream.send(message).send("\n")
13371337
stdoutStream.flush()
13381338
}
13391339
}

Sources/TSCBasic/TerminalController.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,13 @@ public final class TerminalController {
166166

167167
/// Clears the current line and moves the cursor to beginning of the line..
168168
public func clearLine() {
169-
stream <<< clearLineString <<< "\r"
169+
stream.send(clearLineString).send("\r")
170170
flush()
171171
}
172172

173173
/// Moves the cursor y columns up.
174174
public func moveCursor(up: Int) {
175-
stream <<< "\u{001B}[\(up)A"
175+
stream.send("\u{001B}[\(up)A")
176176
flush()
177177
}
178178

@@ -184,7 +184,7 @@ public final class TerminalController {
184184

185185
/// Inserts a new line character into the stream.
186186
public func endLine() {
187-
stream <<< "\n"
187+
stream.send("\n")
188188
flush()
189189
}
190190

@@ -198,9 +198,9 @@ public final class TerminalController {
198198
private func writeWrapped(_ string: String, inColor color: Color, bold: Bool = false, stream: WritableByteStream) {
199199
// Don't wrap if string is empty or color is no color.
200200
guard !string.isEmpty && color != .noColor else {
201-
stream <<< string
201+
stream.send(string)
202202
return
203203
}
204-
stream <<< color.string <<< (bold ? boldString : "") <<< string <<< resetString
204+
stream.send(color.string).send(bold ? boldString : "").send(string).send(resetString)
205205
}
206206
}

Sources/TSCBasic/WritableByteStream.swift

+59-26
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ public protocol ByteStreamable {
2727
/// different output destinations, e.g., a file or an in memory buffer. This is
2828
/// loosely modeled on LLVM's llvm::raw_ostream class.
2929
///
30-
/// The stream is generally used in conjunction with the custom streaming
31-
/// operator '<<<'. For example:
30+
/// The stream is generally used in conjunction with the `appending` function.
31+
/// For example:
3232
///
3333
/// let stream = BufferedOutputByteStream()
34-
/// stream <<< "Hello, world!"
34+
/// stream.appending("Hello, world!")
3535
///
3636
/// would write the UTF8 encoding of "Hello, world!" to the stream.
3737
///
3838
/// The stream accepts a number of custom formatting operators which are defined
3939
/// in the `Format` struct (used for namespacing purposes). For example:
4040
///
4141
/// let items = ["hello", "world"]
42-
/// stream <<< Format.asSeparatedList(items, separator: " ")
42+
/// stream.appending(Format.asSeparatedList(items, separator: " "))
4343
///
4444
/// would write each item in the list to the stream, separating them with a
4545
/// space.
@@ -137,6 +137,34 @@ extension WritableByteStream {
137137
}
138138
}
139139
}
140+
141+
// MARK: helpers that return `self`
142+
143+
// FIXME: This override shouldn't be necesary but removing it causes a 30% performance regression. This problem is
144+
// tracked by the following bug: https://bugs.swift.org/browse/SR-8535
145+
@discardableResult
146+
public func send(_ value: ArraySlice<UInt8>) -> WritableByteStream {
147+
value.write(to: self)
148+
return self
149+
}
150+
151+
@discardableResult
152+
public func send(_ value: ByteStreamable) -> WritableByteStream {
153+
value.write(to: self)
154+
return self
155+
}
156+
157+
@discardableResult
158+
public func send(_ value: CustomStringConvertible) -> WritableByteStream {
159+
value.description.write(to: self)
160+
return self
161+
}
162+
163+
@discardableResult
164+
public func send(_ value: ByteStreamable & CustomStringConvertible) -> WritableByteStream {
165+
value.write(to: self)
166+
return self
167+
}
140168
}
141169

142170
/// The `WritableByteStream` base class.
@@ -366,24 +394,29 @@ precedencegroup StreamingPrecedence {
366394

367395
// FIXME: This override shouldn't be necesary but removing it causes a 30% performance regression. This problem is
368396
// tracked by the following bug: https://bugs.swift.org/browse/SR-8535
397+
398+
@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead")
369399
@discardableResult
370400
public func <<< (stream: WritableByteStream, value: ArraySlice<UInt8>) -> WritableByteStream {
371401
value.write(to: stream)
372402
return stream
373403
}
374404

405+
@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead")
375406
@discardableResult
376407
public func <<< (stream: WritableByteStream, value: ByteStreamable) -> WritableByteStream {
377408
value.write(to: stream)
378409
return stream
379410
}
380411

412+
@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead")
381413
@discardableResult
382414
public func <<< (stream: WritableByteStream, value: CustomStringConvertible) -> WritableByteStream {
383415
value.description.write(to: stream)
384416
return stream
385417
}
386418

419+
@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead")
387420
@discardableResult
388421
public func <<< (stream: WritableByteStream, value: ByteStreamable & CustomStringConvertible) -> WritableByteStream {
389422
value.write(to: stream)
@@ -450,7 +483,7 @@ public struct Format {
450483
let value: Bool
451484

452485
func write(to stream: WritableByteStream) {
453-
stream <<< (value ? "true" : "false")
486+
stream.send(value ? "true" : "false")
454487
}
455488
}
456489

@@ -463,7 +496,7 @@ public struct Format {
463496

464497
func write(to stream: WritableByteStream) {
465498
// FIXME: Diagnose integers which cannot be represented in JSON.
466-
stream <<< value.description
499+
stream.send(value.description)
467500
}
468501
}
469502

@@ -478,7 +511,7 @@ public struct Format {
478511
// FIXME: What should we do about NaN, etc.?
479512
//
480513
// FIXME: Is Double.debugDescription the best representation?
481-
stream <<< value.debugDescription
514+
stream.send(value.debugDescription)
482515
}
483516
}
484517

@@ -494,9 +527,9 @@ public struct Format {
494527
let value: String
495528

496529
func write(to stream: WritableByteStream) {
497-
stream <<< UInt8(ascii: "\"")
530+
stream.send(UInt8(ascii: "\""))
498531
stream.writeJSONEscaped(value)
499-
stream <<< UInt8(ascii: "\"")
532+
stream.send(UInt8(ascii: "\""))
500533
}
501534
}
502535

@@ -514,12 +547,12 @@ public struct Format {
514547
let items: [String]
515548

516549
func write(to stream: WritableByteStream) {
517-
stream <<< UInt8(ascii: "[")
550+
stream.send(UInt8(ascii: "["))
518551
for (i, item) in items.enumerated() {
519-
if i != 0 { stream <<< "," }
520-
stream <<< Format.asJSON(item)
552+
if i != 0 { stream.send(",") }
553+
stream.send(Format.asJSON(item))
521554
}
522-
stream <<< UInt8(ascii: "]")
555+
stream.send(UInt8(ascii: "]"))
523556
}
524557
}
525558

@@ -531,12 +564,12 @@ public struct Format {
531564
let items: [String: String]
532565

533566
func write(to stream: WritableByteStream) {
534-
stream <<< UInt8(ascii: "{")
567+
stream.send(UInt8(ascii: "{"))
535568
for (offset: i, element: (key: key, value: value)) in items.enumerated() {
536-
if i != 0 { stream <<< "," }
537-
stream <<< Format.asJSON(key) <<< ":" <<< Format.asJSON(value)
569+
if i != 0 { stream.send(",") }
570+
stream.send(Format.asJSON(key)).send(":").send(Format.asJSON(value))
538571
}
539-
stream <<< UInt8(ascii: "}")
572+
stream.send(UInt8(ascii: "}"))
540573
}
541574
}
542575

@@ -551,12 +584,12 @@ public struct Format {
551584
let transform: (T) -> String
552585

553586
func write(to stream: WritableByteStream) {
554-
stream <<< UInt8(ascii: "[")
587+
stream.send(UInt8(ascii: "["))
555588
for (i, item) in items.enumerated() {
556-
if i != 0 { stream <<< "," }
557-
stream <<< Format.asJSON(transform(item))
589+
if i != 0 { stream.send(",") }
590+
stream.send(Format.asJSON(transform(item)))
558591
}
559-
stream <<< UInt8(ascii: "]")
592+
stream.send(UInt8(ascii: "]"))
560593
}
561594
}
562595

@@ -572,10 +605,10 @@ public struct Format {
572605
for (i, item) in items.enumerated() {
573606
// Add the separator, if necessary.
574607
if i != 0 {
575-
stream <<< separator
608+
stream.send(separator)
576609
}
577610

578-
stream <<< item
611+
stream.send(item)
579612
}
580613
}
581614
}
@@ -596,8 +629,8 @@ public struct Format {
596629

597630
func write(to stream: WritableByteStream) {
598631
for (i, item) in items.enumerated() {
599-
if i != 0 { stream <<< separator }
600-
stream <<< transform(item)
632+
if i != 0 { stream.send(separator) }
633+
stream.send(transform(item))
601634
}
602635
}
603636
}
@@ -617,7 +650,7 @@ public struct Format {
617650

618651
func write(to stream: WritableByteStream) {
619652
for _ in 0..<count {
620-
stream <<< string
653+
stream.send(string)
621654
}
622655
}
623656
}

0 commit comments

Comments
 (0)