-
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
Make alloc-free string manipulation more ergonomic with String::mutate(&mut self, ...) #2864
Comments
We have
At that point, your
I'm unsure if miri could actually be made happy with See also: https://crates.io/search?q=rope |
note just using: fn mutate(&mut self, F) -> ()
where F: for<'a> Fn(&'a str) -> &'a str doesn't work without checks because of, string.mutate(|_| "static string always works"); To fix this we can add checks that check if the string is in fact a sub-string of |
Indeed, that is why the musings about const generics came into play. @KrishnaSannasi it did not occur to me to have the failure mode for mutate (when result is not a substring) be the allocation of a new string rather than an error, which does indeed make it less pressing for the substr check to be a compile-time error. |
I don't think const generics can help here, we need a way to say exactly this lifetime, not at least this lifetime. But I don't think that would be reasonable to implement. (sounds tricky) |
Ah, but it would if you disregard lifetimes altogether and instead think of the generics as the start address of the slice and its length.
That was my initial line of thought before thinking of a possible out via const generics. It's certainly possible if we pass in a wrapper that includes a phantom type such that it can't be constructed anywhere else, but call any of the |
A wrapper type may work (we could forward all of |
I suppose
We should add the |
What about the less ambitious alternative i.e. introduce the specific in-place modification functions? impl String {
pub fn trim_start_in_place(&mut self);
pub fn trim_end_in_place(&mut self);
pub fn trim_in_place(&mut self);
pub fn trim_start_matches_in_place<'a>(&'a mut self, pat: impl Pattern<'a>);
pub fn trim_end_matches_in_place<'a>(&'a mut self, pat: impl Pattern<'a>);
pub fn trim_matches_in_place<'a>(&'a mut self, pat: impl Pattern<'a>);
} impl<T> Vec<T> {
pub fn shift_left(&mut self, mid: usize);
} This already exists, |
Trim was just an example. What if you wanted to replace a string with the first occurrence of |
I don't understand why the magic |
The original idea was that the method would be compile-time guaranteed to be (re-)allocation-free and the magic lifetimes were to be able to avoid a |
The only time reallocation would be required is if the new slice is larger than the |
Ideally, there would be no copying needed if the slice is a subset of the string. |
@mqudsi That can only work in cases like |
I think @sfackler is right: We should implement |
This is sounding somewhat similar to |
The current API for manipulating
String
objects is largely relegated tostr
, and many operations treat the source string as immutable and return a new&str
reference with the result of the operation (unless non-contiguous results are not guaranteed, e.g..replace()
, etc.)Oftentimes destructive modifications to a
String
are needed "while it is being created" and developers are forced to either write their own logic to duplicatestr
functionality to updateString
values or else use.to_owned()
on the result ofstr
functions.e.g. a function runs a command and returns its output as a string, with trailing whitespace removed:
vs
I believe we're close to being able to support a safe mutating api that provides a
&str
and uses an&str
result to redefine the string (mainly to pop or dequeue elements from the underlying storage), something along the lines ofwhich passes in an (exclusive) reference to the current value of the string and expects to receive a
subset: &'restricted str
as a result, whereself.as_bytes() == &[.., subset.as_bytes(), ..]
holds true (i.e.subset.as_bytes().as_ptr() >= self.as_bytes().as_ptr() && subset.as_bytes().as_ptr() + subset.as_bytes().len() < self.as_bytes().as_ptr() + self.as_bytes().len()
)This makes the most sense it if it is possible to make compile-time guarantees ensuring the above predicate. I don't think #2000 via rust-lang/rust#44580 currently makes this possible, but I feel as if there is overlap between const generics and the ability to do so.
Using it would look something like this:
while forbidding the following:
The text was updated successfully, but these errors were encountered: