Skip to content

TSCBasic: deprecate <<< operator #413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Sources/TSCBasic/DiagnosticsEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ public final class DiagnosticsEngine: CustomStringConvertible {

public var description: String {
let stream = BufferedOutputByteStream()
stream <<< "["
stream.send("[")
for diag in diagnostics {
stream <<< diag.description <<< ", "
stream.send(diag.description).send(", ")
}
stream <<< "]"
stream.send("]")
return stream.bytes.description
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/TSCBasic/FileSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ private struct LocalFileSystem: FileSystem {
}
break
}
data <<< tmpBuffer[0..<n]
data.send(tmpBuffer[0..<n])
}

return data.bytes
Expand Down
34 changes: 17 additions & 17 deletions Sources/TSCBasic/JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,41 +126,41 @@ extension JSON: ByteStreamable {
let shouldIndent = indent != nil
switch self {
case .null:
stream <<< "null"
stream.send("null")
case .bool(let value):
stream <<< Format.asJSON(value)
stream.send(Format.asJSON(value))
case .int(let value):
stream <<< Format.asJSON(value)
stream.send(Format.asJSON(value))
case .double(let value):
// FIXME: What happens for NaN, etc.?
stream <<< Format.asJSON(value)
stream.send(Format.asJSON(value))
case .string(let value):
stream <<< Format.asJSON(value)
stream.send(Format.asJSON(value))
case .array(let contents):
stream <<< "[" <<< (shouldIndent ? "\n" : "")
stream.send("[").send(shouldIndent ? "\n" : "")
for (i, item) in contents.enumerated() {
if i != 0 { stream <<< "," <<< (shouldIndent ? "\n" : " ") }
stream <<< indentStreamable(offset: 2)
if i != 0 { stream.send(",").send(shouldIndent ? "\n" : " ") }
stream.send(indentStreamable(offset: 2))
item.write(to: stream, indent: indent.flatMap({ $0 + 2 }))
}
stream <<< (shouldIndent ? "\n" : "") <<< indentStreamable() <<< "]"
stream.send(shouldIndent ? "\n" : "").send(indentStreamable()).send("]")
case .dictionary(let contents):
// We always output in a deterministic order.
stream <<< "{" <<< (shouldIndent ? "\n" : "")
stream.send("{").send(shouldIndent ? "\n" : "")
for (i, key) in contents.keys.sorted().enumerated() {
if i != 0 { stream <<< "," <<< (shouldIndent ? "\n" : " ") }
stream <<< indentStreamable(offset: 2) <<< Format.asJSON(key) <<< ": "
if i != 0 { stream.send(",").send(shouldIndent ? "\n" : " ") }
stream.send(indentStreamable(offset: 2)).send(Format.asJSON(key)).send(": ")
contents[key]!.write(to: stream, indent: indent.flatMap({ $0 + 2 }))
}
stream <<< (shouldIndent ? "\n" : "") <<< indentStreamable() <<< "}"
stream.send(shouldIndent ? "\n" : "").send(indentStreamable()).send("}")
case .orderedDictionary(let contents):
stream <<< "{" <<< (shouldIndent ? "\n" : "")
stream.send("{").send(shouldIndent ? "\n" : "")
for (i, item) in contents.enumerated() {
if i != 0 { stream <<< "," <<< (shouldIndent ? "\n" : " ") }
stream <<< indentStreamable(offset: 2) <<< Format.asJSON(item.key) <<< ": "
if i != 0 { stream.send(",").send(shouldIndent ? "\n" : " ") }
stream.send(indentStreamable(offset: 2)).send(Format.asJSON(item.key)).send(": ")
item.value.write(to: stream, indent: indent.flatMap({ $0 + 2 }))
}
stream <<< (shouldIndent ? "\n" : "") <<< indentStreamable() <<< "}"
stream.send(shouldIndent ? "\n" : "").send(indentStreamable()).send("}")
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions Sources/TSCBasic/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ public final class Process {
outputRedirection: outputRedirection,
startNewProcessGroup: startNewProcessGroup,
loggingHandler: verbose ? { message in
stdoutStream <<< message <<< "\n"
stdoutStream.send(message).send("\n")
stdoutStream.flush()
} : nil
)
Expand Down Expand Up @@ -1276,13 +1276,13 @@ extension ProcessResult.Error: CustomStringConvertible {
let stream = BufferedOutputByteStream()
switch result.exitStatus {
case .terminated(let code):
stream <<< "terminated(\(code)): "
stream.send("terminated(\(code)): ")
#if os(Windows)
case .abnormal(let exception):
stream <<< "abnormal(\(exception)): "
stream.send("abnormal(\(exception)): ")
#else
case .signalled(let signal):
stream <<< "signalled(\(signal)): "
stream.send("signalled(\(signal)): ")
#endif
}

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

// Include the output, if present.
if let output = try? result.utf8Output() + result.utf8stderrOutput() {
// We indent the output to keep it visually separated from everything else.
let indentation = " "
stream <<< " output:\n" <<< indentation <<< output.replacingOccurrences(of: "\n", with: "\n" + indentation)
stream.send(" output:\n").send(indentation).send(output.replacingOccurrences(of: "\n", with: "\n" + indentation))
if !output.hasSuffix("\n") {
stream <<< "\n"
stream.send("\n")
}
}

Expand Down Expand Up @@ -1333,7 +1333,7 @@ extension FileHandle: WritableByteStream {
extension Process {
@available(*, deprecated)
fileprivate static func logToStdout(_ message: String) {
stdoutStream <<< message <<< "\n"
stdoutStream.send(message).send("\n")
stdoutStream.flush()
}
}
10 changes: 5 additions & 5 deletions Sources/TSCBasic/TerminalController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,13 @@ public final class TerminalController {

/// Clears the current line and moves the cursor to beginning of the line..
public func clearLine() {
stream <<< clearLineString <<< "\r"
stream.send(clearLineString).send("\r")
flush()
}

/// Moves the cursor y columns up.
public func moveCursor(up: Int) {
stream <<< "\u{001B}[\(up)A"
stream.send("\u{001B}[\(up)A")
flush()
}

Expand All @@ -184,7 +184,7 @@ public final class TerminalController {

/// Inserts a new line character into the stream.
public func endLine() {
stream <<< "\n"
stream.send("\n")
flush()
}

Expand All @@ -198,9 +198,9 @@ public final class TerminalController {
private func writeWrapped(_ string: String, inColor color: Color, bold: Bool = false, stream: WritableByteStream) {
// Don't wrap if string is empty or color is no color.
guard !string.isEmpty && color != .noColor else {
stream <<< string
stream.send(string)
return
}
stream <<< color.string <<< (bold ? boldString : "") <<< string <<< resetString
stream.send(color.string).send(bold ? boldString : "").send(string).send(resetString)
}
}
85 changes: 59 additions & 26 deletions Sources/TSCBasic/WritableByteStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ public protocol ByteStreamable {
/// different output destinations, e.g., a file or an in memory buffer. This is
/// loosely modeled on LLVM's llvm::raw_ostream class.
///
/// The stream is generally used in conjunction with the custom streaming
/// operator '<<<'. For example:
/// The stream is generally used in conjunction with the `appending` function.
/// For example:
///
/// let stream = BufferedOutputByteStream()
/// stream <<< "Hello, world!"
/// stream.appending("Hello, world!")
///
/// would write the UTF8 encoding of "Hello, world!" to the stream.
///
/// The stream accepts a number of custom formatting operators which are defined
/// in the `Format` struct (used for namespacing purposes). For example:
///
/// let items = ["hello", "world"]
/// stream <<< Format.asSeparatedList(items, separator: " ")
/// stream.appending(Format.asSeparatedList(items, separator: " "))
///
/// would write each item in the list to the stream, separating them with a
/// space.
Expand Down Expand Up @@ -137,6 +137,34 @@ extension WritableByteStream {
}
}
}

// MARK: helpers that return `self`

// FIXME: This override shouldn't be necesary but removing it causes a 30% performance regression. This problem is
// tracked by the following bug: https://bugs.swift.org/browse/SR-8535
@discardableResult
public func send(_ value: ArraySlice<UInt8>) -> WritableByteStream {
value.write(to: self)
return self
}

@discardableResult
public func send(_ value: ByteStreamable) -> WritableByteStream {
value.write(to: self)
return self
}

@discardableResult
public func send(_ value: CustomStringConvertible) -> WritableByteStream {
value.description.write(to: self)
return self
}

@discardableResult
public func send(_ value: ByteStreamable & CustomStringConvertible) -> WritableByteStream {
value.write(to: self)
return self
}
}

/// The `WritableByteStream` base class.
Expand Down Expand Up @@ -366,24 +394,29 @@ precedencegroup StreamingPrecedence {

// FIXME: This override shouldn't be necesary but removing it causes a 30% performance regression. This problem is
// tracked by the following bug: https://bugs.swift.org/browse/SR-8535

@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead")
@discardableResult
public func <<< (stream: WritableByteStream, value: ArraySlice<UInt8>) -> WritableByteStream {
value.write(to: stream)
return stream
}

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

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

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

func write(to stream: WritableByteStream) {
stream <<< (value ? "true" : "false")
stream.send(value ? "true" : "false")
}
}

Expand All @@ -463,7 +496,7 @@ public struct Format {

func write(to stream: WritableByteStream) {
// FIXME: Diagnose integers which cannot be represented in JSON.
stream <<< value.description
stream.send(value.description)
}
}

Expand All @@ -478,7 +511,7 @@ public struct Format {
// FIXME: What should we do about NaN, etc.?
//
// FIXME: Is Double.debugDescription the best representation?
stream <<< value.debugDescription
stream.send(value.debugDescription)
}
}

Expand All @@ -494,9 +527,9 @@ public struct Format {
let value: String

func write(to stream: WritableByteStream) {
stream <<< UInt8(ascii: "\"")
stream.send(UInt8(ascii: "\""))
stream.writeJSONEscaped(value)
stream <<< UInt8(ascii: "\"")
stream.send(UInt8(ascii: "\""))
}
}

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

func write(to stream: WritableByteStream) {
stream <<< UInt8(ascii: "[")
stream.send(UInt8(ascii: "["))
for (i, item) in items.enumerated() {
if i != 0 { stream <<< "," }
stream <<< Format.asJSON(item)
if i != 0 { stream.send(",") }
stream.send(Format.asJSON(item))
}
stream <<< UInt8(ascii: "]")
stream.send(UInt8(ascii: "]"))
}
}

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

func write(to stream: WritableByteStream) {
stream <<< UInt8(ascii: "{")
stream.send(UInt8(ascii: "{"))
for (offset: i, element: (key: key, value: value)) in items.enumerated() {
if i != 0 { stream <<< "," }
stream <<< Format.asJSON(key) <<< ":" <<< Format.asJSON(value)
if i != 0 { stream.send(",") }
stream.send(Format.asJSON(key)).send(":").send(Format.asJSON(value))
}
stream <<< UInt8(ascii: "}")
stream.send(UInt8(ascii: "}"))
}
}

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

func write(to stream: WritableByteStream) {
stream <<< UInt8(ascii: "[")
stream.send(UInt8(ascii: "["))
for (i, item) in items.enumerated() {
if i != 0 { stream <<< "," }
stream <<< Format.asJSON(transform(item))
if i != 0 { stream.send(",") }
stream.send(Format.asJSON(transform(item)))
}
stream <<< UInt8(ascii: "]")
stream.send(UInt8(ascii: "]"))
}
}

Expand All @@ -572,10 +605,10 @@ public struct Format {
for (i, item) in items.enumerated() {
// Add the separator, if necessary.
if i != 0 {
stream <<< separator
stream.send(separator)
}

stream <<< item
stream.send(item)
}
}
}
Expand All @@ -596,8 +629,8 @@ public struct Format {

func write(to stream: WritableByteStream) {
for (i, item) in items.enumerated() {
if i != 0 { stream <<< separator }
stream <<< transform(item)
if i != 0 { stream.send(separator) }
stream.send(transform(item))
}
}
}
Expand All @@ -617,7 +650,7 @@ public struct Format {

func write(to stream: WritableByteStream) {
for _ in 0..<count {
stream <<< string
stream.send(string)
}
}
}
Expand Down
Loading