icu4x icon indicating copy to clipboard operation
icu4x copied to clipboard

Databake: allow a static result

Open alexkazik opened this issue 11 months ago • 2 comments

I've created a few helpers to bake from a heap type into a static type.

Struct to bake:

#[derive(Bake)]
#[databake(path = crate::stories)]
pub struct Chapter {
    pub name: AsStaticStr<String>,
    pub paragraphs: VecAsRefSlice<AsStaticStr<String>>,
}

Struct generated:

pub struct Chapter {
    pub name: &'static str,
    pub paragraphs: &'static [&'static str],
}

Cow<'_, str> and other collections are also supported (at least in theory, I've not tested it).

It's created by the code below. If interested I can create a PR.

#[repr(transparent)]
pub struct AsStaticStr<T>(pub T);

impl<T> Bake for AsStaticStr<T>
where
    T: AsRef<str>,
{
    fn bake(&self, _ctx: &CrateEnv) -> TokenStream {
        let value = self.0.as_ref();
        quote!(#value)
    }
}

#[repr(transparent)]
pub struct AsRefSlice<I, T>(pub I, pub PhantomData<T>);

impl<I, T> AsRefSlice<I, T> {
    pub fn new(i: I) -> Self {
        AsRefSlice(i, PhantomData)
    }
}

impl<I, T> Bake for AsRefSlice<I, T>
where
    for<'a> &'a I: IntoIterator<Item = &'a T>,
    T: Bake,
{
    fn bake(&self, ctx: &CrateEnv) -> TokenStream {
        bake_iter(self.0.into_iter(), ctx)
    }
}

#[repr(transparent)]
pub struct VecAsRefSlice<T>(pub Vec<T>);

impl<T> Bake for VecAsRefSlice<T>
where
    T: Bake,
{
    fn bake(&self, ctx: &CrateEnv) -> TokenStream {
        bake_iter(self.0.iter(), ctx)
    }
}

fn bake_iter<'a, I, T>(iter: I, ctx: &CrateEnv) -> TokenStream
where
    I: Iterator<Item = &'a T>,
    T: Bake + 'a,
{
    let mut inner = TokenStream::new();
    for e in iter {
        let e = e.bake(ctx);
        inner.extend(quote! {#e,});
    }

    quote! {&[#inner]}
}

possible type alises:

type StringAsStaticStr = AsStaticStr<String>;
type CowAsStaticStr<'a> = AsStaticStr<Cow<'a, str>>;

// use this instead of the explicit type above: new or PhantomData must be used, has 2. field with it
type VecAsRefSlice<T> = AsRefSlice<Vec<T>, T>;

Also the names could probably be shorter and "better", I'm open for suggestions.

alexkazik avatar Mar 07 '24 17:03 alexkazik