From f6719035ccddf78e5fcd14ad09cc68f53a06b4ad Mon Sep 17 00:00:00 2001 From: Natik Gadzhi Date: Sun, 12 Jan 2025 17:54:26 -0800 Subject: [PATCH 1/3] feat: Add `String(contentsOf: FilePath ...)` Motivation: Makes it possible to read contents of an NIOFileSystem.FilePath into a String directly. Modifications: - Added a new `String+FileSystem.swift` into `NIOFileSystem` target. - Added basic tests to the existing `ConvenienceTests.swift`. - Added a test to cover `Array+FileSystem` initializer as well. Result: - String initializer for `FilePath` is now available - Array initializer for `FilePath` now has a test --- Sources/NIOFileSystem/String+FileSystem.swift | 56 +++++++++++++++++++ .../ConvenienceTests.swift | 27 +++++++++ 2 files changed, 83 insertions(+) create mode 100644 Sources/NIOFileSystem/String+FileSystem.swift diff --git a/Sources/NIOFileSystem/String+FileSystem.swift b/Sources/NIOFileSystem/String+FileSystem.swift new file mode 100644 index 0000000000..36459dc0c1 --- /dev/null +++ b/Sources/NIOFileSystem/String+FileSystem.swift @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftNIO open source project +// +// Copyright (c) 2024 Apple Inc. and the SwiftNIO project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftNIO project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import NIOCore + +@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) +extension String { + /// Reads the contents of the file at the path into a String. + /// + /// - Parameters: + /// - path: The path of the file to read. + /// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``. If the file is larger than this, an error is thrown. + /// - fileSystem: The ``FileSystemProtocol`` instance to use to read the file. + /// + /// - Throws: If the file is larger than `maximumSizeAllowed`, an ``FileSystemError.resourceExhausted`` error will be thrown. + public init( + contentsOf path: FilePath, + maximumSizeAllowed: ByteCount, + fileSystem: some FileSystemProtocol + ) async throws { + let byteBuffer = try await fileSystem.withFileHandle(forReadingAt: path) { handle in + try await handle.readToEnd(maximumSizeAllowed: maximumSizeAllowed) + } + + self = Self(buffer: byteBuffer) + } + + /// Reads the contents of the file at the path using ``FileSystem``. + /// + /// - Parameters: + /// - path: The path of the file to read. + /// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``. If the file is larger than this, an error is thrown. + /// + /// - Throws: If the file is larger than `maximumSizeAllowed`, an ``FileSystemError.resourceExhausted`` error will be thrown. + public init( + contentsOf path: FilePath, + maximumSizeAllowed: ByteCount + ) async throws { + self = try await Self( + contentsOf: path, + maximumSizeAllowed: maximumSizeAllowed, + fileSystem: .shared + ) + } +} diff --git a/Tests/NIOFileSystemIntegrationTests/ConvenienceTests.swift b/Tests/NIOFileSystemIntegrationTests/ConvenienceTests.swift index 85a09505df..de9a609485 100644 --- a/Tests/NIOFileSystemIntegrationTests/ConvenienceTests.swift +++ b/Tests/NIOFileSystemIntegrationTests/ConvenienceTests.swift @@ -70,4 +70,31 @@ final class ConvenienceTests: XCTestCase { let bytes = try await ByteBuffer(contentsOf: path, maximumSizeAllowed: .bytes(1024)) XCTAssertEqual(bytes, ByteBuffer(bytes: Array(0..<64))) } + + // MARK: - String + FileSystem + + func testStringFromFullFile() async throws { + let path = try await Self.fs.temporaryFilePath() + try await "some text".write(toFileAt: path) + + let string = try await String(contentsOf: path, maximumSizeAllowed: .bytes(1024)) + XCTAssertEqual(string, "some text") + } + + func testStringFromPartOfAFile() async throws { + let path = try await Self.fs.temporaryFilePath() + try await "some text".write(toFileAt: path) + + await XCTAssertThrowsFileSystemErrorAsync { + try await String(contentsOf: path, maximumSizeAllowed: .bytes(4)) + } + } + + // MARK: - Array + FileSystem + func testArrayFromFullFile() async throws { + let path = try await Self.fs.temporaryFilePath() + try await Array("some text".utf8).write(toFileAt: path) + let array = try await Array(contentsOf: path, maximumSizeAllowed: .bytes(1024)) + XCTAssertEqual(array, Array("some text".utf8)) + } } From 0fe80bcca713b7ce99dc270de73279a43fd69b14 Mon Sep 17 00:00:00 2001 From: Natik Gadzhi Date: Mon, 13 Jan 2025 19:25:36 -0800 Subject: [PATCH 2/3] fix docc comment reference --- Sources/NIOFileSystem/String+FileSystem.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/NIOFileSystem/String+FileSystem.swift b/Sources/NIOFileSystem/String+FileSystem.swift index 36459dc0c1..90f3986785 100644 --- a/Sources/NIOFileSystem/String+FileSystem.swift +++ b/Sources/NIOFileSystem/String+FileSystem.swift @@ -23,7 +23,7 @@ extension String { /// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``. If the file is larger than this, an error is thrown. /// - fileSystem: The ``FileSystemProtocol`` instance to use to read the file. /// - /// - Throws: If the file is larger than `maximumSizeAllowed`, an ``FileSystemError.resourceExhausted`` error will be thrown. + /// - Throws: If the file is larger than `maximumSizeAllowed`, an ``FileSystemError/Code-swift.struct/resourceExhausted`` error will be thrown. public init( contentsOf path: FilePath, maximumSizeAllowed: ByteCount, @@ -42,7 +42,7 @@ extension String { /// - path: The path of the file to read. /// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``. If the file is larger than this, an error is thrown. /// - /// - Throws: If the file is larger than `maximumSizeAllowed`, an ``FileSystemError.resourceExhausted`` error will be thrown. + /// - Throws: If the file is larger than `maximumSizeAllowed`, an ``FileSystemError/Code-swift.struct/resourceExhausted`` error will be thrown. public init( contentsOf path: FilePath, maximumSizeAllowed: ByteCount From 129077aaa463aab626567d21aad803f2d5417f7c Mon Sep 17 00:00:00 2001 From: Natik Gadzhi Date: Tue, 14 Jan 2025 09:18:29 -0800 Subject: [PATCH 3/3] Update Sources/NIOFileSystem/String+FileSystem.swift --- Sources/NIOFileSystem/String+FileSystem.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/NIOFileSystem/String+FileSystem.swift b/Sources/NIOFileSystem/String+FileSystem.swift index 90f3986785..57e2d51c0b 100644 --- a/Sources/NIOFileSystem/String+FileSystem.swift +++ b/Sources/NIOFileSystem/String+FileSystem.swift @@ -2,7 +2,7 @@ // // This source file is part of the SwiftNIO open source project // -// Copyright (c) 2024 Apple Inc. and the SwiftNIO project authors +// Copyright (c) 2025 Apple Inc. and the SwiftNIO project authors // Licensed under Apache License v2.0 // // See LICENSE.txt for license information