-
Notifications
You must be signed in to change notification settings - Fork 698
Add peekInteger API to ByteBuffer #3157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…pple#2736 and apple#2034, leading to verbose or error-prone code. Users may unintentionally access data without correctly managing the reader index. To address this, I introduce a nonmutating peekInteger API that reads integers using the current readerIndex without modifying it. * Added a peekInteger method to ByteBuffer, which provides a nonmutating way to read integers using the current readerIndex. * Implemented peekInteger using the existing getInteger function. * Added some simple unit tests to validate correct behavior, including scenarios for different integer types, insufficient bytes, and multi-write scenarios. * Users now have access to a safer, more intuitive API for inspecting integers in a buffer without modifying state. * Existing getInteger functionality remains unchanged. * Added tests for integer reading scenarios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of doc nits but otherwise this looks great, thank you!
Sources/NIOCore/ByteBuffer-int.swift
Outdated
@@ -113,6 +113,22 @@ extension ByteBuffer { | |||
self.setBytes(ptr, at: index) | |||
} | |||
} | |||
|
|||
/// Peeks at the integer at the current reader index without advancing it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Peeks at the integer at the current reader index without advancing it. | |
/// Returns the integer at the current reader index without advancing it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to echo my comment on one of the issues referred to in the description. Since this kind of a change can be extrapolated to every type that has a get* API, can the scope of this PR increase to consider them or should they separate PRs?
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this PR is effectively good to go I'd bias towards merging this and opening a separate PR for other methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, looks like the formatter failed:
diff --git a/Sources/NIOCore/ByteBuffer-int.swift b/Sources/NIOCore/ByteBuffer-int.swift
index b228801..161eff7 100644
--- a/Sources/NIOCore/ByteBuffer-int.swift
+++ b/Sources/NIOCore/ByteBuffer-int.swift
@@ -127,7 +127,7 @@ extension ByteBuffer {
endianness: Endianness = .big,
as: T.Type = T.self
) -> T? {
- return self.getInteger(at: self.readerIndex, endianness: endianness, as: `as`)
+ self.getInteger(at: self.readerIndex, endianness: endianness, as: `as`)
}
}
diff --git a/Tests/NIOCoreTests/ByteBufferTest.swift b/Tests/NIOCoreTests/ByteBufferTest.swift
index 460810d..dcdaa11 100644
--- a/Tests/NIOCoreTests/ByteBufferTest.swift
+++ b/Tests/NIOCoreTests/ByteBufferTest.swift
@@ -3876,7 +3876,7 @@ extension ByteBufferTest {
let second: UInt8 = 0x34
_ = buffer.writeInteger(first)
_ = buffer.writeInteger(second)
-
+
// First peek to check the first integer.
guard let peeked1: UInt8 = buffer.peekInteger(as: UInt8.self) else {
XCTFail("peekInteger failed to return a value on first call")
@@ -3884,7 +3884,7 @@ extension ByteBufferTest {
}
XCTAssertEqual(peeked1, first)
XCTAssertEqual(buffer.readerIndex, 0)
-
+
// Second peek should return the same value, confirming readerIndex is unchanged.
guard let peeked2: UInt8 = buffer.peekInteger(as: UInt8.self) else {
XCTFail("peekInteger failed to return a value on second call")
Sources/NIOCore/ByteBuffer-int.swift
Outdated
guard let result = self.getInteger(at: self.readerIndex, endianness: endianness, as: T.self) else { | ||
return nil | ||
} | ||
return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the guard
here. The formatter was complaining because of the explicit return where it wasn't necessary:
guard let result = self.getInteger(at: self.readerIndex, endianness: endianness, as: T.self) else { | |
return nil | |
} | |
return result | |
self.getInteger(at: self.readerIndex, endianness: endianness, as: T.self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
I'm sorry, I need to be more careful with the format checks. However, there's some unit tests that fail, are those supposed to be taken care of as well? |
No worries! For what it's worth you should be able to run
The failing unit tests are an issue with a nightly build of the compiler, so nothing more you need to do here. |
### Motivation: Existing get APIs require passing an explicit index and can be misused, leading to verbose and error-prone code. Adding peek variants that automatically use the current readerIndex improves safety and clarity. This aims to address #2034 and #2736, and is a continuation of PR #3157 ### Modifications: - Introduced peekBytes(), peekString(), peekNullTerminatedString(), peekUTF8ValidatedString() and peekDispatchData(). - Added tests for each peek API covering normal, empty, repeated, and partial read scenarios. ### Result: Developers can now use nonmutating peek APIs to inspect ByteBuffer contents without altering the reader index. ***PS**: I have focussed on the ByteBuffer-aux get\* implementations, so I'm not sure if I am missing any other important/error-prone get\* elsewhere, if so, please point me to them and I'll be happy to add respective peek\*'s!*
Existing get APIs require passing an explicit index and can be misused, leading to verbose and error-prone code. Adding peek variants that automatically use the current readerIndex improves safety and clarity. This aims to address issue apple#2034 and issue apple#2736, and is a continuation of PR apple#3157 Modifications: Introduced peekSlice(), peekLengthPrefixedSlice(), peekData(), peekUUIDBytes() and peekWebSocketErrorCode(). Added tests for each peek API covering normal, empty and repeated peek scenarios. Result: Developers can now use nonmutating peek APIs to inspect ByteBuffer contents without altering the reader index.
### Motivation: Existing get APIs require passing an explicit index and can be misused, leading to verbose and error-prone code. Adding peek variants that automatically use the current readerIndex improves safety and clarity. This aims to address issue #2034 and issue #2736, and is a continuation of PR #3157 ### Modifications: Introduced peekSlice(), peekLengthPrefixedSlice(), peekData(), peekUUIDBytes() and peekWebSocketErrorCode(). Added tests for each peek API covering normal, empty and repeated peek scenarios. ### Result: Developers can now use nonmutating peek APIs to inspect ByteBuffer contents without altering the reader index.
Motivation:
The existing getInteger API is often used incorrectly, leading to verbose or error-prone code as mentioned in #2034 and #2736. Users may unintentionally access data without correctly managing the reader index. To address this, I added a peekInteger API that reads integers using the current readerIndex without modifying it.
Modifications:
Result: