-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Fix chunk upload in Swift (box/box-codegen#555) (#215)
- Loading branch information
1 parent
3daadf7
commit 93ff568
Showing
11 changed files
with
288 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{ "engineHash": "6cf3f9e", "specHash": "57614c2", "version": "0.3.1" } | ||
{ "engineHash": "2994c4a", "specHash": "739d87b", "version": "0.3.1" } |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import Foundation | ||
|
||
/// A custom `InputStream` implementation that reads data from an in-memory `Data` object. | ||
class MemoryInputStream: InputStream { | ||
private var data: Data | ||
private var position: Int = 0 | ||
private var _streamStatus: Stream.Status | ||
private var _streamError: Error? | ||
private var _delegate: StreamDelegate? | ||
|
||
/// Initializes a new `MemoryInputStream` with the provided data. | ||
/// - Parameter data: The `Data` object containing the data to be read. | ||
override init(data: Data) { | ||
self.data = data | ||
self._streamStatus = .notOpen | ||
super.init(data: Data()) | ||
} | ||
|
||
/// Reads up to a specified number of bytes into the provided buffer. | ||
/// - Parameters: | ||
/// - buffer: A buffer to which the data will be read. | ||
/// - len: The maximum number of bytes to read. | ||
/// - Returns: The number of bytes actually read, or `-1` if an error occurred or the stream is not open. | ||
override func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength len: Int) -> Int { | ||
guard _streamStatus == .open else { | ||
return -1 // Stream must be open to read | ||
} | ||
|
||
// If we've reached the end of the buffer, mark the stream as atEnd | ||
if position >= data.count { | ||
_streamStatus = .atEnd | ||
return 0 | ||
} | ||
|
||
// Calculate the number of bytes to read | ||
let bytesToRead = min(len, data.count - position) | ||
|
||
// Copy data to the buffer | ||
let range = position..<position + bytesToRead | ||
data.copyBytes(to: buffer, from: range) | ||
|
||
// Update the position | ||
position += bytesToRead | ||
|
||
if position >= data.count { | ||
_streamStatus = .atEnd | ||
} | ||
|
||
return bytesToRead | ||
} | ||
|
||
/// Indicates whether there are bytes available to read. | ||
/// - Returns: `true` if there are bytes available and the stream is open; otherwise, `false`. | ||
override var hasBytesAvailable: Bool { | ||
return position < data.count && _streamStatus == .open | ||
} | ||
|
||
/// Closes the stream, marking the end of the data. | ||
override func close() { | ||
position = data.count | ||
_streamStatus = .closed | ||
} | ||
|
||
/// Resets the stream to its initial state. | ||
/// The position is reset to the beginning of the data and the stream status is set to not open. | ||
func reset() { | ||
position = 0 | ||
_streamStatus = .notOpen | ||
} | ||
|
||
/// Opens the stream for reading. | ||
/// The position is reset to the beginning of the data and the stream status is set to open. | ||
override func open() { | ||
position = 0 | ||
_streamStatus = .open | ||
} | ||
|
||
/// The current status of the stream. | ||
override var streamStatus: Stream.Status { | ||
return _streamStatus | ||
} | ||
|
||
/// The error encountered by the stream, if any. | ||
override var streamError: Error? { | ||
return _streamError | ||
} | ||
|
||
/// The delegate of the stream. | ||
override var delegate: StreamDelegate? { | ||
get { | ||
return _delegate | ||
} | ||
set { | ||
_delegate = newValue | ||
} | ||
} | ||
|
||
/// Schedules the stream in a run loop. This method does nothing in this implementation. | ||
/// - Parameters: | ||
/// - runLoop: The run loop in which to schedule the stream. | ||
/// - mode: The run loop mode in which to schedule the stream. | ||
override func schedule(in _: RunLoop, forMode _: RunLoop.Mode) {} | ||
|
||
/// Removes the stream from a run loop. This method does nothing in this implementation. | ||
/// - Parameters: | ||
/// - runLoop: The run loop from which to remove the stream. | ||
/// - mode: The run loop mode from which to remove the stream. | ||
override func remove(from _: RunLoop, forMode _: RunLoop.Mode) {} | ||
|
||
#if os(iOS) || os(macOS) | ||
/// Returns the value of a specified property key. This method always returns `nil` in this implementation. | ||
/// - Parameter key: The property key. | ||
/// - Returns: `nil`. | ||
override func property(forKey _: Stream.PropertyKey) -> Any? { | ||
return nil | ||
} | ||
|
||
/// Sets the value of a specified property key. This method always returns `false` in this implementation. | ||
/// - Parameters: | ||
/// - property: The property value to set. | ||
/// - key: The property key. | ||
/// - Returns: `false`. | ||
override func setProperty(_: Any?, forKey _: Stream.PropertyKey) -> Bool { | ||
return false | ||
} | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import Foundation | ||
|
||
/// A `Sequence` that reads data from an `InputStream` in chunks. | ||
/// Conforms to the `Sequence` protocol and provides an iterator that yields chunks of data from the stream. | ||
public struct StreamSequence: Sequence { | ||
/// The type of elements that this sequence yields. | ||
public typealias Element = InputStream | ||
|
||
/// The `InputStream` to read data from. | ||
private let inputStream: InputStream | ||
|
||
/// The size of each chunk to read from the `InputStream`. | ||
private let chunkSize: Int | ||
|
||
/// Initializes a `StreamSequence` with the given `InputStream` and chunk size. | ||
/// | ||
/// - Parameters: | ||
/// - inputStream: The `InputStream` to read data from. | ||
/// - chunkSize: The size of each chunk to read from the `InputStream`. | ||
init(inputStream: InputStream, chunkSize: Int) { | ||
self.inputStream = inputStream | ||
self.chunkSize = chunkSize | ||
} | ||
|
||
/// Creates and returns an iterator for this sequence. | ||
/// | ||
/// - Returns: A `StreamIterator` that reads data from the `InputStream` in chunks. | ||
public func makeIterator() -> StreamIterator { | ||
return StreamIterator(inputStream: inputStream, chunkSize: chunkSize) | ||
} | ||
} | ||
|
||
/// An iterator that reads data from an `InputStream` in chunks. | ||
/// Conforms to the `IteratorProtocol` and yields chunks of data as `InputStream` objects. | ||
public struct StreamIterator: IteratorProtocol { | ||
/// The type of elements that this iterator yields. | ||
public typealias Element = InputStream | ||
|
||
/// The `InputStream` to read data from. | ||
private let inputStream: InputStream | ||
|
||
/// The size of each chunk to read from the `InputStream`. | ||
private let chunkSize: Int | ||
|
||
/// A buffer to hold data read from the `InputStream`. | ||
private var buffer: [UInt8] | ||
|
||
/// A flag indicating whether there is more data to read from the `InputStream`. | ||
private var hasMoreData: Bool | ||
|
||
/// Initializes a `StreamIterator` with the given `InputStream` and chunk size. | ||
/// | ||
/// - Parameters: | ||
/// - inputStream: The `InputStream` to read data from. | ||
/// - chunkSize: The size of each chunk to read from the `InputStream`. | ||
init(inputStream: InputStream, chunkSize: Int) { | ||
self.inputStream = inputStream | ||
self.chunkSize = chunkSize | ||
self.buffer = [UInt8](repeating: 0, count: chunkSize) | ||
self.hasMoreData = true | ||
|
||
// Open the input stream for reading. | ||
inputStream.open() | ||
} | ||
|
||
/// Reads the next chunk of data from the `InputStream` and returns it as an `InputStream`. | ||
/// | ||
/// - Returns: An `InputStream` containing the next chunk of data, or `nil` if no more data is available. | ||
public mutating func next() -> InputStream? { | ||
guard hasMoreData else { return nil } | ||
|
||
// Read data into the buffer. | ||
let bytesRead = inputStream.read(&buffer, maxLength: chunkSize) | ||
|
||
if bytesRead > 0 { | ||
// Create and return an `InputStream` containing the read data. | ||
return MemoryInputStream(data: Data(bytes: buffer, count: bytesRead)) | ||
} else { | ||
// No more data to read. | ||
hasMoreData = false | ||
inputStream.close() | ||
return nil | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.