That actually worked much better than I expected inlining everything and
getting rid of vtables (I don't have support for .data section at the
moment :-) ).

I can't say the syntax is very clear to me, but I can get used to it.
Still, one more question remains. I have a "debug output" concept, which
means that debug::d("str") gets delivered to either LCD or UART, whatever
is configured at runtime. I do it via static mut:

pub trait Debugger {
  fn debugs(&mut self, s: &str);
}

pub static mut debug_output: *mut c12332::C12332<'static, &'static
spi::SPI> = unsafe { init() };

pub fn d(s: &str) {
  let debugger = unsafe { &mut (*debug_output) as &mut Debugger }; //
failed to find an implementation of trait hal::spi::SPI for &'static
hal::spi::SPI:'static
  debugger.debugs(s);
}

pub fn set_debugger(lcd: *mut c12332::C12332<&spi::SPI>) {
  unsafe { debug_output = lcd; };
}

I don't really support UART now, but I'd still like to access my LCD via a
globally known static getter. How can I re-write that with typed struct?


On Tue, Apr 8, 2014 at 6:26 PM, Corey Richardson <co...@octayn.net> wrote:

> You don't use bounds in the struct, you put them in the impl. So you
> would instead say
>
>
> struct LCD<S> {
>   spi: S,
>   ...
> }
>
>
> and then:
>
> impl<S: SPI> LCD<S> {
>     ...
> }
>
> On Tue, Apr 8, 2014 at 1:23 PM, Vladimir Pouzanov <farcal...@gmail.com>
> wrote:
> > I might have found an unsupported case.
> >
> > Consider the following:
> >
> > trait SPI { ... }
> >
> > struct McuSPI;
> > impl SPI for McuSPI { ... }
> >
> > struct LCD {
> >   spi: &SPI,
> >   ...
> > }
> >
> > This code results in a dynamic dispatch to SPI, as "trait bounds are not
> > allowed in structure definitions". Is it in any way possible to use
> static
> > dispatch from LCD to SPI given the exact implementations are known at
> > compile time?
> >
> >
> > On Thu, Apr 3, 2014 at 2:46 AM, Ashish Myles <marci...@gmail.com> wrote:
> >>
> >> And just in case there is a confusion (as I have noticed others to
> >> have), it might help to see a specific example comparing static
> >> dispatch with dynamic.
> >>
> >> // This is a single function for all types implementing the LCD Trait.
> >> fn foo(x : &LCD) { // x's type is &LCD rather than the actual type of
> >> the object being passed in
> >>     x.line(....); // dynamic dispatch
> >> }
> >>
> >> // Like C++ templates, this generates a function for each type T that
> >> implements LCD.
> >> fn foo<T : LCD>(x : &T) { // x's type is &T rather than &LCD
> >>     x.line(....); // static dispatch based on type T known at
> compile-time
> >> }
> >>
> >> On Wed, Apr 2, 2014 at 8:32 AM, Daniel Micay <danielmi...@gmail.com>
> >> wrote:
> >> > On 02/04/14 06:25 AM, Vladimir Pouzanov wrote:
> >> >> If I get it right, calls to traits are resolved in runtime (so,
> traits
> >> >> are kind of similar to C++ virtual methods).
> >> >
> >> > All method calls on regular types are resolved via static dispatch,
> >> > whether or not they come from a trait. For example, consider a generic
> >> > function like the following:
> >> >
> >> >     fn min<T: TotalOrd>(a: T, b: T) -> T {
> >> >         if a < b { a } else { b }
> >> >     }
> >> >
> >> > This function performs a *static* call of the `lt` method defined on
> the
> >> > `Ord` trait that `TotalOrd` inherits from. Generics are fully expanded
> >> > at compile-time just as C++ templates are.
> >> >
> >> > Rust also allows using traits as boxed objects, but this is an
> entirely
> >> > transparent choice. They're almost always used for static dispatch via
> >> > trait bounds on generics, or simply outside of generics.
> >> >
> >> >> What I'm proposing here is a compile-time approach.
> >> >>
> >> >> Let's say we have the following trait:
> >> >>
> >> >> pub trait LCD {
> >> >>   fn line(&mut self, x0_b: i32, y0_b: i32, x1: i32, y1: i32, color:
> >> >> u8);
> >> >>   fn rect(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: u8);
> >> >>   fn fillrect(&mut self, x0_b: i32, y0_b: i32, x1_b: i32, y1_b: i32,
> >> >> color: u8);
> >> >>   fn putc(&mut self, value: char);
> >> >>   fn puts(&mut self, s: &str);
> >> >>
> >> >>   fn flush(&self);
> >> >>   fn clear(&mut self);
> >> >> }
> >> >>
> >> >> which defined a LED screen. There are two structs implementing it:
> >> >> C12832 and ILI9341 (two different lcd controllers).
> >> >>
> >> >> So I want my app to print hello world on lcd, I write the following
> >> >> code:
> >> >>
> >> >>   let mut lcd = lcd_c12832::C12832::new(spi);
> >> >>   let mut l: &mut lcd::LCD = lcd as &mut lcd::LCD;
> >> >>   l.puts("hello, world");
> >> >>
> >> >> Which results in a runtime dispatch, a slower and bigger code than
> the
> >> >> one I'd have without a trait.
> >> >
> >> > You can call methods defined on a trait without boxing the object as a
> >> > trait object. The ability to perform dynamic dispatch via a trait
> object
> >> > is totally optional. The methods can also be called directly,
> including
> >> > inside a generic function by specifying the trait as a type parameter
> >> > bound. You can simply call the `puts` method directly on the `lcd`
> >> > object without a cast.
> >> >
> >> >> A second problem is there is no easy way to write unified code that
> >> >> supports both the lcds based on passed in --cfg, as I can't
> >> >> apply #[cfg(lcd_c12832)] to a chunk of code in fn, and it's kind of
> >> >> problematic to return a &LCD out from it given that there is no heap
> >> >> and
> >> >> no analog of placement new from C++.
> >> >
> >> > Rust supports generic functions, and you can write code supporting
> both
> >> > types by making it generic. The choice between static dispatch and
> >> > dynamic dispatch is entirely up to you in the current system.
> >> >
> >> >> Proposed binding concept solves those two problems:
> >> >>
> >> >> #[cfg(lcd_c12832)]
> >> >> let Binding: binding {
> >> >>   let lcd: &lcd_c12832::C12832;
> >> >>   let main: &Main;
> >> >>
> >> >>   bind main.lcd = lcd;
> >> >> }
> >> >>
> >> >> at this point of time compiler can be sure about what struct is
> >> >> implementing LCD trait for main.lcd and can bind the function bodies
> as
> >> >> compile time, inlining them if applicable.
> >> >>
> >> >> This also might be something that is already implemented, please
> >> >> advice.
> >> >> The goal here is to minimise runtime code being executed and its
> size.
> >> >
> >> >
> >> >
> >> > _______________________________________________
> >> > Rust-dev mailing list
> >> > Rust-dev@mozilla.org
> >> > https://mail.mozilla.org/listinfo/rust-dev
> >> >
> >
> >
> >
> >
> > --
> > Sincerely,
> > Vladimir "Farcaller" Pouzanov
> > http://farcaller.net/
> >
> > _______________________________________________
> > Rust-dev mailing list
> > Rust-dev@mozilla.org
> > https://mail.mozilla.org/listinfo/rust-dev
> >
>
>
>
> --
> http://octayn.net/
>



-- 
Sincerely,
Vladimir "Farcaller" Pouzanov
http://farcaller.net/
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to