Skip to content
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

Adds Int(buffer:) initializer to FixedWidthInteger types #3047

Merged
merged 7 commits into from
Jan 17, 2025

Conversation

natikgadzhi
Copy link
Contributor

@natikgadzhi natikgadzhi commented Jan 12, 2025

Motivation:

Makes it possible to make integers out of ByteBuffers directly with an initializer. I.e. UInt32(buffer: ByteBuffer(bytes: [0, 1, 2, 3])). Closes #3012.

Modifications:

  • Adds the Int(buffer:) initializer in ByteBuffer-int.swift
  • Adds tests in ByteBufferTest.swift. Holy hell this file is huge.
  • Note that Int(buffer:) will crash if the buffer does not have enough bytes in it to represent the desired integer type.
  • It also does not expose endianness and uses Endianness.host, to keep the public API clean and simple. It's a convenience initializer, so I thought keeping it minimal is a good idea.

Result:

Nicer direct initializer for integers from ByteBuffers.

Motivation:

Makes it possible to make integers out of ByteBuffers directly with an initializer. I.e. `UInt32(buffer: ByteBuffer(bytes: [0, 1, 2, 3]))`.

Modifications:

- Adds the `Int(buffer:)` initializer in `ByteBuffer-int.swift`
- Adds tests in `ByteBufferTest.swift`. _Holy hell this file is huge._

Result:

Nicer direct initializer for integers from ByteBuffers.
@natikgadzhi
Copy link
Contributor Author

Hmmmm. Unlike Array(buffer:), this will fail if there's not enough stuff in the Buffer. The other two just read whatever is readable, so they should not fail arbitrarily if the user didn't check the length.

Perhaps it's worth adding a check and making this throwing, or keeping this optional? Or documenting that the user should ensure the length of the buffer is enough?

@natikgadzhi
Copy link
Contributor Author

I checked the docs for ByteBuffer, and they already explain that ByteBuffer can cast to/from "various unsigned int types", so I think that's enough.

@Lukasa Lukasa added the 🆕 semver/minor Adds new public API. label Jan 13, 2025
///
/// - Returns: The integer value read from the buffer
@inlinable
public init(buffer: ByteBuffer) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should definitely be failable, so that we can avoid the force-unwrap. We also want to add tests.

There's a separate question about whether this should be exactly the right size.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weissi strong opinions on checking that the buffer size matches the int size exactly?

If we should verify the size match, the most straightforward way would be to check buffer.readableBytes == MemoryLayout<Self.self>.size, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm definitely in favour of checking that this is exactly the right size. It's weird to left garbage around, if that's expected readInteger is the right tool. Endianness should also be configurable (but defaulted to .host) Something like

var buffer = buffer
guard let value = buffer.readInteger(endianness: endianness, as: Self.self), buffer.readableBytes == 0 else {
    return nil
}
return value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. You did all the work for me.

I thought making it optional is a better choice than making it throwing — I don't think anyone need to capture the specific error, so no need to make an extra error type.

@natikgadzhi natikgadzhi requested review from Lukasa and weissi January 15, 2025 04:48
Copy link
Member

@weissi weissi left a 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 happy with this but @Lukasa or someone from the NIO should approve too.

Copy link
Contributor

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lovely patch @natikgadzhi, thank you so much! ✨

@Lukasa
Copy link
Contributor

Lukasa commented Jan 16, 2025

Ah dang, one quick note from the docs:

error: Return value documented for initializer returning void
   --> ../ByteBuffer-int.swift:146:9-146:117
144 |     ///   - endianness: The endianness to use when reading the integer, defaults to the host system's endianness.
145 |     ///
146 +     /// - Returns: The integer value read from the buffer, or nil if the buffer size did not match the integer type.
    |         ╰─suggestion: Remove return value documentation
147 |     @inlinable
148 |     public init?(buffer: ByteBuffer, endianness: Endianness = .host) {

Looks like you should change this to just say "this initializer will fail if the buffer size does not match the size of the integer type".

@natikgadzhi
Copy link
Contributor Author

natikgadzhi commented Jan 16, 2025

Ooops. That should do it. Deleted the whole returns line as the first line already matches "exactly the right size"

@Lukasa Lukasa enabled auto-merge (squash) January 17, 2025 16:58
@Lukasa Lukasa merged commit 456ca25 into apple:main Jan 17, 2025
34 of 35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🆕 semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

FixedWidthInteger.init(buffer: ByteBuffer) missing
3 participants