You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Similarly, `String`s can be created from `UTF8Span`s without re-validating their contents.
213
+
214
+
```swift
215
+
extensionString {
216
+
/// Create's a String containing a copy of the UTF-8 content in `codeUnits`.
217
+
/// Skips
218
+
/// validation.
219
+
publicinit(copyingcodeUnits: UTF8Span)
211
220
}
212
221
```
213
222
@@ -217,7 +226,7 @@ We propose a `UTF8Span.UnicodeScalarIterator` type that can do scalar processing
217
226
218
227
```swift
219
228
extensionUTF8Span {
220
-
/// Returns an iterator that will decode the code units into
229
+
/// Returns an iterator that will decode the code units into
221
230
/// `Unicode.Scalar`s.
222
231
///
223
232
/// The resulting iterator has the same lifetime constraints as `self`.
@@ -315,7 +324,7 @@ extension UTF8Span {
315
324
316
325
We similarly propose a `UTF8Span.CharacterIterator` type that can do grapheme-breaking forwards and backwards.
317
326
318
-
The `CharacterIterator` assumes that the start and end of the `UTF8Span` is the start and end of content.
327
+
The `CharacterIterator` assumes that the start and end of the `UTF8Span` is the start and end of content.
319
328
320
329
Any scalar-aligned position is a valid place to start or reset the grapheme-breaking algorithm to, though you could get different `Character` output if resetting to a position that isn't `Character`-aligned relative to the start of the `UTF8Span` (e.g. in the middle of a series of regional indicators).
321
330
@@ -342,15 +351,15 @@ extension UTF8Span {
342
351
/// Return the `Character` starting at `currentCodeUnitOffset`. After the
343
352
/// function returns, `currentCodeUnitOffset` holds the position at the
344
353
/// end of the `Character`, which is also the start of the next
345
-
/// `Character`.
354
+
/// `Character`.
346
355
///
347
356
/// Returns `nil` if at the end of the `UTF8Span`.
348
357
publicmutatingfuncnext() ->Character?
349
358
350
359
/// Return the `Character` ending at `currentCodeUnitOffset`. After the
351
360
/// function returns, `currentCodeUnitOffset` holds the position at the
352
361
/// start of the returned `Character`, which is also the end of the
353
-
/// previous `Character`.
362
+
/// previous `Character`.
354
363
///
355
364
/// Returns `nil` if at the start of the `UTF8Span`.
356
365
publicmutatingfuncprevious() ->Character?
@@ -394,7 +403,7 @@ extension UTF8Span {
394
403
///
395
404
/// Note: This is only for very specific, low-level use cases. If
396
405
/// `codeUnitOffset` is not properly scalar-aligned, this function can
397
-
/// result in undefined behavior when, e.g., `next()` is called.
406
+
/// result in undefined behavior when, e.g., `next()` is called.
398
407
///
399
408
/// If `i` is scalar-aligned, but not `Character`-aligned, you may get
400
409
/// different results from running `Character` iteration.
@@ -444,13 +453,6 @@ extension UTF8Span {
444
453
}
445
454
```
446
455
447
-
We also support literal (i.e. non-canonical) pattern matching against `StaticString`.
/// Whether `self` orders less than `other` under Unicode Canonical
468
470
/// Equivalence using normalized code-unit order (in NFC).
469
-
publicfuncisCanonicallyLessThan(
471
+
publicfunccanonicallyPrecedes(
470
472
_other: UTF8Span
471
473
) ->Bool
472
474
}
@@ -482,17 +484,17 @@ Slicing a `UTF8Span` is nuanced and depends on the caller's desired use. They ca
482
484
483
485
```swift
484
486
extensionUTF8Span {
485
-
/// Returns whether contents are known to be all-ASCII. A return value of
486
-
/// `true` means that all code units are ASCII. A return value of `false`
487
+
/// Returns whether contents are known to be all-ASCII. A return value of
488
+
/// `true` means that all code units are ASCII. A return value of `false`
487
489
/// means there _may_ be non-ASCII content.
488
490
///
489
491
/// ASCII-ness is checked and remembered during UTF-8 validation, so this
490
-
/// is often equivalent to is-ASCII, but there are some situations where
492
+
/// is often equivalent to is-ASCII, but there are some situations where
491
493
/// we might return `false` even when the content happens to be all-ASCII.
492
494
///
493
-
/// For example, a UTF-8 span generated from a `String` that at some point
494
-
/// contained non-ASCII content would report false for `isKnownASCII`, even
495
-
/// if that String had subsequent mutation operations that removed any
495
+
/// For example, a UTF-8 span generated from a `String` that at some point
496
+
/// contained non-ASCII content would report false for `isKnownASCII`, even
497
+
/// if that String had subsequent mutation operations that removed any
496
498
/// non-ASCII content.
497
499
publicvar isKnownASCII: Bool { get }
498
500
@@ -620,16 +622,24 @@ extension UTF8Span {
620
622
```
621
623
622
624
623
-
624
625
### More alignments and alignment queries
625
626
626
627
Future API could include word iterators (either [simple](https://www.unicode.org/reports/tr18/#Simple_Word_Boundaries) or [default](https://www.unicode.org/reports/tr18/#Default_Word_Boundaries)), line iterators, etc.
627
628
628
629
Similarly, we could add API directly to `UTF8Span` for testing whether a given code unit offset is suitably aligned (including scalar or grapheme-cluster alignment checks).
629
630
631
+
### `~=` and other operators
632
+
633
+
`UTF8Span` supports both binary equivalence and Unicode canonical equivalence. For example, a textual format parser using `UTF8Span` might operate in terms of binary equivalence for processing the textual format itself and then in terms of Unicode canonical equivalnce when interpreting the content of the fields.
634
+
635
+
We are deferring making any decision on what a "default" comparison semantics should be as future work, which would include defining a `~=` operator (which would allow one to switch over a `UTF8Span` and match against literals).
636
+
637
+
It may also be the case that it makes more sense for a library or application to define wrapper types around `UTF8Span` which can define `~=` with their preferred comparison semantics.
638
+
639
+
630
640
### Creating `String` copies
631
641
632
-
We could add an initializer to `String` that makes an owned copy of a `UTF8Span`'s contents. Such an initializer can skip UTF-8 validation.
642
+
We could add an initializer to `String` that makes an owned copy of a `UTF8Span`'s contents. Such an initializer can skip UTF-8 validation.
633
643
634
644
Alternatively, we could defer adding anything until more of the `Container` protocol story is clear.
635
645
@@ -639,7 +649,7 @@ Future API could include checks for whether the content is in a particular norma
639
649
640
650
### UnicodeScalarView and CharacterView
641
651
642
-
Like `Span`, we are deferring adding any collection-like types to non-escapable `UTF8Span`. Future work could include adding view types that conform to a new `Container`-like protocol.
652
+
Like `Span`, we are deferring adding any collection-like types to non-escapable `UTF8Span`. Future work could include adding view types that conform to a new `Container`-like protocol.
643
653
644
654
See "Alternatives Considered" below for more rationale on not adding `Collection`-like API in this proposal.
645
655
@@ -694,6 +704,26 @@ Many printing and logging protocols and facilities operate in terms of `String`.
694
704
695
705
## Alternatives considered
696
706
707
+
### Problems arising from the unsafe init
708
+
709
+
The combination of the unsafe init on `UTF8Span` and the copying init on `String` creates a new kind of easily-accesible backdoor to `String`'s security and safety, namely the invariant that it holds validly encoded UTF-8 when in native form.
710
+
711
+
Currently, String is 100% safe outside of crazy custom subclass shenanigans (only on ObjC platforms) or arbitrarily scribbling over memory (which is true of all of Swift). Both are highly visible and require writing many lines of advanced-knowledge code.
712
+
713
+
Without these two API, it is in theory possible to skip validation and produce a String instance of the [indirect contiguous UTF-8](https://forums.swift.org/t/piercing-the-string-veil/21700) flavor through a custom subclass of NSString. But, it is only available on Obj-C platforms and involves creating a custom subclass of `NSString`, having knowledge of lazy bridging internals (which can and sometimes do change from release to release of Swift), and writing very specialized code. The product would be an unsafe lazily bridged instance of `String`, which could more than offset any performance gains from the workaround itself.
714
+
715
+
With these two API, you can get to UB via a:
716
+
717
+
```swift
718
+
let codeUnits = unsafe UTF8Span(unsafeAssumingValidUTF8: bytes)
719
+
...
720
+
String(copying: codeUnits)
721
+
```
722
+
723
+
We are (very) weakly in favor of keeping the unsafe init, because there are many low-level situations in which the valid-UTF8 invariant is held by the system itself (such as a data structure using a custom allocator).
724
+
725
+
726
+
697
727
### Invalid start / end of input UTF-8 encoding errors
698
728
699
729
Earlier prototypes had `.invalidStartOfInput` and `.invalidEndOfInput` UTF8 validation errors to communicate that the input was perhaps incomplete or not slices along scalar boundaries. In this scenario, `.invalidStartOfInput` is equivalent to `.unexpectedContinuation` with the range's lower bound equal to 0 and `.invalidEndOfInput` is equivalent to `.truncatedScalar` with the range's upper bound equal to `count`.
@@ -764,7 +794,7 @@ Scalar-alignment can still be checked and managed by the caller through the `res
764
794
765
795
#### View Collections
766
796
767
-
Another forumulation of these operations could be to provide a collection-like API phrased in terms of indices. Because `Collection`s are `Escapable`, we cannot conform nested `View` types to `Collection` so these would not benefit from any `Collection`-generic code, algorithms, etc.
797
+
Another forumulation of these operations could be to provide a collection-like API phrased in terms of indices. Because `Collection`s are `Escapable`, we cannot conform nested `View` types to `Collection` so these would not benefit from any `Collection`-generic code, algorithms, etc.
768
798
769
799
A benefit of such `Collection`-like views is that it could help serve as adapter code for migration. Existing `Collection`-generic algorithms and methods could be converted to support `UTF8Span` via copy-paste-edit. That is, a developer could interact with `UTF8Span` ala:
0 commit comments