-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Relocate and improve c_str #435
Conversation
Created the draft for improve-c_str.
One thing to note: This wouldn't remove |
I don't think this should be in the |
Also, as discussed in those issues, it might be best to split |
A few more thoughts...
Always defining
I think in general we're going to want a way of using other allocators with Rust types including standard types like |
@canndrew: No problem with |
The fact that the |
I don't see much value in mutable wrappers. For collection-wise mutations one can convert to a In my understanding, the primary purpose of |
Quoting Daniel Micay: [libc] is a low-level binding to the C standard library, not a dumping ground for abstractions related to C. rust-lang#435 (comment)
I've worked with |
@canndrew You make a good point in that the constructors could follow the C ownership conventions regarding pointer constness. So the ownership-taking constructors would take a |
@thestinger the current organization of libc with all those nested modules already seems hard to reproduce automatically. Do you consider that a bug? |
@ben0x539: Yes, I think any organization or design decisions in libc that aren't present in the original C headers is a bug. I don't think splitting it up by standard or whatever else makes sense. It should correspond directly to what the platforms provide. |
@thestinger System headers seem to feature-gate declarations using macros etc, should we bother translating that into our bindings? |
@thestinger, @ben0x539: perhaps the idea was to be able to switch off parts of the standards that are missing on some platform. The real libc API variation is probably more fractured, anyway. The issues of binding to libc should be discussed separately, I think. |
The APIs are inherently non-portable because they use very platform-specific types. For example, The APIs are generally not fully specified to there are many differences between platforms in that sense too. For example,
You're proposing that we put stuff into the C bindings that aren't provided by the C standard library. I think it's appropriate to discuss my opinion on that here. I don't think it makes sense to move libc further away from being auto-generated / matching the C headers. |
@thestinger I have already removed the question on moving to |
The convention in C APIs is to use constness to designate absence of ownership transfer, so using a `*mut libc::char` in the ownership-taking constructors may help prevent accidental misuse. Destructor functions on the C side normally take pointers to non-const data as well. rust-lang/rfcs#435 (comment)
I have a nagging idea that representation of an unowned buffer could be laid onto |
A quick census of impl Foo {
fn get_inner_string<'a>(&'a self) -> CChars<'a> {
unsafe { CChars::wrap(raw::foo_get_inner_string(self)) }
}
} |
As an experiment, I have added a branch for |
Now I'm getting doubts on whether there's real need for three types to represent a C string. |
@mzabaluev sorry I should have posted here sooner, but I wanted to give you an update on my progress as well. I've taken over this RFC from @aturon and have been giving this some thought recently. After thinking about this for awhile, I think that all our usage of C strings can be lumped into one of three categories:
I, like you, have been questioning the fundamental utility of
The key idea here is that For use case (2), the two conversion functions to be located in the For use case (3) I'm still noodling out some ideas, but I'm thinking of a smart-pointer-style vector which will basically be what I'm also thinking of deprecating all these functions (in modules other than
What do you think of this? In general I don't want to have a huge proliferation of types to work with here, and I'd rather leverage byte slices as much as possible (that's basically what a C string is). |
@alexcrichton I think case (1) is currently addressed primarily by fn frob<T: ToCStr>(s: T) {
s.with_c_str(|p| {
unsafe { foreign::frob(p); }
}
} Note that The pointer-to-slice conversion functions will probably address most needs, except the efficient passing back to C as described above. C strings are byte slices with a twist, which can be made use of statically.
In your design, To summarize my proposed solutions for the cases you have listed:
|
I was hoping to totally remove the Ah yes, I didn't go into too much detail for (3)! I ended up writing a proto-RFC today about this topic, and I'll probably open it up soon-ish. I'd be very curious to see this feedback folded into this RFC though, it's always nice to have a few options to choose from! |
@alexcrichton Thanks for the document, I'll be happy to provide feedback on your proposal. The problem I see with trading Getting owned strings under |
@mzabaluev indeed! This is a bit of a tradeoff one way or another. I wouldn't expect the case of handing an owned string into Rust and then back into C would be too common, but using I'm fairly confident that we can regain a small string optimization, but I would prefer to stress a clear API in this area rather than micro-optimize from the start. We could add helper functions later always, but I think that using an inline vector of ~64 bytes or so would be pretty close to today's small string optimization. I've now opened the RFC as well: #494 |
I have redesigned the library, bringing it closer to @alexcrichton 's #494 and bringing it up to date with Rust library conventions. |
@mzabaluev The competing #494 has just been accepted. You can see some details in the comment I added, but the basic point is that #494 takes a more conservative approach and should be extendable to the design you've proposed here over time, if a clear need to do so emerges. We also plan to grow Thanks again for your work drawing attention to this issue and proposing a concrete design! |
Fair enough, I can see the concerns. Thanks to all participants for your work on improving Rust! |
After some more development, I have published the crate as c_string. let reaction = c_str!("Awesome!");
unsafe { libc::puts(reaction.as_ptr()) }; |
Forwarding Element Modifiers with "Splattributes"
Relocation and interface changes for the Rust library module
c_str
.For the time being, the redesigned module is available as a
standalone project.
c_str
module out ofstd
to free the standard library frompublic type dependencies on
libc
.CString
is made generic over a destructor type, allowing arbitrarydeallocation functions.
CString
to Rust slice types are namedparse_as_bytes
andparse_as_utf8
to reflect the scanning cost andthe possibility of failure (in the UTF-8 case).
library.
Result
for conversions that may fail, with descriptive error types.Clone
implementation onCString
due to lack of purpose..as_mut_ptr()
due to its potential for convenient evil.CStrArg
for passing string data to foreign functionsaccepting null-terminated strings.
IntoCStr
to enable optimized conversions toCStrArg
.Rejected ideas
Left here as context to the comments below:
CString
into a low-level typeCStrBuf
anda length-aware
CString
to make computation costs explicit.CString
had dynamically assigned destructors as arbitrary boxed closures.Prior issues