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

DSTify ToCStr #18457

Merged
merged 1 commit into from
Nov 1, 2014
Merged

DSTify ToCStr #18457

merged 1 commit into from
Nov 1, 2014

Conversation

japaric
Copy link
Member

@japaric japaric commented Oct 30, 2014

Methods that used to take ToCStr implementors by value, now take them by reference. In particular, this breaks some uses of Command:

Command::new("foo");  // Still works
Command::new(path) -> Command::new(&path)
cmd.arg(string) -> cmd.arg(&string) or cmd.arg(string.as_slice())

[breaking-change]


It may be sensible to remove impl ToCstr for String since:

  • We're getting impl Deref<str> for String, so string.to_cstr() would still work
  • Command methods would still be able to use cmd.arg(string[..]) instead of cmd.arg(&string).

But, I'm leaving that up to the library stabilization process.

r? @aturon
cc #16918

@rust-highfive
Copy link
Collaborator

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

unsafe fn with_c_str_unchecked<T>(&self, f: |*const libc::c_char| -> T) -> T {
(**self).with_c_str_unchecked(f)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Would this be better expressed by impl<'a, T: ToCStr> ToCStr for &'a T ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually this is only necessary because of the use case of cmd.args(&["foo", "bar"]). If we move to a iterator centric API this could be removed (maybe, I haven't give it too much thought).

@alexcrichton
Copy link
Member

While I think it makes sense to impl ToCStr for str directly, the loss in ergonomics of Command here is somewhat unfortunate (adding lots of &). This keeps the string-literal case at the same level of ergonomics, but any owned value now has to have a & stuck in front. I've frequently liked how Command is so versatile in what I can throw at it and it almost always looks great (just a mild concern).

Perhaps Command could continue to take T by value but the trait could be defined for str instead of &'a str?

@japaric
Copy link
Member Author

japaric commented Oct 30, 2014

The to_c_str doesn't need to take ownership, since it always does a (malloc) allocation and copies the input (i.e. it doesn't reuse the memory owned by the input). If we make the Command methods take by value we are going to encourage unnecessary clones, for example:

// path has type &Path
// Take ToCStr by value
Command::new(path.clone());  // allocates for Path (just to satisfy the by-value need)
// and allocates again for CString
// vs
// Take ToCStr by reference
Command::new(path);  // only one allocation for the CString

Although I didn't find any unnecessary clone in this PR, I did find a few unnecessary clones in my BytesContainer DSTification branch (which contains a similar by-value to by-reference change).

@alexcrichton
Copy link
Member

Note that if we T is taken by value then &Path can still implement BytesContainer just as Path can, so you could call Command::new(path) where path has type Path or &Path. This can be enabled via the blanket ToCStr for &'a T where T: ToCStr

@japaric
Copy link
Member Author

japaric commented Oct 30, 2014

Note that if we T is taken by value then &Path can still implement BytesContainer just as Path can, so you could call Command::new(path) where path has type Path or &Path. This can be enabled via the blanket ToCStr for &'a T where T: ToCStr

That sounds good to me. (blanket impl for &T + take T: ToCStr by value)

@aturon What do you think?

@japaric japaric mentioned this pull request Oct 30, 2014
@aturon
Copy link
Member

aturon commented Oct 31, 2014

I'm comfortable with that. Given that we're already taking a generic parameter for easy overloading, may as well let you pass owned data when convenient.

I would suggest making the impl for &str instead generic over any T: ToCStr, as @alexcrichton proposed.

@japaric japaric mentioned this pull request Oct 31, 2014
@japaric
Copy link
Member Author

japaric commented Oct 31, 2014

Updated to use @alexcrichton proposal and squashed.

@aturon re-r?

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Oct 31, 2014
bors added a commit that referenced this pull request Nov 1, 2014
Methods that used to take `ToCStr` implementors by value, now take them by reference. In particular, this breaks some uses of `Command`:

``` rust
Command::new("foo");  // Still works
Command::new(path) -> Command::new(&path)
cmd.arg(string) -> cmd.arg(&string) or cmd.arg(string.as_slice())
```

[breaking-change]

---

It may be sensible to remove `impl ToCstr for String` since:
- We're getting `impl Deref<str> for String`, so `string.to_cstr()` would still work
- `Command` methods would still be able to use `cmd.arg(string[..])` instead of `cmd.arg(&string)`.

But, I'm leaving that up to the library stabilization process.

r? @aturon 
cc #16918
@bors bors closed this Nov 1, 2014
@bors bors merged commit dd9dda7 into rust-lang:master Nov 1, 2014
@japaric japaric deleted the tocstr branch November 1, 2014 15:59
bors added a commit that referenced this pull request Nov 3, 2014
- The `BytesContainer::container_into_owned_bytes` method has been removed

- Methods that used to take `BytesContainer` implementors by value, now take them by reference. In particular, this breaks some uses of Path:

``` rust
Path::new("foo")  // Still works
path.join(another_path) -> path.join(&another_path)
```

[breaking-change]

---

Re: `container_into_owned_bytes`, I've removed it because

- Nothing in the whole repository uses it
- Takes `self` by value, which is incompatible with unsized types (`str`)

The alternative to removing this method is to split `BytesContainer` into `BytesContainer for Sized?` and `SizedBytesContainer: BytesContainer + Sized`, where the second trait only contains the `container_into_owned_bytes` method. I tried this alternative [in another branch](https://github.com/japaric/rust/commits/bytes) and it works, but it seemed better not to create a new trait for an unused method.

Re: Breakage of `Path` methods

We could use the idea that @alexcrichton proposed in #18457 (add blanket `impl BytesContainer for &T where T: BytesContainer` + keep taking `T: BytesContainer` by value in `Path` methods) to avoid breaking any code.

r? @aturon 
cc #16918
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 pul