Interface for managing allocas

Today I came up with few traits for managing stack allocated space.

Background:

  1. RFC: Placement by return
  2. Procedural vtables and fully customizeable wide pointers
  3. Old Alloca for Rust
  4. Merged Unsized Rvalues
  5. Idea of KnownSize trait

The interface:

//Placement trait, thing where NRVO is guranteed.
trait Place {
    //try to fit value in the inner memory block
    fn try_emplace<T: KnownSize,F: FnOnce()->T>(self,f: &F) -> (bool,Option<impl Place>); //consuming Place, trying to do placement, returns (if placement suceed; placemet obj to memory left, if there are some).
}
//This trait requires sized because it's not supposed to be made into trait object.
//lifetime 'a is used to tie implementor to the scope where it lives, and gurantee that builders will not outlive automata.
trait AllocAutomata<'a>: Sized {
    type Builder: Place;
    
    //While increasing size of last stack block this is used.
    fn extend_curr(&mut self,val: usize);
    
    //Last stack block is given to value builder, which actually used for placement values.
    fn get_next_builder(&mut self)->Self::Builder + 'a;
    
}

This rely on new auto trait KnownSize

    //unsized types have to implement it either manually or with compiler guidance
    unsafe auto trait KnownSize {
        fn size_of_unit() -> usize;
        fn size_of_array(sz: usize) -> usize {
            sz * size_of_unit()
        }
    }

    //blanket impl for `Sized` types
    impl<T: Sized> KnownSize for T {
        fn size_of_unit()->usize {
            std::mem::size_of::<T>()
        } 
    }

Actualy current AllocAutomata trait would be impossible to use for getting actual value or pointer to it, instead it is intended for use inside of compiler, when it does binding of unsized value.

I’d recommend you to use syntax highlighting if you expect anyone to read this.

Use blocks like

```
code here
```

instead of indentation to get hightlighted code blocks.

Note that you can, and should, edit your second post in this thread to conform to the Forum Code Formatting and Syntax Highlighting guidelines. You can edit any of your own posts by clicking on the pencil-shaped "edit this post" button under those posts to apply correct formatting. As @steffahn implied in the prior post, many readers of the two Rust forums simply ignore code that does not follow the forum posting guidelines.

1 Like

While you’re at it, readability could be further approved by applying rustfmt. (These space-less -> and ,s are a bit hard to read and not pretty.) You should also try to decrease the width of your code a bit in the comments and remove the four spaces of indentation since, as I said, you ought to use the ``` delimiters instead of the indentation.


That’s not a valid concern for a trait that’s not object safe. Maybe you intended it to be object safe though, in which case you forgot a bunch of self parameters. In this case you should explain why trait objects are a problem.


I’m skimming the link you provided and getting the feeling that this kind of trait is useless unless you’re adding types to Rust that cannot work with mem::size_of_val. But I could be misunderstanding something. Or you’re implying that your suggestion requires some (or all) of the linked proposals to already be implemented to make sense? These are a lot of links, perhaps you could further specify what you take for granted; in partigular the F: FnOnce() -> T suggests you assume some kind of placement-by-return.

Are you trying to augment one particular of the linked RFCs / ideas, if yes which one? If your proposal is unrelated but builds on top of them, I feel like we should wait for those other proposals to land first before spending too much time on ideas of what-else to do with them. Unless your point is to say “hey, I have this idea of what else we could do that only works if this other proposal lands this way instead of that way”. In which case, you should explicitly say so.


I think you might be misunderstanding how generic parameters work. This function signature leaves the type P as the callers choice. Also you provide no example or explanation whatsoever as to how this method is going to be used, or what kind of types would implement it.

1 Like

From my understanding it seems you want a function to automatically perform an alloca when it calls another function that returns a dynamically sized type? Then implementing traits that would be useful for those types?

If i'm understanding the first RFC correctly, it is using a generator to essentially defer the allocation method to the caller rather than simply using the global allocator. If that is the case than I think a "StackBox" type would be more appropriate to make the alloca explicit.

fn returns_dyn() -> dyn str;

// allocate the return on a bump allocator
let bump_alloc = BumpBox::new_with(|| returns_dyn());
// allocate the return on the global allocator
let glob_alloc = Box::new_with(|| returns_dyn());
// allocate the return on the stack
let stak_alloc = StackBox::new_with(|| returns_dyn());
// allocate the return on some local buffer
let buff_alloc = Buffer<[usize; 10]>::new_with(|| return_dyn())?;

Then StackBox would include methods that could return the size of the allocation. This explicit call to StackBox would also be helpful in identifying alloca's occurring in a loop. Although using a fixed sized buffer to "allocate" onto might be preferable to an alloca.

That or maybe the generator stores it's return types as variants in addition to it's state, meaning you can 'consume' the generator into one of the output types. Although at that point just return an enum.

Interface I wrote here was lacking some critical details, so I changed it in playground and updated it here. Example of usage.

This trait is intended to be an interface to something that handles alloca's, so this is tied to function scope and doesn't make any sense in moving implementor value or upcasting it to trait object.

The only thing I assume is implementation of RFC: Placement by return. Another links was given mainly as prior art. Excuse me for that.

This is intended to be used inside of DST bindings by "Placement by return" feature. I think that these sized structs must live within the scope of unsized locals and keep track of the memory allocated for DST. One more thing I want to raise is "Should AllocAutomata methods be ever called like function?" (i.e they have to be #[inline(always)]), it seems like calling the function when doing stack extension leads to stack coruption.