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

Provide CStr getters and setters for c_char pointers and arrays #831

Merged
merged 1 commit into from
Nov 28, 2023

Conversation

MarijnS95
Copy link
Collaborator

It is a common operation to read and write NUL-terminated C string in the Vulkan API, yet the only helpers for that were thus far open-coded in the Debug printing implementations.

Move them to separate functions that are exposed to the user, in hopes of helping them no longer misunderstand NUL-terminated strings (see e.g. #830).

Important to note is that the array-copy for a static-sized c_char array has also been replaced with a CStr wrapper: this forces the user and our implementation to have a NUL-terminated string, but may now also panic if the incoming CStr with NUL-terminator is too large for the target c_char array.

@MarijnS95 MarijnS95 requested a review from Ralith November 25, 2023 09:41
@MarijnS95 MarijnS95 force-pushed the cstr-read-write-wrappers branch from a5dc83c to 1006322 Compare November 25, 2023 09:53
@MarijnS95
Copy link
Collaborator Author

but may now also panic if the incoming CStr with NUL-terminator is too large for the target c_char array.

Pushed a second commit that returns a Result here based on get_mut(..bytes.len()) returning None, but I'm not too happy about it yet...

@Ralith
Copy link
Collaborator

Ralith commented Nov 25, 2023

IMO the Result is fine, so this LGTM overall. One note: std precedent is as_c_str, not as_cstr. This is more consistent with the capitalization of the type, besides.

It is a common operation to read and write NUL-terminated C string in
the Vulkan API, yet the only helpers for that were thus far open-coded
in the `Debug` printing implementations.

Move them to separate functions that are exposed to the user, in hopes
of helping them no longer misunderstand NUL-terminated strings (see
e.g. #830).

Important to note is that the array-copy for a static-sized `c_char`
array has also been replaced with a `CStr` wrapper: this forces the user
and our implementation to have a NUL-terminator at the end of the string,
and the setter returns `Err()` when the given `CStr (with NUL-terminator)
is too large for the static-sized array it has to be written to.
@MarijnS95 MarijnS95 force-pushed the cstr-read-write-wrappers branch from 5df2380 to 5e4ac22 Compare November 25, 2023 23:18
@MarijnS95
Copy link
Collaborator Author

Ah fair enough, I hadn't seen that yet but I agree; corrected that.

Bit unfortunate that the standard library didn't follow this convention with into_cstring (same capitalization on CString) while they did for into_boxed_c_str).

@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `VK_EXT_hdr_metadata` device extension (#804)
- Added `VK_NV_cuda_kernel_launch` device extension (#805)
- Added `descriptor_count()` setter on `ash::vk::WriteDescriptorSet` (#809)
- Added `*_as_c_str()` getters for `c_char` pointers and `c_char` arrays (#831)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nit in hindsight: we also added setters for c_char pointers... And only replaced the c_char array setters with a CStr interface.

generator/src/lib.rs Show resolved Hide resolved
@MarijnS95 MarijnS95 merged commit 02c7a83 into master Nov 28, 2023
22 checks passed
@MarijnS95 MarijnS95 deleted the cstr-read-write-wrappers branch November 28, 2023 23:37
#[inline]
#deprecated
pub unsafe fn #param_ident_as_c_str(&self) -> &std::ffi::CStr {
std::ffi::CStr::from_ptr(self.#param_ident)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@Ralith I don't remember if we discussed this but these pointers can trivially be NULL. Fortunately the function is unsafe and this call is not used in Debug, so I'm curious if it was deliberate.

However, we might want to switch this to return Option to represent that (and to safely use this API in Debug.

Copy link
Collaborator

@Ralith Ralith Jan 10, 2024

Choose a reason for hiding this comment

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

Oops. I agree we should return Option here, and further, we should probably accept Option in the setters. Expecting users to check .foo.is_null() as appropriate is a bit optimistic and certain a missed opportunity for better safety.

I don't think we can safely use this API in Debug regardless because the pointer might be garbage.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we should probably accept Option in the setters

Same for the pointer slice setters.

I don't think we can safely use this API in Debug regardless because the pointer might be garbage.

Exactly, that's also what I wrote in #858 (comment): we can only print (subslices of) static arrays that are embedded in known-valid structs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Same for the pointer slice setters.

And arbitrary struct pointers (if Vulkan denotes them optional). Perhaps we should ask ourselves if the builder pattern isn't intended to (re)set fields to NULL?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Good point. Let's not. The asymmetry is weird, but treating slices specially is weirder, and putting Option in every setter would be a significant downgrade in ergonomics.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems reasonable, though of limited use outside implementing layers or ICDs.

Copy link
Collaborator Author

@MarijnS95 MarijnS95 Jan 12, 2024

Choose a reason for hiding this comment

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

In hindsight it makes total sense, as the caller already allocates and passes those mutable arrays/sizes. That's not the case for the static-arrays in #858, so they're the only ones where a slice-getter makes sense.

I feel like I've brought this up before, and had the same realization only hours later. 🤯

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm confused -- are you saying it makes sense to not have getters for pointer-slice fields? Why would the storage not being inline make that any less useful?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As you said, it's of limited use outside of layers and ICDs. Might be a useful addition if we wish to target those.

Just thinking out loud why I've never needed these slices helpers in client code 😉

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, yeah. I know there's been occasional interest. We could have a feature gate for implementer-side APIs, even. Still, far from urgent.

@MarijnS95 MarijnS95 added this to the Ash 0.38 milestone Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants