File: Path.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 (159 lines) | stat: -rw-r--r-- 6,454 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Foundation

/// A simple representation of a path in the file system.
public struct Path: Hashable {
    private let _string: String

    /// Initializes the path from the contents a string, which should be an
    /// absolute path in platform representation.
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public init(_ string: String) {
        self._string = string
    }

    init(url: URL) {
        self._string = url.path
    }

    /// A string representation of the path.
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public var string: String {
        self._string
    }

    // Note: this avoids duplication warnings for our own code.
    var stringValue: String {
        self._string
    }

    /// The last path component (including any extension).
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public var lastComponent: String {
        // Check for a special case of the root directory.
        if self._string == "/" {
            // Root directory, so the basename is a single path separator (the
            // root directory is special in this regard).
            return "/"
        }
        // Find the last path separator.
        guard let idx = _string.lastIndex(of: "/") else {
            // No path separators, so the basename is the whole string.
            return self._string
        }
        // Otherwise, it's the string from (but not including) the last path
        // separator.
        return String(self._string.suffix(from: self._string.index(after: idx)))
    }

    /// The last path component (without any extension).
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public var stem: String {
        let filename = self.lastComponent
        if let ext = self.extension {
            return String(filename.dropLast(ext.count + 1))
        } else {
            return filename
        }
    }

    /// The filename extension, if any (without any leading dot).
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public var `extension`: String? {
        // Find the last path separator, if any.
        let sIdx = self._string.lastIndex(of: "/")

        // Find the start of the basename.
        let bIdx = (sIdx != nil) ? self._string.index(after: sIdx!) : self._string.startIndex

        // Find the last `.` (if any), starting from the second character of
        // the basename (a leading `.` does not make the whole path component
        // a suffix).
        let fIdx = self._string.index(bIdx, offsetBy: 1, limitedBy: self._string.endIndex) ?? self._string.startIndex
        if let idx = _string[fIdx...].lastIndex(of: ".") {
            // Unless it's just a `.` at the end, we have found a suffix.
            if self._string.distance(from: idx, to: self._string.endIndex) > 1 {
                return String(self._string.suffix(from: self._string.index(idx, offsetBy: 1)))
            }
        }
        // If we get this far, there is no suffix.
        return nil
    }

    /// The path except for the last path component.
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public func removingLastComponent() -> Path {
        // Find the last path separator.
        guard let idx = string.lastIndex(of: "/") else {
            // No path separators, so the directory name is `.`.
            return Path(".")
        }
        // Check if it's the only one in the string.
        if idx == self.string.startIndex {
            // Just one path separator, so the directory name is `/`.
            return Path("/")
        }
        // Otherwise, it's the string up to (but not including) the last path
        // separator.
        return Path(String(self._string.prefix(upTo: idx)))
    }

    /// The result of appending a subpath, which should be a relative path in
    /// platform representation.
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public func appending(subpath: String) -> Path {
        Path(self._string + (self._string.hasSuffix("/") ? "" : "/") + subpath)
    }

    /// The result of appending one or more path components.
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public func appending(_ components: [String]) -> Path {
        self.appending(subpath: components.joined(separator: "/"))
    }

    /// The result of appending one or more path components.
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public func appending(_ components: String...) -> Path {
        self.appending(components)
    }
}

extension Path: CustomStringConvertible {
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public var description: String {
        self.string
    }
}

extension Path: Codable {
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.string)
    }

    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let string = try container.decode(String.self)
        self.init(string)
    }
}

extension String.StringInterpolation {
    @available(_PackageDescription, deprecated: 6.0, message: "Use `URL` type instead of `Path`.")
    public mutating func appendInterpolation(_ path: Path) {
        self.appendInterpolation(path.string)
    }
}