 // Text Formatting Prototype
 //
 // This file demonstrates the concepts proposed in TextFormatting.rst
-
-// FIXME: Workaround for <rdar://problem/14011860> SubTLF: Default
-// implementations in protocols.
-infix operator ~> { precedence 255 }
-
-/// \brief A thing into which we can stream text
-protocol XOutputStream {
-  mutating
-  func append(_ text: String)
-}
-
-/// \brief Strings are XOutputStreams
-extension String: XOutputStream {
-  mutating
-  func append(_ text: String) {
-    self += text
-  }
-}
-
-/// \brief A thing that can be written to an XOutputStream
-protocol XStreamable {
-  func writeTo<Target: XOutputStream>(_ target: inout Target)
-}
-
-/// \brief A thing that can be printed in the REPL and the Debugger
-///
-/// Everything compiler-magically conforms to this protocol.  To
-/// change the debug representation for a type, you don't need to
-/// declare conformance: simply give the type a debugFormat().
-protocol XDebugPrintable {
-
-  associatedtype DebugRepresentation : XStreamable // = String
-
-  /// \brief Produce a textual representation for the REPL and
+//
+// We may not want the following protocol exactly as-is; it overlaps somewhat
+// with CustomStringConvertible and CustomDebugStringConvertible, and it's not
+// clear whether a protocol is even needed.
+
+/// A type that supports format() and debugFormat().
+protocol CustomFormatted : CustomStringConvertible, CustomDebugStringConvertible {
+
+  associatedtype DebugRepresentation : TextOutputStreamable = String
+  associatedtype PrintRepresentation : TextOutputStreamable = DebugRepresentation
+  
+  /// Produce a textual representation for the REPL and
   /// Debugger.
   ///
-  /// Because String is a XStreamable, your implementation of
+  /// Because String is a TextOutputStreamable, your implementation of
   /// debugRepresentation can just return a String.  If you want to write
-  /// directly to the XOutputStream for efficiency reasons,
+  /// directly to the TextOutputStream for efficiency reasons,
   /// (e.g. if your representation is huge), you can return a custom
   /// DebugRepresentation type.
   ///

  }
}

/// \brief An integral type that can be printed
protocol XPrintableInteger : ExpressibleByIntegerLiteral, Comparable, SignedNumber, XPrintable {
  func %(lhs: Self, rhs: Self) -> Self
  func /(lhs: Self, rhs: Self) -> Self

  // FIXME: Stand-in for constructor pending <rdar://problem/13695680>
  // (Constructor requirements in protocols)
  static func fromInt(_ x: Int) -> Self
  func toInt() -> Int
}

extension Int : XDebugPrintable {
  func debugFormat() -> String { return String(self) }
}

extension Int : XPrintableInteger {
  static func fromInt(_ x: Int) -> Int { return x }
  func toInt() -> Int { return self }

  func getValue() -> Int {
    return self
  }
}

struct _formatArgs {
  var radix: Int, fill: String, width: Int
}

func format(radix radix: Int = 10, fill: String = " ", width: Int = 0) -> _formatArgs {
  return _formatArgs(radix: radix, fill: fill, width: width)
}

// FIXME: this function was a member of RadixFormat, but
// <rdar://problem/15525229> (SIL verification failed: operand of
// 'apply' doesn't match function input type) changed all that.
func _writePositive<T:XPrintableInteger, S: XOutputStream>(
  _ value: T, _ stream: inout S, _ args: _formatArgs) -> Int
{

  if value == 0 {
    return 0
  }

  var radix: T = T.fromInt(args.radix)
  var rest: T = value / radix
  var nDigits = _writePositive(rest, &stream, args)
  var digit = UInt32((value % radix).toInt())
  var baseCharOrd : UInt32 = digit <= 9 ? UnicodeScalar("0").value 
                                        : UnicodeScalar("A").value - 10
  stream.append(String(UnicodeScalar(baseCharOrd + digit)!))
  return nDigits + 1
}

// FIXME: this function was a member of RadixFormat, but
// <rdar://problem/15525229> (SIL verification failed: operand of
// 'apply' doesn't match function input type) changed all that.
func _writeSigned<T:XPrintableInteger, S: XOutputStream>(
  _ value: T, _ target: inout S, _ args: _formatArgs
) {
  var width = 0
  var result = ""

  if value == 0 {
    result = "0"
    width += 1
  }
  else {
    var absVal = abs(value)
    if (value < 0) {
      target.append("-")
      width += 1
    }
    width += _writePositive(absVal, &result, args)
  }

  while width < args.width {
    width += 1
    target.append(args.fill)
  }
  target.append(result)
}

struct RadixFormat<T: XPrintableInteger> : XStreamable {
  init(value: T, args: _formatArgs) {
    self.value = value
    self.args = args
  }

  func writeTo<S: XOutputStream>(_ target: inout S) {
    _writeSigned(value, &target, args)
  }

  typealias DebugRepresentation = String
  func debugFormat() -> String {
    return "RadixFormat(" + toDebugString(value) + ", " + toDebugString(args.radix) + ")"
  }

  var value: T
  var args: _formatArgs
}

func ~> <T:XPrintableInteger> (x: T, _: __PrintedFormat) -> RadixFormat<T> {
  return RadixFormat(value: x, args: format())
}

func ~> <T:XPrintableInteger> (x: T, args: _formatArgs) -> RadixFormat<T> {
  return RadixFormat(value: x, args: args)
}

// ==========

//
// xprint and xprintln
//

struct StdoutStream : XOutputStream {
  func append(_ text: String) { Swift.print(text, terminator: "") }
  // debugging only
  func dump() -> String {
    return "<StdoutStream>"
  }
}

func xprint<Target: XOutputStream, T: XStreamable>(_ target: inout Target, _ x: T) {
  x.writeTo(&target)
}

func xprint<Target: XOutputStream, T: XPrintable>(_ target: inout Target, _ x: T) {
  xprint(&target, x~>format())
}

func xprint<T: XPrintable>(_ x: T) {
  var target = StdoutStream()
  xprint(&target, x)
}

func xprint<T: XStreamable>(_ x: T) {
  var target = StdoutStream()
  xprint(&target, x)
}

func xprintln<Target: XOutputStream, T: XPrintable>(_ target: inout Target, _ x: T) {
  xprint(&target, x)
  target.append("\n")
}

func xprintln<Target: XOutputStream, T: XStreamable>(_ target: inout Target, _ x: T) {
  xprint(&target, x)
  target.append("\n")
}

func xprintln<T: XPrintable>(_ x: T) {
  var target = StdoutStream()
  xprintln(&target, x)
}

func xprintln<T: XStreamable>(_ x: T) {
  var target = StdoutStream()
  xprintln(&target, x)
}

func xprintln(_ x: String) {
  var target = StdoutStream()
  x.writeTo(&target)
  "\n".writeTo(&target)
}

extension String {
  init <T: XStreamable>(_ x: T) {
    self = ""
    xprint(&self, x)
  }
}

func toPrettyString<T: XStreamable>(_ x: T) -> String {
  var result = "|"
  xprint(&result, x)
  result += "|"
  return result
}

// ===========

var x = "fubar\n\tbaz"

xprintln(x)
// CHECK: fubar
// CHECK-NEXT: 	baz

xprintln(toDebugString(x))
// CHECK-NEXT: "fubar\n\tbaz"

xprintln(toPrettyString(424242~>format(radix:16, width:8)))
// CHECK-NEXT: |   67932|

var zero = "0"
xprintln(toPrettyString(-434343~>format(fill:zero, width:8)))
// CHECK-NEXT: |-0434343|

xprintln(toPrettyString(-42~>format(radix:13, width:8)))
// CHECK-NEXT: |-     33|

xprintln(0x1EADBEEF~>format(radix:16))
// CHECK-NEXT: 1EADBEEF

// FIXME: rdar://16168414 this doesn't work in 32-bit
// xprintln(0xDEADBEEF~>format(radix:16))
// CHECK-NEXT-not: DEADBEEF

  /// escaped, etc.  A struct Point { var x, y: Int } might be
  /// represented as "Point(x: 3, y: 5)".
  func debugFormat() -> DebugRepresentation

  /// produce a "pretty" textual representation that can be
  /// distinct from the debug format.  For example,
  /// String.printRepresentation returns the string itself, without quoting.
  ///
  /// In general you can return a String here, but if you need more
  /// control, we strongly recommend returning a custom Representation
  /// type, e.g. a nested struct of your type.  If you're lazy, you
  /// can conform to TextOutputStreamable directly and just implement its
  /// write() func.
  func format() -> PrintRepresentation
}

extension CustomFormatted where PrintRepresentation == DebugRepresentation {
  func format() -> DebugRepresentation { return debugFormat() }
}

/// CustomFormatted's conformance to CustomStringConvertible and
/// CustomDebugStringConvertible
extension CustomFormatted {
  public var description: String {
    return _description
  }
  
  public var debugDescription: String {
    return _debugDescription
  }

  //===--- Using [debug]description directly might pick up the stdlib -----===//
  //===--- versions and skew test results, so use these for testing -------===//
  var _description: String {
    var result = ""
    x.format().write(to: &result)
    return result
  }
  
  var _debugDescription: String {
    var result = ""
    x.debugFormat().write(to: &result)
    return result
  }
}

extension String : CustomFormatted {
  // Streamer for the debug representation of String. When an
  // EscapedStringFormat is written to a TextOutputStream, it adds
  // surrounding quotes and escapes special characters.
  struct EscapedFormat : TextOutputStreamable {

    init(_ s: String) {
      self._value = s
    }

    func write<Target: TextOutputStream>(to target: inout Target) {
      target.write("\"")
      for c in _value.unicodeScalars {
        target.write(c.escaped(asASCII: true))
      }
      target.write("\"")
    }

    var _value: String
  }

  func debugFormat() -> EscapedFormat {
    return EscapedFormat(self)
  }

  func format() -> String {
