Implementing traits that depend on each other

I am trying to create a way to pass custom allocators to an object when I create it. These allocators need to keep track of some of the details of what they are allocating. I want the allocator to determine how to allocate and the object to determine how it is represented (separation of concerns). So I implemented a trait for each of these separate concerns. But I am getting the error

expected type parameter `U` found type `f64`

link to playground

I don't understand what this message is saying and why I can't pass self into my alloc function. Hoping someone can help me understand this. It looks like I have circular Type dependency or something. But I can't seem to find a way to implement these traits without it.

trait Alloc<T> where T: Sized {
    fn alloc(&mut self, obj: T) -> Box<T>;
}

trait IntoBox<T, U> where T: Alloc<U>, U: Sized {
    fn into_box(self, alloc: &mut T) -> Type;
}

// Dummy Object
enum Type {
    Float(Box<f64>),
    Int(i64),
    String(Box<String>),
}

// Dummy Struct
struct Arena{
    count: usize,
}

impl<T: Sized> Alloc<T> for Arena {
    // Dummy implementation
    fn alloc(&mut self, obj: T) -> Box<T> {
        self.count += 1;
        Box::new(obj)
    }
}

impl<T: Alloc<U>, U: Sized> IntoBox<T, U> for f64 {
    fn into_box(self, allocator: &mut T) -> Type {
        let boxed = allocator.alloc(self);
        Type::Float(boxed)
    }
}

fn main() {
    let mut allocator = Arena{count: 0};
    let x = 1.5;
    x.into_box(&mut allocator);
}

It fails to compile because U might be something else than f64, but you can only put an Box<f64> into Type::Float. This compiles:

impl<T: Alloc<f64>> IntoBox<T, f64> for f64 {
    fn into_box(self, allocator: &mut T) -> Type {
        let boxed = allocator.alloc(self);
        Type::Float(boxed)
    }
}
1 Like

Thanks. I did not realize that Type parameters could be substituted with concrete types.