#Wrapping a Struct taking a Fn Generic

13 messages · Page 1 of 1 (latest)

halcyon sage
#

I have a struct

struct MyType<T: Fn(u32) -> u32> {
    my_thingy: T
}

This struct is pretty cool! I'd like to make a wrapper for it.

struct MyWrapper {
    my_type: MyType<...>
}

impl MyWrapper {
    pub fn new() -> MyWrapper {
        MyWrapper {
            my_type: MyType { my_thingy: |x| x + 4 }
        }
    }
}

What do I put in ...? I know I can resolve this with Box<dyn ...> and modifying MyType to take a trait. Is there a way to avoid the heap and not change MyType?

sleek spire
#

In your particular example, you can use a function pointer as the concrete type. Lambdas that don't capture anything from the environment are just anonymous functions and can be coerced into function pointers

#

?play

struct MyType<T: Fn(u32) -> u32> {
    my_thingy: T
}

struct MyWrapper {
    my_type: MyType<fn(u32) -> u32>
}

impl MyWrapper {
    pub fn new() -> MyWrapper {
        MyWrapper {
            my_type: MyType { my_thingy: |x| x + 4 }
        }
    }
}

fn main() {
    let wrapper = MyWrapper::new();
    println!("{}", (wrapper.my_type.my_thingy)(10));
}
kind dewBOT
#
14```
halcyon sage
#

that is very nice

#

what if i want some context?

#

no user pointer

sleek spire
#

I'm not sure I understand the question sorry, perhaps an example of the API you're going for?

halcyon sage
#

i mean like

    pub fn new(z: u32) -> MyWrapper {
        MyWrapper {
            my_type: MyType { my_thingy: |x| x + z }
        }
    }
#

i believe this doesnt compile?

sleek spire
#

Hmmm yeah you can't really name the type of that closure once it captures things from the environment, it's no longer coercible to a function pointer instead being some anonymous compiler generated callable struct containing the captured variables

If not using the heap then you will probably have to just propagate the generic type parameter to the wrapper

But then that defeats the purpose of having the wrapper I'm guessing if the purpose is to get rid of the generics

sleek spire
#

One way is to use a side-channel at a fixed location (so that the lambda doesn't need to capture it and simply reads from that location). Have the wrapper write to that location before calling the function pointer.....not necessarily a good idea but it does the job

#

?play

use std::sync::atomic::{AtomicU32, Ordering};

static NUM_TO_ADD: AtomicU32 = AtomicU32::new(0);

struct MyType<T: Fn(u32) -> u32> {
    my_thingy: T
}

struct MyWrapper {
    my_type: MyType<fn(u32) -> u32>,
    z: u32
}

impl MyWrapper {
    fn new(z: u32) -> MyWrapper {
        MyWrapper {
            my_type: MyType { my_thingy: |x| x + NUM_TO_ADD.load(Ordering::Relaxed) },
            z
        }
    }
    
    fn call(&self, x: u32) -> u32 {
        NUM_TO_ADD.store(self.z, Ordering::Relaxed);
        (self.my_type.my_thingy)(x)
    }
}

fn main() {
    let wrapper = MyWrapper::new(38);
    println!("{}", wrapper.call(10));
}