diff --git a/Sources/OTCore/Abstractions/DataReader.swift b/Sources/OTCore/Abstractions/DataReader.swift index 2a18554..748f539 100644 --- a/Sources/OTCore/Abstractions/DataReader.swift +++ b/Sources/OTCore/Abstractions/DataReader.swift @@ -35,10 +35,26 @@ public struct DataReader { } /// Manually advance by _n_ number of bytes from current read offset. + /// Note that this method is unchecked which may result in an offset beyond the end of the data stream. public mutating func advanceBy(_ count: Int) { readOffset += count } + /// Return the next byte and increment the read offset. + /// + /// If no bytes remain, `nil` will be returned. + public mutating func readByte() -> UInt8? { + guard let d = dataByte() else { return nil } + 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() -> UInt8? { + 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. @@ -59,6 +75,11 @@ public struct DataReader { // MARK: - Internal + func dataByte() -> UInt8? { + guard remainingByteCount > 0 else { return nil } + return base[readOffset] + } + func data(bytes count: Int? = nil) -> (data: Data, advanceCount: Int)? { if count == 0 { return (data: Data(), advanceCount: 0) diff --git a/Sources/OTCore/Abstractions/PassiveDataReader.swift b/Sources/OTCore/Abstractions/PassiveDataReader.swift index 5d832d0..75c038b 100644 --- a/Sources/OTCore/Abstractions/PassiveDataReader.swift +++ b/Sources/OTCore/Abstractions/PassiveDataReader.swift @@ -45,10 +45,26 @@ public struct PassiveDataReader { // MARK: - Methods /// Manually advance by _n_ number of bytes from current read offset. + /// Note that this method is unchecked which may result in an offset beyond the end of the data stream. public mutating func advanceBy(_ count: Int) { readOffset += count } + /// 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 } + 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() + } + /// 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. @@ -75,6 +91,12 @@ public struct PassiveDataReader { return out } + func dataByte() -> D.Element? { + guard remainingByteCount > 0 else { return nil } + let readPosIndex = withData { $0.index($0.startIndex, offsetBy: readOffset) } + return withData { $0[readPosIndex] } + } + func data(bytes count: Int? = nil) -> (data: D.SubSequence, advanceCount: Int)? { if count == 0 { return (data: withData { $0[$0.startIndex ..< $0.startIndex] }, advanceCount: 0) diff --git a/Tests/OTCoreTests/Abstractions/DataReader Tests.swift b/Tests/OTCoreTests/Abstractions/DataReader Tests.swift index 0b20730..e185b2a 100644 --- a/Tests/OTCoreTests/Abstractions/DataReader Tests.swift +++ b/Tests/OTCoreTests/Abstractions/DataReader Tests.swift @@ -15,7 +15,7 @@ class Abstractions_DataReader_Tests: XCTestCase { func testRead() { let data = Data([0x01, 0x02, 0x03, 0x04]) - // .read - byte by byte + // .read(bytes:) do { var dr = DataReader(data) @@ -33,6 +33,24 @@ class Abstractions_DataReader_Tests: XCTestCase { XCTAssertEqual(dr.remainingByteCount, 0) } + // .readByte() + do { + var dr = DataReader(data) + + XCTAssertEqual(dr.readOffset, 0) + XCTAssertEqual(dr.remainingByteCount, 4) + XCTAssertEqual(dr.readByte(), 0x01) + XCTAssertEqual(dr.remainingByteCount, 3) + XCTAssertEqual(dr.readByte(), 0x02) + XCTAssertEqual(dr.remainingByteCount, 2) + XCTAssertEqual(dr.readByte(), 0x03) + XCTAssertEqual(dr.remainingByteCount, 1) + XCTAssertEqual(dr.readByte(), 0x04) + XCTAssertEqual(dr.remainingByteCount, 0) + XCTAssertEqual(dr.readByte(), nil) + XCTAssertEqual(dr.remainingByteCount, 0) + } + // .read - nil read - return all remaining bytes do { var dr = DataReader(data) @@ -67,6 +85,16 @@ class Abstractions_DataReader_Tests: XCTestCase { XCTAssertEqual(dr.read(bytes: 1), Data([0x01])) } + // single bytes + do { + var dr = DataReader(data) + + XCTAssertEqual(dr.nonAdvancingReadByte(), data[0]) + XCTAssertEqual(dr.nonAdvancingReadByte(), data[0]) + XCTAssertEqual(dr.readByte(), data[0]) + XCTAssertEqual(dr.readByte(), data[1]) + } + // .nonAdvancingRead - read byte counts do { let dr = DataReader(data) diff --git a/Tests/OTCoreTests/Abstractions/PassiveDataReader Tests.swift b/Tests/OTCoreTests/Abstractions/PassiveDataReader Tests.swift index 78bba55..2d526a4 100644 --- a/Tests/OTCoreTests/Abstractions/PassiveDataReader Tests.swift +++ b/Tests/OTCoreTests/Abstractions/PassiveDataReader Tests.swift @@ -15,7 +15,7 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase { func testRead() { var data = Data([0x01, 0x02, 0x03, 0x04]) - // .read - byte by byte + // .read(bytes:) do { var dr = PassiveDataReader { $0(&data) } @@ -33,6 +33,24 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase { XCTAssertEqual(dr.remainingByteCount, 0) } + // .readByte() + do { + var dr = PassiveDataReader { $0(&data) } + + XCTAssertEqual(dr.readOffset, 0) + XCTAssertEqual(dr.remainingByteCount, 4) + XCTAssertEqual(dr.readByte(), 0x01) + XCTAssertEqual(dr.remainingByteCount, 3) + XCTAssertEqual(dr.readByte(), 0x02) + XCTAssertEqual(dr.remainingByteCount, 2) + XCTAssertEqual(dr.readByte(), 0x03) + XCTAssertEqual(dr.remainingByteCount, 1) + XCTAssertEqual(dr.readByte(), 0x04) + XCTAssertEqual(dr.remainingByteCount, 0) + XCTAssertEqual(dr.readByte(), nil) + XCTAssertEqual(dr.remainingByteCount, 0) + } + // .read - nil read - return all remaining bytes do { var dr = PassiveDataReader { $0(&data) } @@ -67,6 +85,16 @@ class Abstractions_PassiveDataReader_Tests: XCTestCase { XCTAssertEqual(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]) + } + // .nonAdvancingRead - read byte counts do { let dr = PassiveDataReader { $0(&data) }