mirror of
https://github.com/apple/swift-foundation.git
synced 2025-05-22 21:40:04 +08:00
* rdar://107778676 Stop vendoring the Collections package * rdar://107778676 Fix test expectation AttributedString.CharacterView needs to round all indices down to the nearest Character boundary to avoid semantic issues with its Collection conformance. This means that CharacterView slices can never start or end in between Character boundaries. * Remove a stray print statement
789 lines
24 KiB
Swift
789 lines
24 KiB
Swift
//===----------------------------------------------------------------------===//
|
||
//
|
||
// This source file is part of the Swift.org open source project
|
||
//
|
||
// Copyright (c) 2020-2023 Apple Inc. and the Swift project authors
|
||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||
//
|
||
// See https://swift.org/LICENSE.txt for license information
|
||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#if FOUNDATION_FRAMEWORK
|
||
@_implementationOnly @_spi(Unstable) import CollectionsInternal
|
||
#else
|
||
import _RopeModule
|
||
#endif
|
||
|
||
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
|
||
extension AttributedString.Runs {
|
||
@preconcurrency
|
||
public struct AttributesSlice1<T : AttributedStringKey> : BidirectionalCollection, Sendable where T.Value : Sendable {
|
||
public typealias Index = AttributedString.Index
|
||
|
||
// FIXME: Why no labels?
|
||
public typealias Element = (T.Value?, Range<AttributedString.Index>)
|
||
|
||
internal typealias Runs = AttributedString.Runs
|
||
|
||
let runs : Runs
|
||
let _names: [String]
|
||
let _constraints: [AttributeRunBoundaries]
|
||
|
||
init(runs: Runs) {
|
||
self.runs = runs
|
||
// FIXME: ☠️ Get these from a proper cache in runs._guts.
|
||
_names = [T.name]
|
||
_constraints = T._constraintsInvolved
|
||
}
|
||
|
||
public struct Iterator: IteratorProtocol, Sendable {
|
||
// Note: This is basically equivalent to `IndexingIterator`.
|
||
|
||
public typealias Element = AttributesSlice1.Element
|
||
|
||
let _slice: AttributesSlice1
|
||
var _index: AttributesSlice1.Index
|
||
|
||
internal init(_ slice: AttributesSlice1) {
|
||
self._slice = slice
|
||
self._index = slice.startIndex
|
||
}
|
||
|
||
public mutating func next() -> Element? {
|
||
if _index == _slice.endIndex {
|
||
return nil
|
||
}
|
||
let run = _slice.runs[_index]
|
||
let next = _slice.index(after: _index)
|
||
let range = _index ..< next
|
||
_index = next
|
||
return (run._attributes[T.self], range)
|
||
}
|
||
}
|
||
|
||
public func makeIterator() -> Iterator {
|
||
Iterator(self)
|
||
}
|
||
|
||
public var startIndex: Index {
|
||
runs._range.lowerBound
|
||
}
|
||
public var endIndex: Index {
|
||
runs._range.upperBound
|
||
}
|
||
|
||
public func index(before i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
before: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public func index(after i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
after: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public subscript(position: AttributedString.Index) -> Element {
|
||
let (start, runIndex) = runs._slicedRunBoundary(
|
||
roundingDown: position,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
let end = self.index(after: position)
|
||
let attributes = runs._guts.runs[runIndex.rangeIndex].attributes
|
||
return (attributes[T.self], start ..< end)
|
||
}
|
||
}
|
||
|
||
public subscript<T : AttributedStringKey>(_ keyPath: KeyPath<AttributeDynamicLookup, T>) -> AttributesSlice1<T> {
|
||
return AttributesSlice1<T>(runs: self)
|
||
}
|
||
|
||
public subscript<T : AttributedStringKey>(_ t: T.Type) -> AttributesSlice1<T> {
|
||
return AttributesSlice1<T>(runs: self)
|
||
}
|
||
}
|
||
|
||
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
|
||
extension AttributedString.Runs {
|
||
@preconcurrency
|
||
public struct AttributesSlice2<
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey
|
||
> : BidirectionalCollection, Sendable
|
||
where
|
||
T.Value : Sendable,
|
||
U.Value : Sendable
|
||
{
|
||
public typealias Index = AttributedString.Index
|
||
|
||
// FIXME: Why no labels?
|
||
public typealias Element = (T.Value?, U.Value?, Range<AttributedString.Index>)
|
||
|
||
internal typealias Runs = AttributedString.Runs
|
||
|
||
let runs : Runs
|
||
let _names: [String]
|
||
let _constraints: [AttributeRunBoundaries]
|
||
|
||
init(runs: Runs) {
|
||
self.runs = runs
|
||
// FIXME: ☠️ Get these from a proper cache in runs._guts.
|
||
_names = [T.name, U.name]
|
||
_constraints = Array(_contents: T.runBoundaries, U.runBoundaries)
|
||
}
|
||
|
||
public struct Iterator: IteratorProtocol, Sendable {
|
||
// Note: This is basically equivalent to `IndexingIterator`.
|
||
|
||
public typealias Element = AttributesSlice2.Element
|
||
|
||
let _slice: AttributesSlice2
|
||
var _index: AttributedString.Index
|
||
|
||
internal init(_ slice: AttributesSlice2) {
|
||
self._slice = slice
|
||
self._index = slice.startIndex
|
||
}
|
||
|
||
public mutating func next() -> Element? {
|
||
if _index == _slice.endIndex {
|
||
return nil
|
||
}
|
||
let run = _slice.runs[_index]
|
||
let next = _slice.index(after: _index)
|
||
let range = _index ..< next
|
||
_index = next
|
||
return (run._attributes[T.self], run._attributes[U.self], range)
|
||
}
|
||
}
|
||
|
||
public func makeIterator() -> Iterator {
|
||
Iterator(self)
|
||
}
|
||
|
||
public var startIndex: Index {
|
||
runs._range.lowerBound
|
||
}
|
||
public var endIndex: Index {
|
||
runs._range.upperBound
|
||
}
|
||
|
||
public func index(before i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
before: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public func index(after i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
after: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public subscript(position: AttributedString.Index) -> Element {
|
||
let (start, runIndex) = runs._slicedRunBoundary(
|
||
roundingDown: position,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
let end = self.index(after: position)
|
||
let attributes = runs._guts.runs[runIndex.rangeIndex].attributes
|
||
return (attributes[T.self], attributes[U.self], start ..< end)
|
||
}
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey
|
||
> (
|
||
_ t: KeyPath<AttributeDynamicLookup, T>,
|
||
_ u: KeyPath<AttributeDynamicLookup, U>
|
||
) -> AttributesSlice2<T, U> {
|
||
return AttributesSlice2<T, U>(runs: self)
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey
|
||
> (
|
||
_ t: T.Type,
|
||
_ u: U.Type
|
||
) -> AttributesSlice2<T, U> {
|
||
return AttributesSlice2<T, U>(runs: self)
|
||
}
|
||
}
|
||
|
||
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
|
||
extension AttributedString.Runs {
|
||
@preconcurrency
|
||
public struct AttributesSlice3<
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey
|
||
> : BidirectionalCollection, Sendable
|
||
where
|
||
T.Value : Sendable,
|
||
U.Value : Sendable,
|
||
V.Value : Sendable
|
||
{
|
||
public typealias Index = AttributedString.Index
|
||
|
||
// FIXME: Why no labels?
|
||
public typealias Element = (T.Value?, U.Value?, V.Value?, Range<AttributedString.Index>)
|
||
|
||
internal typealias Runs = AttributedString.Runs
|
||
|
||
let runs : Runs
|
||
let _names: [String]
|
||
let _constraints: [AttributeRunBoundaries]
|
||
|
||
init(runs: Runs) {
|
||
self.runs = runs
|
||
// FIXME: ☠️ Get these from a proper cache in runs._guts.
|
||
_names = [T.name, U.name, V.name]
|
||
_constraints = Array(_contents: T.runBoundaries, U.runBoundaries, V.runBoundaries)
|
||
}
|
||
|
||
public struct Iterator: IteratorProtocol, Sendable {
|
||
// Note: This is basically equivalent to `IndexingIterator`.
|
||
|
||
public typealias Element = AttributesSlice3.Element
|
||
|
||
let _slice: AttributesSlice3
|
||
var _index: AttributedString.Index
|
||
|
||
internal init(_ slice: AttributesSlice3) {
|
||
self._slice = slice
|
||
self._index = slice.startIndex
|
||
}
|
||
|
||
public mutating func next() -> Element? {
|
||
if _index == _slice.endIndex {
|
||
return nil
|
||
}
|
||
let run = _slice.runs[_index]
|
||
let next = _slice.index(after: _index)
|
||
let range = _index ..< next
|
||
_index = next
|
||
return (
|
||
run._attributes[T.self],
|
||
run._attributes[U.self],
|
||
run._attributes[V.self],
|
||
range)
|
||
}
|
||
}
|
||
|
||
public func makeIterator() -> Iterator {
|
||
Iterator(self)
|
||
}
|
||
|
||
public var startIndex: Index {
|
||
runs._range.lowerBound
|
||
}
|
||
public var endIndex: Index {
|
||
runs._range.upperBound
|
||
}
|
||
|
||
public func index(before i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
before: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public func index(after i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
after: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public subscript(position: AttributedString.Index) -> Element {
|
||
let (start, runIndex) = runs._slicedRunBoundary(
|
||
roundingDown: position,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
let end = self.index(after: position)
|
||
let attributes = runs._guts.runs[runIndex.rangeIndex].attributes
|
||
return (attributes[T.self], attributes[U.self], attributes[V.self], start ..< end)
|
||
}
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey
|
||
> (
|
||
_ t: KeyPath<AttributeDynamicLookup, T>,
|
||
_ u: KeyPath<AttributeDynamicLookup, U>,
|
||
_ v: KeyPath<AttributeDynamicLookup, V>
|
||
) -> AttributesSlice3<T, U, V> {
|
||
return AttributesSlice3<T, U, V>(runs: self)
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey
|
||
> (
|
||
_ t: T.Type,
|
||
_ u: U.Type,
|
||
_ v: V.Type
|
||
) -> AttributesSlice3<T, U, V> {
|
||
return AttributesSlice3<T, U, V>(runs: self)
|
||
}
|
||
}
|
||
|
||
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
|
||
extension AttributedString.Runs {
|
||
@preconcurrency
|
||
public struct AttributesSlice4<
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey,
|
||
W : AttributedStringKey
|
||
> : BidirectionalCollection, Sendable
|
||
where
|
||
T.Value : Sendable,
|
||
U.Value : Sendable,
|
||
V.Value : Sendable,
|
||
W.Value : Sendable
|
||
{
|
||
public typealias Index = AttributedString.Index
|
||
|
||
// FIXME: Why no labels?
|
||
public typealias Element = (T.Value?, U.Value?, V.Value?, W.Value?, Range<AttributedString.Index>)
|
||
|
||
internal typealias Runs = AttributedString.Runs
|
||
|
||
let runs : Runs
|
||
let _names: [String]
|
||
let _constraints: [AttributeRunBoundaries]
|
||
|
||
init(runs: Runs) {
|
||
self.runs = runs
|
||
// FIXME: ☠️ Get these from a proper cache in runs._guts.
|
||
_names = [T.name, U.name, V.name, W.name]
|
||
_constraints = Array(
|
||
_contents: T.runBoundaries, U.runBoundaries, V.runBoundaries, W.runBoundaries)
|
||
}
|
||
|
||
public struct Iterator: IteratorProtocol, Sendable {
|
||
// Note: This is basically equivalent to `IndexingIterator`.
|
||
|
||
public typealias Element = AttributesSlice4.Element
|
||
|
||
let _slice: AttributesSlice4
|
||
var _index: AttributedString.Index
|
||
|
||
internal init(_ slice: AttributesSlice4) {
|
||
self._slice = slice
|
||
self._index = slice.startIndex
|
||
}
|
||
|
||
public mutating func next() -> Element? {
|
||
if _index == _slice.endIndex {
|
||
return nil
|
||
}
|
||
let run = _slice.runs[_index]
|
||
let next = _slice.index(after: _index)
|
||
let range = _index ..< next
|
||
_index = next
|
||
return (
|
||
run._attributes[T.self],
|
||
run._attributes[U.self],
|
||
run._attributes[V.self],
|
||
run._attributes[W.self],
|
||
range)
|
||
}
|
||
}
|
||
|
||
public func makeIterator() -> Iterator {
|
||
Iterator(self)
|
||
}
|
||
|
||
public var startIndex: Index {
|
||
runs._range.lowerBound
|
||
}
|
||
public var endIndex: Index {
|
||
runs._range.upperBound
|
||
}
|
||
|
||
public func index(before i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
before: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public func index(after i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
after: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public subscript(position: AttributedString.Index) -> Element {
|
||
let (start, runIndex) = runs._slicedRunBoundary(
|
||
roundingDown: position,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
let end = self.index(after: position)
|
||
let attributes = runs._guts.runs[runIndex.rangeIndex].attributes
|
||
return (
|
||
attributes[T.self],
|
||
attributes[U.self],
|
||
attributes[V.self],
|
||
attributes[W.self],
|
||
start ..< end)
|
||
}
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey,
|
||
W : AttributedStringKey
|
||
> (
|
||
_ t: KeyPath<AttributeDynamicLookup, T>,
|
||
_ u: KeyPath<AttributeDynamicLookup, U>,
|
||
_ v: KeyPath<AttributeDynamicLookup, V>,
|
||
_ w: KeyPath<AttributeDynamicLookup, W>
|
||
) -> AttributesSlice4<T, U, V, W> {
|
||
return AttributesSlice4<T, U, V, W>(runs: self)
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey,
|
||
W : AttributedStringKey
|
||
> (
|
||
_ t: T.Type,
|
||
_ u: U.Type,
|
||
_ v: V.Type,
|
||
_ w: W.Type
|
||
) -> AttributesSlice4<T, U, V, W> {
|
||
return AttributesSlice4<T, U, V, W>(runs: self)
|
||
}
|
||
}
|
||
|
||
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
|
||
extension AttributedString.Runs {
|
||
@preconcurrency
|
||
public struct AttributesSlice5<
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey,
|
||
W : AttributedStringKey,
|
||
X : AttributedStringKey
|
||
> : BidirectionalCollection, Sendable
|
||
where
|
||
T.Value : Sendable,
|
||
U.Value : Sendable,
|
||
V.Value : Sendable,
|
||
W.Value : Sendable,
|
||
X.Value : Sendable
|
||
{
|
||
public typealias Index = AttributedString.Index
|
||
|
||
// FIXME: Why no labels?
|
||
public typealias Element = (T.Value?, U.Value?, V.Value?, W.Value?, X.Value?, Range<AttributedString.Index>)
|
||
|
||
internal typealias Runs = AttributedString.Runs
|
||
|
||
let runs : Runs
|
||
let _names: [String]
|
||
let _constraints: [AttributeRunBoundaries]
|
||
|
||
init(runs: Runs) {
|
||
self.runs = runs
|
||
// FIXME: ☠️ Get these from a proper cache in runs._guts.
|
||
_names = [T.name, U.name, V.name, W.name]
|
||
_constraints = Array(
|
||
_contents: T.runBoundaries,
|
||
U.runBoundaries,
|
||
V.runBoundaries,
|
||
W.runBoundaries,
|
||
X.runBoundaries)
|
||
}
|
||
|
||
public struct Iterator: IteratorProtocol, Sendable {
|
||
public typealias Element = AttributesSlice5.Element
|
||
|
||
let _slice: AttributesSlice5
|
||
var _index: AttributedString.Index
|
||
|
||
internal init(_ slice: AttributesSlice5) {
|
||
self._slice = slice
|
||
self._index = slice.startIndex
|
||
}
|
||
|
||
public mutating func next() -> Element? {
|
||
if _index == _slice.endIndex {
|
||
return nil
|
||
}
|
||
let run = _slice.runs[_index]
|
||
let next = _slice.index(after: _index)
|
||
let range = _index ..< next
|
||
_index = next
|
||
return (
|
||
run._attributes[T.self],
|
||
run._attributes[U.self],
|
||
run._attributes[V.self],
|
||
run._attributes[W.self],
|
||
run._attributes[X.self],
|
||
range)
|
||
}
|
||
}
|
||
|
||
public func makeIterator() -> Iterator {
|
||
Iterator(self)
|
||
}
|
||
|
||
public var startIndex: Index {
|
||
runs._range.lowerBound
|
||
}
|
||
public var endIndex: Index {
|
||
runs._range.upperBound
|
||
}
|
||
|
||
public func index(before i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
before: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public func index(after i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
after: i,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
}
|
||
|
||
public subscript(position: AttributedString.Index) -> Element {
|
||
let (start, runIndex) = runs._slicedRunBoundary(
|
||
roundingDown: position,
|
||
attributeNames: _names,
|
||
constraints: _constraints)
|
||
let end = self.index(after: position)
|
||
let attributes = runs._guts.runs[runIndex.rangeIndex].attributes
|
||
return (
|
||
attributes[T.self],
|
||
attributes[U.self],
|
||
attributes[V.self],
|
||
attributes[W.self],
|
||
attributes[X.self],
|
||
start ..< end)
|
||
}
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey,
|
||
W : AttributedStringKey,
|
||
X : AttributedStringKey
|
||
> (
|
||
_ t: KeyPath<AttributeDynamicLookup, T>,
|
||
_ u: KeyPath<AttributeDynamicLookup, U>,
|
||
_ v: KeyPath<AttributeDynamicLookup, V>,
|
||
_ w: KeyPath<AttributeDynamicLookup, W>,
|
||
_ x: KeyPath<AttributeDynamicLookup, X>
|
||
) -> AttributesSlice5<T, U, V, W, X> {
|
||
return AttributesSlice5<T, U, V, W, X>(runs: self)
|
||
}
|
||
|
||
public subscript <
|
||
T : AttributedStringKey,
|
||
U : AttributedStringKey,
|
||
V : AttributedStringKey,
|
||
W : AttributedStringKey,
|
||
X : AttributedStringKey
|
||
> (
|
||
_ t: T.Type,
|
||
_ u: U.Type,
|
||
_ v: V.Type,
|
||
_ w: W.Type,
|
||
_ x: X.Type
|
||
) -> AttributesSlice5<T, U, V, W, X> {
|
||
return AttributesSlice5<T, U, V, W, X>(runs: self)
|
||
}
|
||
}
|
||
|
||
#if FOUNDATION_FRAMEWORK
|
||
|
||
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
|
||
extension AttributedString.Runs {
|
||
@_spi(AttributedString)
|
||
public struct NSAttributesSlice : BidirectionalCollection, Sendable {
|
||
public typealias Index = AttributedString.Index
|
||
|
||
// FIXME: Why no labels?
|
||
public typealias Element = (AttributeContainer, Range<AttributedString.Index>)
|
||
|
||
internal typealias Runs = AttributedString.Runs
|
||
|
||
let runs : Runs
|
||
let keys : [NSAttributedString.Key]
|
||
|
||
private let _names: [String]
|
||
|
||
internal init(runs: Runs, keys: [NSAttributedString.Key]) {
|
||
self.runs = runs
|
||
self.keys = keys
|
||
self._names = keys.map { $0.rawValue }
|
||
}
|
||
|
||
public struct Iterator: IteratorProtocol, Sendable {
|
||
// Note: This is basically equivalent to `IndexingIterator`.
|
||
|
||
public typealias Element = NSAttributesSlice.Element
|
||
|
||
let _slice: NSAttributesSlice
|
||
var _index: AttributedString.Index
|
||
|
||
internal init(_ slice: NSAttributesSlice) {
|
||
self._slice = slice
|
||
self._index = slice.startIndex
|
||
}
|
||
|
||
public mutating func next() -> Element? {
|
||
if _index == _slice.endIndex {
|
||
return nil
|
||
}
|
||
let run = _slice.runs[_index]
|
||
let next = _slice.index(after: _index)
|
||
let range = _index ..< next
|
||
_index = next
|
||
return (_slice.buildContainer(from: run._attributes), range)
|
||
}
|
||
}
|
||
|
||
public func makeIterator() -> Iterator {
|
||
Iterator(self)
|
||
}
|
||
|
||
public var startIndex: Index {
|
||
runs._range.lowerBound
|
||
}
|
||
public var endIndex: Index {
|
||
runs._range.upperBound
|
||
}
|
||
|
||
public func index(before i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
before: i,
|
||
attributeNames: _names,
|
||
constraints: [])
|
||
}
|
||
|
||
public func index(after i: Index) -> Index {
|
||
runs._slicedRunBoundary(
|
||
after: i,
|
||
attributeNames: _names,
|
||
constraints: [])
|
||
}
|
||
|
||
public subscript(position: AttributedString.Index) -> Element {
|
||
let (start, runIndex) = runs._slicedRunBoundary(
|
||
roundingDown: position,
|
||
attributeNames: _names,
|
||
constraints: [])
|
||
let end = self.index(after: position)
|
||
let attributes = runs._guts.runs[runIndex.rangeIndex].attributes
|
||
return (buildContainer(from: attributes), start ..< end)
|
||
}
|
||
|
||
private func buildContainer(from storage: AttributedString._AttributeStorage) -> AttributeContainer {
|
||
AttributeContainer(storage.filter { _names.contains($0.key) })
|
||
}
|
||
}
|
||
|
||
@_spi(AttributedString)
|
||
public subscript(nsAttributedStringKeys keys: NSAttributedString.Key...) -> NSAttributesSlice {
|
||
return NSAttributesSlice(runs: self, keys: keys)
|
||
}
|
||
}
|
||
|
||
#endif // FOUNDATION_FRAMEWORK
|
||
|
||
extension RangeReplaceableCollection {
|
||
internal init(_contents item1: Element?) {
|
||
self.init()
|
||
if let item1 { self.append(item1) }
|
||
}
|
||
|
||
internal init(_contents item1: Element?, _ item2: Element?) {
|
||
self.init()
|
||
var c = 0
|
||
if item1 != nil { c &+= 1 }
|
||
if item2 != nil { c &+= 1 }
|
||
guard c > 0 else { return }
|
||
self.reserveCapacity(c)
|
||
if let item1 { self.append(item1) }
|
||
if let item2 { self.append(item2) }
|
||
}
|
||
|
||
internal init(_contents item1: Element?, _ item2: Element?, _ item3: Element?) {
|
||
self.init()
|
||
var c = 0
|
||
if item1 != nil { c &+= 1 }
|
||
if item2 != nil { c &+= 1 }
|
||
if item3 != nil { c &+= 1 }
|
||
guard c > 0 else { return }
|
||
self.reserveCapacity(c)
|
||
if let item1 { self.append(item1) }
|
||
if let item2 { self.append(item2) }
|
||
if let item3 { self.append(item3) }
|
||
}
|
||
|
||
internal init(
|
||
_contents item1: Element?, _ item2: Element?, _ item3: Element?, _ item4: Element?
|
||
) {
|
||
self.init()
|
||
var c = 0
|
||
if item1 != nil { c &+= 1 }
|
||
if item2 != nil { c &+= 1 }
|
||
if item3 != nil { c &+= 1 }
|
||
if item4 != nil { c &+= 1 }
|
||
guard c > 0 else { return }
|
||
self.reserveCapacity(c)
|
||
if let item1 { self.append(item1) }
|
||
if let item2 { self.append(item2) }
|
||
if let item3 { self.append(item3) }
|
||
if let item4 { self.append(item4) }
|
||
}
|
||
|
||
internal init(
|
||
_contents item1: Element?,
|
||
_ item2: Element?,
|
||
_ item3: Element?,
|
||
_ item4: Element?,
|
||
_ item5: Element?
|
||
) {
|
||
self.init()
|
||
var c = 0
|
||
if item1 != nil { c &+= 1 }
|
||
if item2 != nil { c &+= 1 }
|
||
if item3 != nil { c &+= 1 }
|
||
if item4 != nil { c &+= 1 }
|
||
if item5 != nil { c &+= 1 }
|
||
guard c > 0 else { return }
|
||
self.reserveCapacity(c)
|
||
if let item1 { self.append(item1) }
|
||
if let item2 { self.append(item2) }
|
||
if let item3 { self.append(item3) }
|
||
if let item4 { self.append(item4) }
|
||
if let item5 { self.append(item5) }
|
||
}
|
||
}
|
||
|