On Sat, 2014-02-22 at 22:48 +0100, Philippe Delrieu wrote:
> Thank for you reply. But I don't see any solution to my problem.. I'll
> explain it a little more.
> 
> I want to develop a sort of GUI. The GUI has its own logic and use a
> rendering engine to do the work. I want my GUI separate of the
> rendering engine.
> In the first solution I use a trait that hide the renderer. So I have
> a struct that old the renderer that implement the trait. It is created
> at the start of ther application and  passed to every GUI call. At the
> end the trait is casted to the effective renderer to do the work:
> 
> trait Renderer{}
> struct MyRender{
>     API_render: ~effectiveRenderer,
> }
> 
> impl Renderer for MyRender{}
> 
> struct MyGUIWidget;
> 
> impl MyGUIWidget {
>     fn draw(&self, renderer: &renderer)    {  //here I know what type
> of renderer to use.
>         let myrender  = render as &MyRender; //error: non-scalar cast:
> `&Renderer<no-bounds>` as `&MyRender`
>         myrender.API_render.render(); 
>     }
> }
> 
> #[main]
> fn main() {
>     let render = MyRender{API_render: ~...}; //init with user choice
> renderer
>     let widget = MyGUIWidget;
>     widget.draw(render); //draw
> }
> 
> I didn't find a way to send specific Renderer to an API with a generic
> trait and to polymorph it when I know which struct it is.
> 
> I can use a singleton or a static variable but static allocation
> doesn't seem to be allowed (as I undersdant the documentation).
> 
> So I try with closure and I have a sort of example working using a
> renderer :
> trait Renderer{} // 
> 
> struct MyRender{
>     API_render: ~effectiveRenderer,
> }
> 
> impl Renderer for MyRender{}
> 
> 
> trait Container{
>     fn draw(&self, draw_render: ||);
> }
> 
> struct MyContainer    {
>     value :~str,
> }
> 
> impl Container for MyContainer {
>     fn draw(&self, draw_render: ||)    {
>         draw_render();
>     }
> }
> 
> #[main]
> fn main() {    
>      let render = MyRender{API_render: ~StringRender}; //init with
> user choice renderer
>     let container = MyContainer{value: ~"value"};
>     container.draw(||    {
>         render.API_render.render(container.value);
>     }); //draw
> }
> 
> To extend my API I need to use more closure and if I don't what to
> construct every thing in the main I have to return closure constructed
> by each widget for example.
> 
> My last idea is to use a spawned task that hold the renderer and send
> it the widget to draw but It seems to me a little complicated.
> 
> So I don't see any simple to do it. If anybody can help, it would be
> very helpful.
> 
> Philippe
> 

I believe you want something like:

pub mod rendering {
    trait RendererTrait {
        fn draw_line(&mut self);
    }

    pub struct Renderer {
        renderer: ~RendererTrait
    }

    impl Renderer {
        pub fn draw_line(&mut self) {
            self.renderer.draw_line()
        }
    }

    pub fn get_renderer() -> Renderer {
        // TODO: Choose correct renderer
        Renderer {renderer: ~gtk::GtkRenderer}
    }

    mod gtk {
        pub struct GtkRenderer;

        impl ::rendering::RendererTrait for GtkRenderer {
            fn draw_line(&mut self) {}
        }
    }
}

struct Container;

trait Widget {
    fn draw(&self, renderer: &mut rendering::Renderer);
}

impl Widget for Container {
    fn draw(&self, renderer: &mut rendering::Renderer) {
        renderer.draw_line()
    }
}

pub fn main() {
    let mut renderer = rendering::get_renderer();
    let container = Container;
    container.draw(&mut renderer);
}


I'm not expert in rust so I hope I got visibility right - the
rendering::Renderer and rendering::gtk are suppose to be hidden from
user.

Although if user have choice of renderer IMHO something like that would
be better:

pub mod rendering {
    pub trait Renderer {
        fn draw_line(&mut self);
    }

    pub mod gtk {
        pub struct GtkRenderer;

        impl GtkRenderer {
            pub fn new() -> GtkRenderer {
                GtkRenderer
            }
        }

        impl ::rendering::Renderer for GtkRenderer {
            fn draw_line(&mut self) {}
        }
    }
}

struct Container;

trait Widget {
    fn draw<Renderer : rendering::Renderer>(&self, renderer: &mut
Renderer);
}

impl Widget for Container {
    fn draw<Renderer : rendering::Renderer>(&self, renderer: &mut
Renderer) {
        renderer.draw_line()
    }
}

pub fn main() {
    let mut renderer = rendering::gtk::GtkRenderer::new();
    let container = Container;
    container.draw(&mut renderer);
}

The change is similar to change from lambdas to typeclasses in say
Haskell. YMMV if it is good style in Haskell but it has nice properties
in rust (like static dispatch).

> Le 20/02/2014 04:14, Jack Moffitt a écrit :
> 
> > > I'am learning the functional programming paradigm with rust and to help 
> > > me I
> > > decide to translate the pattern of the book "Functional Programming 
> > > Patterns
> > > in Scala and Clojure" in Rust. In this work I have a problem to return a
> > > closure (or a function) as a return value and I didn't find any solution. 
> > > I
> > > understand the problem but I can't find a solution. The code is :
> > Closures in Rust are stack allocated, so you can't return them from a
> > function since the function's stack will be gone. You can use either a
> > proc() or a ~Trait object. A proc can only be called once, but a trait
> > object can be called many times. If you don't need to close over any
> > state (which it appears you don't from your example), then you can
> > return bare functions.
> > 
> > Here's a trait object example (untested and incomplete):
> > 
> > trait Comparison {
> >   fn compare(&self, p1: &Person, p2: &Person) -> Ordering;
> > }
> > 
> > fn make_comparison() -> ~Comparison {
> >   struct ClosedOverState {
> >      ...
> >   }
> >   impl Comparison for ClosedOverState {
> >     fn compare(...) -> Ordering {
> >        .... // access state through self.foo
> >     }
> >   }
> > 
> >   ~ClosedOverState {
> >     foo: 0,
> >   }
> > }
> > 
> > It can be simplified with macros.
> > 
> > jack.
> > 
> > 
> 

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to