slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.43k stars 597 forks source link

Allow constructing a `SharedString` from `&'static str` without copying #2371

Open jturcotte opened 1 year ago

jturcotte commented 1 year ago

Allocating and copying SharedStrings when updating a model on MCUs can be a bottle neck, so it would be nice if this could be avoided when the strings itself are defined from a &'static str.

ogoffart commented 1 year ago

I think we should indeed do that. But currently SharedString is just a pointer. If we want to store &'static str, we need two pointer. But we can think of a smart string type that is both

jturcotte commented 1 year ago

@tronical mentioned in the chat that SharedVector could hold the slice instead of SharedString, so you could get the &[u8] and store it in SharedVector instead of the ref-counted pointer.

ogoffart commented 1 year ago

But &[u8] is two pointer large (size + pointer). What would be the memory layout of SharedVector?

jturcotte commented 1 year ago

I'm not sure if that'd even compile, but I was thinking that it could be possible to wrap both in an enum so that you have the union of something like this:

#[repr(C)]
struct StaticSharedVectorHeader {
    refcount: atomic::AtomicIsize,
}

#[repr(C)]
struct StaticSharedVectorInner<T> {
    header: StaticSharedVectorHeader,
    data: &[T],
}

with the non-static version?

#[repr(C)]
struct SharedVectorHeader {
    refcount: atomic::AtomicIsize,
    size: usize,
    capacity: usize,
}

#[repr(C)]
struct SharedVectorInner<T> {
    header: SharedVectorHeader,
    data: MaybeUninit<T>,
}

Assuming that the memory layout of StaticSharedVectorInner would fit within the current SharedVectorInner. But I have no idea how the C++ interop would be affected.

jturcotte commented 1 year ago

Well it would still need an extra allocation just to hold the slice, otherwise I think that you either need to increase the size of SharedString or to make it a trait, both of which sound like a heavy price.

I thought that while this would make the construction of the SharedString still relatively expensive, it would allow making it Sync or const, but thinking about it now I'm not sure if that's possible if SharedString is the same type for both the allocated and &'static versions. So I'm probably talking nonsense.

jturcotte commented 1 year ago

Maybe you could make it slightly less worse by moving size: usize or capacity: usize from the SharedVectorInnerHeader into SharedVector?

While this would increase the memory usage for heavily shared SharedString by duplicating it, it would keep the same memory usage as currently for single ref count SharedStrings.