placenew 2.0.0

A crate providing the macro 'place_boxed' which allows you to create a object in-place on the heap using the normal struct initializer, the macro uses Box::new_uninit(), initializes all members using the values from the struct initializer, and then calls .assume_init() for regular value types => writes the expression in-place for array types ([T; N]) => generates a for loop for expressions such as [0; 100], and generates a sequence of arr[i] = v for an expression such as [0, 1, 2, 3]
Documentation
extern crate proc_macro;
use proc_macro::{TokenStream};
use std::convert::TryInto;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Expr, FieldValue, Member};
use syn::parse::Parser;
/*
This macro allows you to construct values in the heap in-place safely,
using the struct initialization syntax


Example usage:
let mut my_box = place_boxed!(
    MyStruct{
        member_1: 5,
        member_array: [0; 100],
        member_array2: [1, 2, 3],
    }
)

Example codegen:
let mut my_box = {
    let mut res = Box::<MyStruct>::new_uninit();

    unsafe {
        let ptr = res.as_mut_ptr();

        (&raw mut (*ptr).member_1).write(5);

        for i in 0..100 {
            (&raw mut (*ptr).member_array[i]).write(0);
        }

        (&raw mut (*ptr).member_array2[0]).write(1);
        (&raw mut (*ptr).member_array2[1]).write(2);
        (&raw mut (*ptr).member_array2[2]).write(3);

        res.assume_init()
    }
}
*/



fn inner_place_expr(member: proc_macro2::TokenStream, val: &Expr, nesting: u32) -> proc_macro2::TokenStream {
    match val {
        Expr::Array(arr) => {
            let construction = arr
                .elems
                .iter()
                .enumerate()
                .map(|(i, item)| {
                    inner_place_expr(quote! { #member[#i] }, item, nesting + 1)
                });

            quote! {
                #(#construction)*
            }
        },
        Expr::Repeat(rep) => {
            let v = &rep.expr;
            let len = &rep.len;
            let loop_var = format_ident!("i_{}", nesting);
            let initializer = inner_place_expr(quote! { #member[#loop_var] }, &v, nesting + 1);
            quote! {
                for #loop_var in 0..#len {
                    #initializer
                }
            }
        },
        expr => {
            quote! {
                (&raw mut #member).write(#expr);
            }
        }
    }
}

struct PlaceBoxedInput {
    expr: syn::Expr,
    ty: Option<syn::Type>,
}

impl syn::parse::Parse for PlaceBoxedInput {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let expr = input.parse::<syn::Expr>()?;
        let ty = if input.peek(syn::Token![,]) {
            input.parse::<syn::Token![,]>()?;
            Some(input.parse::<syn::Type>()?)
        } else {
            None
        };
        Ok(Self { expr, ty })
    }
}


/// place_boxed is a macro that creates a structure in-place from a structure initializer input
///
/// this macro is unsafe as there isn't a way to validate the structure initializer input is valid,
/// you can leave out some fields, and so this macro requires wrapping with unsafe in order to
/// mark that the programmer must validate their input is valid, my recommendation is to
/// first initialize the struct as you would normally, validate it compiles through either your ide,
/// or manually compiling, then wrapping in place_boxed
///
/// this macro is great for reducing unnecessary copying, or simplifying constructing
/// large structures on the heap
///
/// example usage:
/// ```rust
///struct MyStruct {
///    trivial_val: i32,
///    name: String,
///    array: [i32; 5],
///    nested_array: [[i32; 10]; 5]
///}
///
///let my_box = place_boxed!(
///    MyStruct {
///        trivial_val: 10,
///        name: String::from("Bob"),
///        array: [1, 2, 3, 4, 5],
///        nested_array: [[5; 10]; 5]
///    }
///);
///
/// let my_boxed_slice = place_boxed!( [10; 100_000], [i32; 100_000] );
/// ```
///
///example codegen (edited for readability):
/// ```rust
///let my_box = unsafe {
///    let _ensure_struct_correct = || {
///         MyStruct {
///            trivial_val: 10,
///            name: String::from("Bob"),
///            array: [1, 2, 3, 4, 5],
///            nested_array: [[5; 10]; 5]
///         }
///    };
///
///    let mut res = std::boxed::Box::<MyStruct>::new_uninit();
///
///    let ptr = res.as_mut_ptr();
///
///    (&raw mut (*ptr).trivial_val).write(10);
///
///    (&raw mut (*ptr).name).write(String::from("Bob"));
///
///    (&raw mut (*ptr).array[0usize]).write(1);
///
///    (&raw mut (*ptr).array[1usize]).write(2);
///
///    (&raw mut (*ptr).array[2usize]).write(3);
///
///    (&raw mut (*ptr).array[3usize]).write(4);
///
///    (&raw mut (*ptr).array[4usize]).write(5);
///
///    for i_0 in 0..5 {
///        for i_1 in 0..10 {
///            (&raw mut (*ptr).nested_array[i_0][i_1]).write(5);
///        }
///    }
///
///    res.assume_init()
///}
///
/// let my_boxed_slice = unsafe {
///         let _ensure_correct = || { [10; 100_000] };
///
///         let mut res = std::boxed::Box::<[i32; 100_000]>::new_uninit();
///         let ptr = res.as_mut_ptr();
///         for i_0 in 0..100_000 { (&raw mut (*ptr)[i_0]).write(10); }
///         res.assume_init()
/// };
/// ```
#[proc_macro]
pub fn place_boxed(input: TokenStream) -> TokenStream {

    let inp = parse_macro_input!(input as PlaceBoxedInput);
    let struct_expr = match inp.expr {
        syn::Expr::Struct(s) => s,
        e => {
            let Some(ty) = inp.ty else {
                return syn::Error::new_spanned(e, "Expected type argument for constructing non-structure type")
                    .to_compile_error()
                    .into();
            };
            let generated = inner_place_expr(quote!{ (*ptr) }, &e, 0);
            return quote! {

                unsafe {
                    let _ensure_correct = || { #e };

                    let mut res = std::boxed::Box::<#ty>::new_uninit();

                    let ptr = res.as_mut_ptr();

                    #generated

                    res.assume_init()
                }
            }.into()
        }
    };

    if let Some(rest) = &struct_expr.rest {
        return syn::Error::new_spanned(rest, "place_boxed limitation: Cannot use \
        ..Rest expressions in struct initializers")
            .to_compile_error()
            .into();
    }



    let path = &struct_expr.path;


    let mut generated = Vec::new();

    // std::boxed::Box::<i32>::new_uninit()



    for field in &struct_expr.fields {
        let name = &field.member;
        generated.push(
            inner_place_expr(
                quote!{
                    (*ptr).#name
                },
                &field.expr, 0
            )
        )
    }



    quote! {
        unsafe {
            let _ensure_struct_correct = || {
                #struct_expr
            };

            let mut res = std::boxed::Box::<#path>::new_uninit();

            let ptr = res.as_mut_ptr();

            #(#generated)*

            res.assume_init()

        }
    }.into()
}