Type alias for !Sized types

I would like to use a type alias for some occurences of [u8] and Vec<u8> in my code (mostly for documentation purposes / code clarity).

I guess I have to define two separate alias like the following?

pub type Content = [u8];
pub type OwnedContent = <Content as ToOwned>::Owned;

pub fn foo(_content: &Content) {
    todo!()
}

pub fn bar() -> OwnedContent {
    todo!()
}

(Playground)

Or is there any more conscise way? (edit: I mean with a single type alias, for example. Of course I could use Vec<u8> instead of <Content as ToOwned>::Owned) And how do I name these? Content/OwnedContent? Or Content/ContentBuf?

One reasonable naming scheme to follow could be the one from Path and PathBuf. So, adding Buf to the end of the name of the growable owned version.

I thought on this too, but in my case, the OwnedContent will usually not serve to build (buffer) the content, but more to serve as keeping the content allocated :thinking:. This makes me wonder if semantically, I have more something like this:

pub type Content = [u8];
pub type ContentBuf = Vec<u8>;

pub fn foo(_content: &Content) {
    todo!()
}

pub fn bar() -> Box<Content> {
    todo!()
}

(Playground)

But I tend to avoid using Box<[u8]> for some reason. I guess it makes things complex sometimes.

Anyway, since std also uses two types, maybe it's what I should settle down with.

The trade-off of Box<[u8]> vs Vec<u8> — in settings where you'll never (or at least rarely) need to further grow or shrink the value — should generally be that creating Box<[u8]> (usually from a Vec<u8>) will involve another reallocation, unless the Vec had exactly the right capacity to begin with, while in the other hand, the fact that excess capacity is removed can be seen as a way to limit wasted memory. If using shrink_to_fit seemed like a reasonable (memory usage) optimization in your use case, then a boxed slice could also be reasonable.

2 Likes

I don't really think using Box is worth it in my case. But out of curiosity, wouldn't it be possible to create a Box<[u8]> from a Vec<u8> without reallocation by "wasting" the excess memory, yet saving the memory for the capacity information? (assuming that the memory allocator doesn't need to know the length, as free in C also doesn't need to know the length)

The thing I'm "annoyed" with is that (disregarding memory storage) I have to use two types to describe the exact same thing (similar to Path/PathBuf, str/String, etc). But I think that's the way to go in Rust.

Perhaps I'm missing some syntax like this:

pub type Id = u64;
pub type Content = [u8];

macro_rules! owned {
    ($type:tt) => { <$type as ::std::borrow::ToOwned>::Owned };
}

pub fn foo(_content: &Content) -> owned!(Id) {
    todo!()
}

pub fn bar(_id: &Id) -> owned!(Content) {
    todo!()
}

(Playground)

(Side note: I think :tt isn't the right choice in the macro, but I remember :path had some issues.)

My point is: Defining two types seems to be redundant. But I think it's the way it's done in Rust.

As far as I know, in Rust, allocators do need to know the length.

1 Like

This assumption doesn't hold in Rust. Whenever you call dealloc(), you need to pass a pointer and the Layout of your allocation (i.e. alignment and size). Passing in the incorrect length (the overall allocation would be a Vec's capacity, but Box<[u8]> only has access to the len) will probably cause the allocator implementation to have a bad time.

2 Likes

There’s no need for a macro in the first place :wink:

Edit: and also, $type:ty is a thing

2 Likes

Oh, I see. But that makes sense. The C way would have overhead in cases where the layout is known, so I do like the Rust approach more.

"Warum einfach, wenn's auch kompliziert geht" :sweat_smile: (German saying: why easy if you can solve it in a complicated way)

Still not sure if such type (constructor) alias makes things easier. I think the idiomatic way is to provide two type aliases, right?


I might likely settle for the Buf approach:

Mostly because it's short.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.