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