File: FileHelpers.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (122 lines) | stat: -rw-r--r-- 4,293 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 This source file is part of the Swift System open source project

 Copyright (c) 2020 Apple Inc. and the Swift System project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
*/

/*System 0.0.1, @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)*/
extension FileDescriptor {
  /// Runs a closure and then closes the file descriptor, even if an error occurs.
  ///
  /// - Parameter body: The closure to run.
  ///   If the closure throws an error,
  ///   this method closes the file descriptor before it rethrows that error.
  ///
  /// - Returns: The value returned by the closure.
  ///
  /// If `body` throws an error
  /// or an error occurs while closing the file descriptor,
  /// this method rethrows that error.
  public func closeAfter<R>(_ body: () throws -> R) throws -> R {
    // No underscore helper, since the closure's throw isn't necessarily typed.
    let result: R
    do {
      result = try body()
    } catch {
      _ = try? self.close() // Squash close error and throw closure's
      throw error
    }
    try self.close()
    return result
  }

  /// Writes a sequence of bytes to the current offset
  /// and then updates the offset.
  ///
  /// - Parameter sequence: The bytes to write.
  /// - Returns: The number of bytes written, equal to the number of elements in `sequence`.
  ///
  /// This method either writes the entire contents of `sequence`,
  /// or throws an error if only part of the content was written.
  ///
  /// Writes to the position associated with this file descriptor, and
  /// increments that position by the number of bytes written.
  /// See also ``seek(offset:from:)``.
  ///
  /// If `sequence` doesn't implement
  /// the <doc://com.apple.documentation/documentation/swift/sequence/3128824-withcontiguousstorageifavailable> method,
  /// temporary space will be allocated as needed.
  @_alwaysEmitIntoClient
  @discardableResult
  public func writeAll<S: Sequence>(
    _ sequence: S
  ) throws -> Int where S.Element == UInt8 {
    return try _writeAll(sequence).get()
  }

  @usableFromInline
  internal func _writeAll<S: Sequence>(
    _ sequence: S
  ) -> Result<Int, Errno> where S.Element == UInt8 {
    sequence._withRawBufferPointer { buffer in
      var idx = 0
      while idx < buffer.count {
        switch _write(
          UnsafeRawBufferPointer(rebasing: buffer[idx...]), retryOnInterrupt: true
        ) {
        case .success(let numBytes): idx += numBytes
        case .failure(let err): return .failure(err)
        }
      }
      assert(idx == buffer.count)
      return .success(buffer.count)
    }
  }

  /// Writes a sequence of bytes to the given offset.
  ///
  /// - Parameters:
  ///   - offset: The file offset where writing begins.
  ///   - sequence: The bytes to write.
  /// - Returns: The number of bytes written, equal to the number of elements in `sequence`.
  ///
  /// This method either writes the entire contents of `sequence`,
  /// or throws an error if only part of the content was written.
  /// Unlike ``writeAll(_:)``,
  /// this method preserves the file descriptor's existing offset.
  ///
  /// If `sequence` doesn't implement
  /// the <doc://com.apple.documentation/documentation/swift/sequence/3128824-withcontiguousstorageifavailable> method,
  /// temporary space will be allocated as needed.
  @_alwaysEmitIntoClient
  @discardableResult
  public func writeAll<S: Sequence>(
    toAbsoluteOffset offset: Int64, _ sequence: S
  ) throws -> Int where S.Element == UInt8 {
    try _writeAll(toAbsoluteOffset: offset, sequence).get()
  }

  @usableFromInline
  internal func _writeAll<S: Sequence>(
    toAbsoluteOffset offset: Int64, _ sequence: S
  ) -> Result<Int, Errno> where S.Element == UInt8 {
    sequence._withRawBufferPointer { buffer in
      var idx = 0
      while idx < buffer.count {
        switch _write(
          toAbsoluteOffset: offset + Int64(idx),
          UnsafeRawBufferPointer(rebasing: buffer[idx...]),
          retryOnInterrupt: true
        ) {
        case .success(let numBytes): idx += numBytes
        case .failure(let err): return .failure(err)
        }
      }
      assert(idx == buffer.count)
      return .success(buffer.count)
    }
  }
}