Skip to content

[stdlib] String.Index: conform to CustomDebugStringConvertible #75433

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 6 commits into from
Oct 9, 2024
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
53 changes: 27 additions & 26 deletions stdlib/public/core/StringIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -524,42 +524,43 @@ extension String.Index {
}
}

// The definitions below are placeholders for potential future `String.Index`
// conformances to `CustomStringConvertible` and
// `CustomDebugStringConvertible`. They are supplied here to make working with
// string indices somewhat bearable while we're working on adding the actual
// conformances.

/// A textual representation of this instance.
@_alwaysEmitIntoClient
/// A textual representation of this instance, intended for debugging.
///
/// - Important: The contents of the returned string are not guaranteed to
/// remain stable: they may arbitrarily change in any Swift release.
@_alwaysEmitIntoClient // FIXME: Use @backDeployed
@inline(never)
public var _description: String {
public var debugDescription: String {
// 23[utf8]+1
var d = "\(_encodedOffset)[\(_encodingDescription)]"
if transcodedOffset != 0 {
d += "+\(transcodedOffset)"
}
return d
}
}

/// A textual representation of this instance, suitable for debugging.
@available(SwiftStdlib 6.1, *)
extension String.Index: CustomDebugStringConvertible {}

extension String.Index {
/// A textual representation of this instance, intended for debugging.
///
/// - Important: The contents of the returned string are not guaranteed to
/// remain stable: they may arbitrarily change in any Swift release.
@_alwaysEmitIntoClient
@inline(never)
@available(*, deprecated, renamed: "debugDescription")
public var _description: String {
debugDescription
}

/// A textual representation of this instance, intended for debugging.
///
/// - Important: The contents of the returned string are not guaranteed to
/// remain stable: they may arbitrarily change in any Swift release.
@_alwaysEmitIntoClient
@available(*, deprecated, renamed: "debugDescription")
public var _debugDescription: String {
var d = "String.Index("
d += "offset: \(_encodedOffset)[\(_encodingDescription)]"
if transcodedOffset != 0 {
d += "+\(transcodedOffset)"
}
if _isCharacterAligned {
d += ", aligned: character"
} else if _isScalarAligned {
d += ", aligned: scalar"
}
if let stride = characterStride {
d += ", stride: \(stride)"
}
d += ")"
return d
debugDescription
}
}
5 changes: 5 additions & 0 deletions test/abi/macOS/arm64/stdlib.swift
Original file line number Diff line number Diff line change
Expand Up @@ -767,3 +767,8 @@ Added: _$ss7UnicodeO5ASCIIO27encodedReplacementCharacters15CollectionOfOneVys5UI
Added: _$ss7UnicodeO5UTF16O27encodedReplacementCharacters11_UIntBufferVys6UInt16VGvpZMV
Added: _$ss7UnicodeO5UTF32O27encodedReplacementCharacters15CollectionOfOneVys6UInt32VGvpZMV
Added: _$sSo19_SwiftStdlibVersionasE6v6_1_0ABvpZMV

// SE-0445 Improving printed descriptions of String.Index
Added: _$sSS5IndexV16debugDescriptionSSvpMV
Added: _$sSS5IndexVs28CustomDebugStringConvertiblesMc
Added: _$sSS5IndexVs28CustomDebugStringConvertiblesWP
5 changes: 5 additions & 0 deletions test/abi/macOS/x86_64/stdlib.swift
Original file line number Diff line number Diff line change
Expand Up @@ -768,3 +768,8 @@ Added: _$ss7UnicodeO5ASCIIO27encodedReplacementCharacters15CollectionOfOneVys5UI
Added: _$ss7UnicodeO5UTF16O20_replacementCodeUnits6UInt16VvpZMV
Added: _$ss7UnicodeO5UTF16O27encodedReplacementCharacters11_UIntBufferVys6UInt16VGvpZMV
Added: _$ss7UnicodeO5UTF32O27encodedReplacementCharacters15CollectionOfOneVys6UInt32VGvpZMV

// SE-0445 Improving printed descriptions of String.Index
Added: _$sSS5IndexV16debugDescriptionSSvpMV
Added: _$sSS5IndexVs28CustomDebugStringConvertiblesMc
Added: _$sSS5IndexVs28CustomDebugStringConvertiblesWP
2 changes: 2 additions & 0 deletions test/api-digester/stability-stdlib-abi-without-asserts.test
Original file line number Diff line number Diff line change
Expand Up @@ -817,4 +817,6 @@ Func _SliceBuffer.withUnsafeBufferPointer(_:) has mangled name changing from 'Sw
Func _SliceBuffer.withUnsafeMutableBufferPointer(_:) has been renamed to Func __abi_withUnsafeMutableBufferPointer(_:)
Func _SliceBuffer.withUnsafeMutableBufferPointer(_:) has mangled name changing from 'Swift._SliceBuffer.withUnsafeMutableBufferPointer<A>((Swift.UnsafeMutableBufferPointer<A>) throws -> A1) throws -> A1' to 'Swift._SliceBuffer.__abi_withUnsafeMutableBufferPointer<A>((Swift.UnsafeMutableBufferPointer<A>) throws -> A1) throws -> A1'

Struct String.Index has added a conformance to an existing protocol CustomDebugStringConvertible

// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment above.)
107 changes: 89 additions & 18 deletions test/stdlib/StringIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1013,23 +1013,22 @@ suite.test("UTF-16 breadcrumbs") {
c̵̛̘̥̮̙̥̟̘̝͙̤̮͉͔̭̺̺̅̀̽̒̽̏̊̆͒͌̂͌̌̓̈́̐̔̿̂͑͠͝͝ͅ\#
"""#

print(string.utf16.count)
let indices = Array(string.utf16.indices) + [string.utf16.endIndex]
for i in 0 ..< indices.count {
for j in 0 ..< indices.count {
let distance = string.utf16.distance(from: indices[i], to: indices[j])
expectEqual(distance, j - i,
"""
i: \(i), indices[i]: \(indices[i]._description)
j: \(j), indices[j]: \(indices[j]._description)
i: \(i), indices[i]: \(indices[i])
j: \(j), indices[j]: \(indices[j])
""")

let target = string.utf16.index(indices[i], offsetBy: j - i)
expectEqual(target, indices[j],
"""
i: \(i), indices[i]: \(indices[i]._description)
j: \(j), indices[j]: \(indices[j]._description)
target: \(target._description)
i: \(i), indices[i]: \(indices[i])
j: \(j), indices[j]: \(indices[j])
target: \(target)
""")
}
}
Expand Down Expand Up @@ -1136,9 +1135,9 @@ if #available(SwiftStdlib 5.8, *) {
let actual = string._index(roundingDown: index)
expectEqual(actual, expected,
"""
index: \(index._description)
actual: \(actual._description)
expected: \(expected._description)
index: \(index)
actual: \(actual)
expected: \(expected)
""")
}
}
Expand All @@ -1154,9 +1153,9 @@ suite.test("String index rounding/Scalars")
let actual = string.unicodeScalars._index(roundingDown: index)
expectEqual(actual, expected,
"""
index: \(index._description)
actual: \(actual._description)
expected: \(expected._description)
index: \(index)
actual: \(actual)
expected: \(expected)
""")
}
}
Expand All @@ -1180,9 +1179,9 @@ suite.test("String index rounding/UTF-16")
let actual = string.utf16._index(roundingDown: index)
expectEqual(actual, expected,
"""
index: \(index._description)
actual: \(actual._description)
expected: \(expected._description)
index: \(index)
actual: \(actual)
expected: \(expected)
""")
}
}
Expand All @@ -1205,9 +1204,81 @@ suite.test("String index rounding/UTF-8")
let actual = string.utf8._index(roundingDown: index)
expectEqual(actual, expected,
"""
index: \(index._description)
actual: \(actual._description)
expected: \(expected._description)
index: \(index)
actual: \(actual)
expected: \(expected)
""")
}
}

if #available(SwiftStdlib 6.1, *) {
suite.test("String index printing (native)") {
let str = "nai\u{308}ve 🪻"

let utf8Indices = [
"0[any]", "1[utf8]", "2[utf8]", "3[utf8]", "4[utf8]", "5[utf8]",
"6[utf8]", "7[utf8]", "8[utf8]", "9[utf8]", "10[utf8]", "11[utf8]"
]
expectEqual(str.utf8.indices.map { "\($0)" }, utf8Indices)

let utf16Indices = [
"0[any]", "1[utf8]", "2[utf8]", "3[utf8]", "5[utf8]", "6[utf8]",
"7[utf8]", "8[utf8]", "8[utf8]+1"
]
expectEqual(str.utf16.indices.map { "\($0)" }, utf16Indices)

let scalarIndices = [
"0[any]", "1[utf8]", "2[utf8]", "3[utf8]", "5[utf8]", "6[utf8]",
"7[utf8]", "8[utf8]"
]
expectEqual(str.unicodeScalars.indices.map { "\($0)" }, scalarIndices)

let characterIndices = [
"0[any]", "1[utf8]", "2[utf8]", "5[utf8]", "6[utf8]", "7[utf8]", "8[utf8]"
]
expectEqual(str.indices.map { "\($0)" }, characterIndices)
}
}

suite.test("String index debugDescription backdeployment") {
// Note: no availability check
let str = "i\u{308}"
expectEqual(str.startIndex.debugDescription, "0[any]")
expectEqual(str.endIndex.debugDescription, "3[utf8]")
}


#if _runtime(_ObjC)
if #available(SwiftStdlib 6.1, *) {
suite.test("String index printing (bridged Cocoa)") {
let utf16 = Array("nai\u{308}ve 🪻".utf16)
let nsstr = NSString(characters: utf16, length: utf16.count)
let str = nsstr as String

let utf8Indices = [
"0[any]", "1[utf16]", "2[utf16]", "3[utf16]", "3[utf16]+1", "4[utf16]",
"5[utf16]", "6[utf16]", "7[utf16]", "7[utf16]+1", "7[utf16]+2",
"7[utf16]+3"
]
expectEqual(str.utf8.indices.map { "\($0)" }, utf8Indices)

let utf16Indices = [
"0[any]", "1[utf16]", "2[utf16]", "3[utf16]", "4[utf16]", "5[utf16]",
"6[utf16]", "7[utf16]", "8[utf16]"
]
expectEqual(str.utf16.indices.map { "\($0)" }, utf16Indices)

let scalarIndices = [
"0[any]", "1[utf16]", "2[utf16]", "3[utf16]", "4[utf16]", "5[utf16]",
"6[utf16]", "7[utf16]"
]
expectEqual(str.unicodeScalars.indices.map { "\($0)" }, scalarIndices)

let characterIndices = [
"0[any]", "1[utf16]", "2[utf16]", "4[utf16]", "5[utf16]", "6[utf16]",
"7[utf16]"
]
expectEqual(str.indices.map { "\($0)" }, characterIndices)
}
}
#endif