#![feature(test)] extern crate attr; extern crate test; use test::{Bencher, black_box}; use attr::retrieve; use attr::Traverse; trait Attributes { fn attrs() -> AttributeType; } #[derive(Debug)] pub struct Foo { bar: String, batz: Bla, numbers: Vec } #[derive(Debug)] pub struct Bla { name: String } pub mod foo { use attr::Attr; use attr::IndexableAttr; use attr::IterableAttr; use super::Attributes; use super::Foo; use super::Bla; #[derive(Default)] pub struct Bar; #[derive(Default)] pub struct Batz; #[derive(Default)] pub struct Numbers; #[derive(Default)] pub struct FooAttributes { pub bar: Bar, pub batz: Batz, pub numbers: Numbers } impl Attributes for Foo { fn attrs() -> FooAttributes { FooAttributes::default() } } impl<'a> Attr<&'a Foo> for Bar { type Output = &'a str; fn get(&self, i: &'a Foo) -> &'a str { i.bar.as_ref() } fn name(&self) -> &'static str { "bar" } } impl<'a> Attr<&'a mut Foo> for Bar { type Output = &'a mut String; fn get(&self, i: &'a mut Foo) -> &'a mut String { &mut i.bar } fn name(&self) -> &'static str { "bar" } } impl<'a> Attr<&'a Foo> for Batz { type Output = &'a Bla; fn get(&self, i: &'a Foo) -> &'a Bla { &i.batz } fn name(&self) -> &'static str { "batz" } } impl<'a> Attr<&'a mut Foo> for Batz { type Output = &'a mut Bla; fn get(&self, i: &'a mut Foo) -> &'a mut Bla { &mut i.batz } fn name(&self) -> &'static str { "batz" } } impl<'a> Attr<&'a Foo> for Numbers { type Output = &'a[i32]; fn get(&self, i: &'a Foo) -> &'a[i32] { i.numbers.as_ref() } fn name(&self) -> &'static str { "numbers" } } impl<'a> Attr<&'a mut Foo> for Numbers { type Output = &'a mut Vec; fn get(&self, i: &'a mut Foo) -> &'a mut Vec { &mut i.numbers } fn name(&self) -> &'static str { "numbers" } } impl<'a> IndexableAttr<&'a Foo, usize> for Numbers { type Output = i32; fn at(&self, i: &'a Foo, idx: usize) -> i32 { self.get(i)[idx] } } impl<'a> IndexableAttr<&'a mut Foo, usize> for Numbers { type Output = &'a mut i32; fn at(&self, i: &'a mut Foo, idx: usize) -> &'a mut i32 { unsafe { self.get(i).get_unchecked_mut(idx) } } } impl<'a> IterableAttr<'a, &'a Foo> for Numbers { type Item = &'a i32; fn iter(&self, i: &'a Foo) -> Box + 'a> { Box::new(self.get(i).iter()) } } impl<'a> IterableAttr<'a, &'a mut Foo> for Numbers { type Item = &'a mut i32; fn iter(&self, i: &'a mut Foo) -> Box +'a> { Box::new(self.get(i).iter_mut()) } } } pub mod bla { use attr::Attr; use super::Attributes; use super::Bla; #[derive(Default)] pub struct Name; #[derive(Default)] pub struct BlaAttributes { pub name: Name, } impl Attributes for Bla { fn attrs() -> BlaAttributes { BlaAttributes::default() } } impl<'a> Attr<&'a Bla> for Name { type Output = &'a str; fn get(&self, i: &'a Bla) -> &'a str { i.name.as_ref() } fn name(&self) -> &'static str { "name" } } impl<'a> Attr<&'a mut Bla> for Name { type Output = &'a mut String; fn get(&self, i: &'a mut Bla) -> &'a mut String { &mut i.name } fn name(&self) -> &'static str { "name" } } } #[bench] fn direct_access_bench(b: &mut Bencher) { let f = Foo { bar: "foobar".into(), batz: Bla { name: "foo".into() }, numbers: vec![1,2,3] }; b.iter(|| black_box(direct_access(&f)) ); } #[inline] fn direct_access(f: &Foo) -> &str { &f.batz.name } #[bench] fn through_path(b: &mut Bencher) { let f = Foo { bar: "foobar".into(), batz: Bla { name: "foo".into() }, numbers: vec![1,2,3] }; b.iter(|| black_box(path_access(&f)) ); } #[inline] fn path_access(f: &Foo) -> Result<&str, String> { let p = retrieve(bla::Name).from(foo::Batz); p.traverse(f) }