Skip to content

Commit

Permalink
PassiveDataReader: Now uses throws instead of returning Optionals
Browse files Browse the repository at this point in the history
  • Loading branch information
orchetect committed Aug 18, 2022
1 parent 40aeaa0 commit bf0eed0
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 71 deletions.
34 changes: 21 additions & 13 deletions Sources/OTCore/Abstractions/PassiveDataReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,34 +53,34 @@ public struct PassiveDataReader<D: DataProtocol> {
/// Return the next byte and increment the read offset.
///
/// If no bytes remain, `nil` will be returned.
public mutating func readByte() -> D.Element? {
guard let d = dataByte() else { return nil }
public mutating func readByte() throws -> D.Element {
let d = try dataByte()
defer { readOffset += 1 }
return d
}

/// Read the next byte without advancing the read offset.
/// If no bytes remain, `nil` will be returned.
public func nonAdvancingReadByte() -> D.Element? {
dataByte()
public func nonAdvancingReadByte() throws -> D.Element {
try dataByte()
}

/// Return the next _n_ number of bytes and increment the read offset.
///
/// If `bytes` parameter is nil, the remainder of the data will be returned.
///
/// If fewer bytes remain than are requested, `nil` will be returned.
public mutating func read(bytes count: Int? = nil) -> D.SubSequence? {
guard let d = data(bytes: count) else { return nil }
public mutating func read(bytes count: Int? = nil) throws -> D.SubSequence {
let d = try data(bytes: count)
defer { readOffset += d.advanceCount }
return d.data
}

/// Read _n_ number of bytes from the current read offset, without advancing the read offset.
/// If `bytes count` passed is `nil`, the remainder of the data will be returned.
/// If fewer bytes remain than are requested, `nil` will be returned.
public func nonAdvancingRead(bytes count: Int? = nil) -> D.SubSequence? {
data(bytes: count)?.data
public func nonAdvancingRead(bytes count: Int? = nil) throws -> D.SubSequence {
try data(bytes: count).data
}

// MARK: - Internal
Expand All @@ -91,19 +91,19 @@ public struct PassiveDataReader<D: DataProtocol> {
return out
}

func dataByte() -> D.Element? {
guard remainingByteCount > 0 else { return nil }
func dataByte() throws -> D.Element {
guard remainingByteCount > 0 else { throw ReadError.pastEndOfStream }
let readPosIndex = withData { $0.index($0.startIndex, offsetBy: readOffset) }
return withData { $0[readPosIndex] }
}

func data(bytes count: Int? = nil) -> (data: D.SubSequence, advanceCount: Int)? {
func data(bytes count: Int? = nil) throws -> (data: D.SubSequence, advanceCount: Int) {
if count == 0 {
return (data: withData { $0[$0.startIndex ..< $0.startIndex] }, advanceCount: 0)
}

if let count = count,
count < 0 { return nil }
count < 0 { throw ReadError.invalidByteCount }

let readPosStartIndex = withData { $0.index($0.startIndex, offsetBy: readOffset) }

Expand All @@ -113,14 +113,22 @@ public struct PassiveDataReader<D: DataProtocol> {

guard withData({
$0.indices.contains(readPosStartIndex) && $0.indices.contains(endIndex)
}) else { return nil }
}) else { throw ReadError.pastEndOfStream }

let returnBytes = withData { $0[readPosStartIndex ... endIndex] }

return (data: returnBytes, advanceCount: count)
}
}

extension PassiveDataReader {
/// Error returned by `PassiveDataReader` methods.
public enum ReadError: Error {
case pastEndOfStream
case invalidByteCount
}
}

extension DataProtocol {
/// **OTCore:**
/// Accesses the data by providing a `PassiveDataReader` instance to a closure.
Expand Down
116 changes: 58 additions & 58 deletions Tests/OTCoreTests/Abstractions/PassiveDataReader Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {

XCTAssertEqual(dr.readOffset, 0)
XCTAssertEqual(dr.remainingByteCount, 4)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.remainingByteCount, 3)
XCTAssertEqual(dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(dr.remainingByteCount, 2)
XCTAssertEqual(dr.read(bytes: 1), Data([0x03]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x03]))
XCTAssertEqual(dr.remainingByteCount, 1)
XCTAssertEqual(dr.read(bytes: 1), Data([0x04]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x04]))
XCTAssertEqual(dr.remainingByteCount, 0)
XCTAssertEqual(dr.read(bytes: 1), nil)
XCTAssertThrowsError(try dr.read(bytes: 1))
XCTAssertEqual(dr.remainingByteCount, 0)
}

Expand All @@ -39,38 +39,38 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {

XCTAssertEqual(dr.readOffset, 0)
XCTAssertEqual(dr.remainingByteCount, 4)
XCTAssertEqual(dr.readByte(), 0x01)
XCTAssertEqual(try dr.readByte(), 0x01)
XCTAssertEqual(dr.remainingByteCount, 3)
XCTAssertEqual(dr.readByte(), 0x02)
XCTAssertEqual(try dr.readByte(), 0x02)
XCTAssertEqual(dr.remainingByteCount, 2)
XCTAssertEqual(dr.readByte(), 0x03)
XCTAssertEqual(try dr.readByte(), 0x03)
XCTAssertEqual(dr.remainingByteCount, 1)
XCTAssertEqual(dr.readByte(), 0x04)
XCTAssertEqual(try dr.readByte(), 0x04)
XCTAssertEqual(dr.remainingByteCount, 0)
XCTAssertEqual(dr.readByte(), nil)
XCTAssertThrowsError(try dr.readByte())
XCTAssertEqual(dr.remainingByteCount, 0)
}

// .read - nil read - return all remaining bytes
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(), data)
XCTAssertEqual(dr.read(bytes: 1), nil)
XCTAssertEqual(try dr.read(), data)
XCTAssertThrowsError(try dr.read(bytes: 1))
}

// .read - zero count read - return empty data, not nil
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(bytes: 0), Data())
XCTAssertEqual(try dr.read(bytes: 0), Data())
}

// .read - read overflow - return nil
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(bytes: 5), nil)
XCTAssertThrowsError(try dr.read(bytes: 5))
}
}

Expand All @@ -81,34 +81,34 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingRead(), data)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.nonAdvancingRead(), data)
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
}

// single bytes
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingReadByte(), data[0])
XCTAssertEqual(dr.nonAdvancingReadByte(), data[0])
XCTAssertEqual(dr.readByte(), data[0])
XCTAssertEqual(dr.readByte(), data[1])
XCTAssertEqual(try dr.nonAdvancingReadByte(), data[0])
XCTAssertEqual(try dr.nonAdvancingReadByte(), data[0])
XCTAssertEqual(try dr.readByte(), data[0])
XCTAssertEqual(try dr.readByte(), data[1])
}

// .nonAdvancingRead - read byte counts
do {
let dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingRead(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.nonAdvancingRead(bytes: 2), Data([0x01, 0x02]))
XCTAssertEqual(try dr.nonAdvancingRead(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.nonAdvancingRead(bytes: 2), Data([0x01, 0x02]))
}

// .nonAdvancingRead - read overflow - return nil
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingRead(bytes: 5), nil)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertThrowsError(try dr.nonAdvancingRead(bytes: 5))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
}
}

Expand All @@ -120,7 +120,7 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
var dr = PassiveDataReader { $0(&data) }

dr.advanceBy(1)
XCTAssertEqual(dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x02]))
}
}

Expand All @@ -131,10 +131,10 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.read(bytes: 2), Data([0x02, 0x03]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 2), Data([0x02, 0x03]))
dr.reset()
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
}
}

Expand All @@ -145,14 +145,14 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.readOffset, 0)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x02]))

data = Data([0x0A, 0x0B, 0x0C, 0x0D])

XCTAssertEqual(dr.read(bytes: 1), Data([0x0C]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x0D]))
XCTAssertEqual(dr.read(bytes: 1), nil)
XCTAssertEqual(try dr.read(bytes: 1), Data([0x0C]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x0D]))
XCTAssertThrowsError(try dr.read(bytes: 1))
}

// MARK: - Data storage starting with index >0
Expand All @@ -174,33 +174,33 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.readOffset, 0)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x03]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x04]))
XCTAssertEqual(dr.read(bytes: 1), nil)
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x03]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x04]))
XCTAssertThrowsError(try dr.read(bytes: 1))
}

// .read - nil read - return all remaining bytes
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(), data)
XCTAssertEqual(dr.read(bytes: 1), nil)
XCTAssertEqual(try dr.read(), data)
XCTAssertThrowsError(try dr.read(bytes: 1))
}

// .read - zero count read - return empty data, not nil
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(bytes: 0), Data())
XCTAssertEqual(try dr.read(bytes: 0), Data())
}

// .read - read overflow - return nil
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(bytes: 5), nil)
XCTAssertThrowsError(try dr.read(bytes: 5))
}
}

Expand All @@ -220,24 +220,24 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingRead(), data)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.nonAdvancingRead(), data)
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
}

// .nonAdvancingRead - read byte counts
do {
let dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingRead(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.nonAdvancingRead(bytes: 2), Data([0x01, 0x02]))
XCTAssertEqual(try dr.nonAdvancingRead(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.nonAdvancingRead(bytes: 2), Data([0x01, 0x02]))
}

// .nonAdvancingRead - read overflow - return nil
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.nonAdvancingRead(bytes: 5), nil)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertThrowsError(try dr.nonAdvancingRead(bytes: 5))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
}
}

Expand All @@ -258,7 +258,7 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
var dr = PassiveDataReader { $0(&data) }

dr.advanceBy(1)
XCTAssertEqual(dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x02]))
}
}

Expand All @@ -278,23 +278,23 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase {
do {
var dr = PassiveDataReader { $0(&data) }

XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.read(bytes: 2), Data([0x02, 0x03]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 2), Data([0x02, 0x03]))
dr.reset()
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
}
}

func testWithDataReader() throws {
let data = Data([0x01, 0x02, 0x03, 0x04])

data.withDataReader { dr in
try data.withDataReader { dr in
XCTAssertEqual(dr.readOffset, 0)
XCTAssertEqual(dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x03]))
XCTAssertEqual(dr.read(bytes: 1), Data([0x04]))
XCTAssertEqual(dr.read(bytes: 1), nil)
XCTAssertEqual(try dr.read(bytes: 1), Data([0x01]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x02]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x03]))
XCTAssertEqual(try dr.read(bytes: 1), Data([0x04]))
XCTAssertThrowsError(try dr.read(bytes: 1))
}

struct TestError: Error { }
Expand Down

0 comments on commit bf0eed0

Please sign in to comment.