Unsized types distinct from DSTs


#1

There are cases where borrowed references provide a view to a larger object in memory than the nominal sized type being referenced. When only immutable references are available on such types, it’s possible to prevent copying out the nominal sized value in safe code, but there is still potential for trouble with values under reference having a bogus size. A couple of examples:

  • CStr as a proposed ‘thin’ dereference type for CString. A token type to represent an undetermined number of bytes in a null-terminated string. As currently defined, the struct has size of 1.
  • A structure that is a public view into a larger contiguously allocated object (e.g. obtained via FFI). Rust methods are implemented on the public structure, but for them to work the whole object has to be present.

To prevent unintended use of such types as sized, could a further distinction be made under non-Sized types, between DSTs and completely unsized types?

How I could see this done, is [T], str, and types containing them would get a new intrinsically implemented trait DynamicSize, and non-DSTs could opt out of Sized (and out of Copy) by including a marker:

struct CStr {
    head: libc::c_char,  // Contains at least one character...
    rest: std::marker::NotSized  // ...but there can be more
}

DynamicSize will be determinant in deciding whether a reference to the type will be ‘fat’ and require the actual size of the data to be computed at runtime. Things like std::mem::size_of, on the other hand, will continue being bound by Sized, so a truly unsized type under reference cannot be misinterpreted as a value that can be copied or otherwise used in isolation from its current location in memory.

Thoughts? Feasible?


#2

I’ve wanted this for a while now for representing FFI types that can’t live on the stack. Making such a type dynamically sized would be perfect, because then the compiler wouldn’t let you declare it locally and things like mem::swap wouldn’t be allowed.

Here’s an example where someone else brought this up on r/rust: http://www.reddit.com/r/rust/comments/292h3g/c_structs_ending_in_zerolength_arrays_and_ffi/cigugy6

And here’s the use case I have for dynamically sized types without ‘fat’ pointers in my personal project: https://github.com/SSheldon/rust-objc/issues/6


#3

I’ve filed this as an RFC PR.


#4

The RFC has been postponed, but the idea is getting developed further: http://internals.rust-lang.org/t/rfc-unsized-types-take-2/1574


#5

This is something I desire heavily for FFI, especially with WinAPI. Many structs will often have their last member be an unsized array (or even worse a union of several different unsized arrays). Even if this was implemented in a very limited scope where only unsafe code could work with such structs, it would make life much easier.