-
Notifications
You must be signed in to change notification settings - Fork 656
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Adding ByteBuffer.hexDump in xxd and hexdump -C formats #2475
Conversation
206173f
to
4975ffa
Compare
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.
I've cleaned up the short hexdump helpers for now, but will work on the long-format more. Not yet ready for a thorough review.
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.
Great start @natikgadzhi! Sorry for the delay, I've been out of office for a while. I added a little to weissi's feedback.
@glbrntt thank you for the review! I was slow last week, but will get back at it today — should have the next stage to review on Wednesday. |
@glbrntt, I cleaned up what I already had — but I still have to write the clipped version of the hexdump, and then implement the format enum and the switcher method. Time to get some sleep, but I hope to get it to work tomorrow. UPD: added the public API that switches formats. Take a look at the implementations. If they make sense overall, I'll bang my head against a wall and figure out a way to clip the long output. |
…not just readableBytes
3c96a83
to
f188f67
Compare
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.
This is coming along nicely!
I've worked through most of your feedback, but left the clipped hexdump format implementation for tomorrow. I hope to find time and work on it in the morning, though. One tricky part (to me) is to figure out what to use for the placeholder when clipping, if the clipping happens within a line. One option would be to always clip on 16-byte increments (but that won't be precise). Another option would be to use "." or space to show that that byte was omitted. And always insert one empty line with "..." in the middle to show that this line signifies the clipped part. So it would be something like this:
But that looks weird to me. Admittedly, I also didn't use hex dumps very often. What format should I implement, @glbrntt? |
I like this |
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.
This is looking really good. I mostly left doc/typo fixes but also left a little feedback on hexDumpLine
. Thanks for sticking with this!
result += String(repeating: " ", count: paddingBefore * 3) | ||
// If the padding is 8 or more bytes, pad with extra space to match hexdump -C format. | ||
if paddingBefore >= 8 { | ||
result += " " | ||
} | ||
|
||
// Iterate over the bytes in the line, and dump them one by one, insert a separator if needed. | ||
for (byteIndex, byte) in self.readableBytesView.enumerated() { | ||
result += String(byte, radix: 16, padding: 2) | ||
result += " " | ||
if byteIndex + paddingBefore == 7 { | ||
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.
This part is a little hard to follow because of the extra spaces being added conditionally. Can I suggest something like this?
result += String(repeating: " ", count: paddingBefore * 3)
// Add the left side of the central column
if paddingBefore < 8 {
for byte in self.readableBytesView.prefix(8 - paddingBefore) {
result += String(byte, radix: 16, padding: 2)
result += " "
}
}
// Add an extra space for the centre column.
result += " "
// Add the right side of the central column.
let bytesToSkip = paddingBefore < 8 ? 8 - paddingBefore : 0
for byte in self.readableBytesView.dropFirst(bytesToSkip) {
result += String(byte, radix: 16, padding: 2)
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.
Reworked it based on your feedback: d057109
That way, all if
statements can go away, seems more readable?
func testHexDumpDetailedWithMultilineFrontAndBack() { | ||
let buf = ByteBuffer(string: """ | ||
Goodbye, world! It was nice knowing you. | ||
I will miss this pull request with all of it's 94+ comments. |
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 can keep it going if you like? 😅 (Also, thank you again, this is a really awesome addition!)
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.
such good changes
Co-authored-by: George Barnett <gbarnett@apple.com>
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.
Ready for the next round ;)
result += String(repeating: " ", count: paddingBefore * 3) | ||
// If the padding is 8 or more bytes, pad with extra space to match hexdump -C format. | ||
if paddingBefore >= 8 { | ||
result += " " | ||
} | ||
|
||
// Iterate over the bytes in the line, and dump them one by one, insert a separator if needed. | ||
for (byteIndex, byte) in self.readableBytesView.enumerated() { | ||
result += String(byte, radix: 16, padding: 2) | ||
result += " " | ||
if byteIndex + paddingBefore == 7 { | ||
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.
Reworked it based on your feedback: d057109
That way, all if
statements can go away, seems more readable?
@swift-server-bot test this please |
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.
This looks good to me now, great job on this and thanks for sticking with it 🙂
/// - radix: radix base to use for conversion. | ||
/// - padding: the desired lenght of the resulting string. | ||
@inlinable | ||
internal init<T>(_ value: T, radix: Int, padding: Int) where T: BinaryInteger { |
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.
Can we give this a better generic type parameter name? Maybe Value
?
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.
Good call. Done in 96c077b.
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.
nicely done
@swift-server-bot add to allowlist |
@swift-server-bot test this please |
Huh, let me do a clean build and fix those. |
It should be good now. @glbrntt can you poke the swift CI gods, please? |
@natikgadzhi I added you to the allow list, so your pushes to the PR should automatically trigger CI from now on. (I just fixed the soundness check job permissions) @swift-server-bot test this please |
@yim-lee, thank you <3 |
cool person |
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.
Awesome, thanks @natikgadzhi!
…2495) ### Motivation `CustomDebugStringConvertible `/`debugDescription` name and documentation is confusing and should be changed but it is today expected to be suitable to be used as part of a structured display e.g. to be printed as part of an `Array`s description, a `struct` or `enum` with associated values. Therefore it should have no unpaired parentheses, no unescaped quotes, no top-level commas and no new lines. ### Modifications let `debugDescription` simply contain the same contents as `description`. We can't remove the property or the conformance without breaking API. ### Results `ByteBuffer` has a proper string representation suitable for being displayed in an `Array`, as the property of a `struct` or an associated value of an `enum`. We can add a new property/method once #2475 landed e.g. ```swift extension ByteBuffer { struct PrintFormat { static let hex: Self static let decimal: Self ... } func descriptionWithContents(format: PrintFormat = .hex, maxBytes: Int = 1024) { ... } } ``` Co-authored-by: Franz Busch <f.busch@apple.com>
…pple#2495) ### Motivation `CustomDebugStringConvertible `/`debugDescription` name and documentation is confusing and should be changed but it is today expected to be suitable to be used as part of a structured display e.g. to be printed as part of an `Array`s description, a `struct` or `enum` with associated values. Therefore it should have no unpaired parentheses, no unescaped quotes, no top-level commas and no new lines. ### Modifications let `debugDescription` simply contain the same contents as `description`. We can't remove the property or the conformance without breaking API. ### Results `ByteBuffer` has a proper string representation suitable for being displayed in an `Array`, as the property of a `struct` or an associated value of an `enum`. We can add a new property/method once apple#2475 landed e.g. ```swift extension ByteBuffer { struct PrintFormat { static let hex: Self static let decimal: Self ... } func descriptionWithContents(format: PrintFormat = .hex, maxBytes: Int = 1024) { ... } } ``` Co-authored-by: Franz Busch <f.busch@apple.com>
This PR adds a bunch of
hexDump
functions toByteBuffer
.Closes #2447
Motivation:
@weissi says he ends up writing hex dump helper functions in most projects with NIO, so they would be useful to have straight out of the box.
Modifications:
String(byte: UInt, padding: Int)
initializer to format bytes.ByteBuffer.Storage.dumpBytes
and re-uses it.hexDump
implementations for different formats.TODO
get*
.ByteBuffer.HexDumpFormat
enum and a public function to get a hex dump of aByteBuffer
providing the desired format.hexDumpLong(maxLength:)
implementation for long-format clipped hex dumpshexDump()
functionResult:
We'll have one new public function on
ByteBuffer
that accepts desiredHexDumpFormat
and returns the formatted hex dump string.