Skip to content

Instantly share code, notes, and snippets.

@sagacity
Created July 25, 2017 15:46
Show Gist options
  • Select an option

  • Save sagacity/0a23d6cd66553d321b128e7da84f0595 to your computer and use it in GitHub Desktop.

Select an option

Save sagacity/0a23d6cd66553d321b128e7da84f0595 to your computer and use it in GitHub Desktop.

Revisions

  1. sagacity created this gist Jul 25, 2017.
    255 changes: 255 additions & 0 deletions main.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,255 @@
    use std::collections::HashMap;
    use std::rc::Rc;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    struct Component {
    events: HashMap<Event, Box<StateCallback>>,
    children: Vec<Component>,
    }

    impl Component {
    fn invoke(&self, event: Event) -> Component {
    let f = &self.events[&event];
    f.invoke()
    }

    fn children(&self) -> &Vec<Component> {
    &self.children
    }
    }

    #[derive(PartialEq, Hash, Eq)]
    enum Event {
    Pressed,
    Released
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    trait State where Self: Sized + Clone + 'static {
    fn component(&self, context: BuildContext<Self>) -> Component;

    fn build(&self) -> Component {
    self.component(self.context())
    }

    fn context(&self) -> BuildContext<Self> {
    BuildContext::new(self)
    }
    }

    struct BuildContext<S: State> {
    state_provider: Rc<StateProvider<S>>
    }

    impl<S: State> BuildContext<S> {
    fn new(state: &S) -> BuildContext<S> {
    BuildContext {
    state_provider: Rc::new(StateProvider { state: state.clone() })
    }
    }
    }

    fn button<S: State>(context: &BuildContext<S>) -> ButtonBuilder<S> {
    ButtonBuilder { builder: Builder::new(context) }
    }

    fn label<S: State>(context: &BuildContext<S>) -> LabelBuilder<S> {
    LabelBuilder { builder: Builder::new(context) }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    struct Builder<S: State> {
    state_provider: Rc<StateProvider<S>>,
    events: HashMap<Event, Box<StateCallback>>,
    children: Vec<Component>,
    }

    type StateHandler<S> = Box<Fn(&S) -> S>;

    impl<S: State> Builder<S> {
    fn new(context: &BuildContext<S>) -> Builder<S> {
    Builder {
    state_provider: context.state_provider.clone(),
    events: HashMap::new(),
    children: Vec::new(),
    }
    }

    fn register_event(&mut self, event: Event, handler: StateHandler<S>) {
    let f = GenericStateCallback {
    state_provider: self.state_provider.clone(),
    handler,
    };

    self.events.insert(event, Box::new(f));
    }

    fn child(&mut self, child: Component) {
    self.children.push(child);
    }

    fn build(self) -> Component {
    Component {
    events: self.events,
    children: self.children
    }
    }
    }

    trait StateCallback {
    fn invoke(&self) -> Component;
    }

    struct GenericStateCallback<S: State> {
    state_provider: Rc<StateProvider<S>>,
    handler: StateHandler<S>
    }

    impl<S: State> StateCallback for GenericStateCallback<S> {
    fn invoke(&self) -> Component {
    let state = self.state_provider.provide();
    let new_state = (self.handler)(&state);
    new_state.build()
    }
    }

    struct StateProvider<S: State> {
    state: S
    }

    impl<S: State> StateProvider<S> {
    fn provide(&self) -> &S {
    &self.state
    }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    trait GetInnerBuilder<S: State> {
    fn inner_builder(&mut self) -> &mut Builder<S>;
    }

    trait OnBuilder<S: State> where Self: GetInnerBuilder<S> + Sized {
    fn on(mut self, event: Event, handler: StateHandler<S>) -> Self {
    self.inner_builder().register_event(event, handler);
    self
    }
    }

    trait ChildBuilder<S: State> where Self: GetInnerBuilder<S> + Sized {
    fn child<C: Into<Component>>(mut self, child: C) -> Self {
    self.inner_builder().child(child.into());
    self
    }

    fn children<C: IntoIterator<Item=Component>>(mut self, children: C) -> Self {
    for child in children {
    self.inner_builder().child(child.into());
    }
    self
    }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    macro_rules! impl_builder {
    ($builder_name:ident) => {
    impl_builder!($builder_name;);
    };
    ($builder_name:ident; $($o:ty),*) => (
    // Build component from inner builder
    impl<S: State> From<$builder_name<S>> for Component {
    fn from(c: $builder_name<S>) -> Self {
    c.builder.build()
    }
    }

    // Access inner builder (assumed to be in self.builder)
    impl<S: State> GetInnerBuilder<S> for $builder_name<S> {
    fn inner_builder(&mut self) -> &mut Builder<S> { &mut self.builder }
    }

    // Implement additional traits
    $(impl<S: State> $o for $builder_name<S> {})*
    );
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    struct ButtonBuilder<S: State> {
    builder: Builder<S>
    }

    impl_builder!(ButtonBuilder; OnBuilder<S>, ChildBuilder<S>);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    struct LabelBuilder<S: State> {
    builder: Builder<S>
    }

    impl<S: State> LabelBuilder<S> {
    fn caption<C: Into<String>>(self, caption: C) -> Self {
    //self.caption = caption;
    let _ = caption; // ignore for now
    self
    }
    }

    impl_builder!(LabelBuilder);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    #[derive(Clone, Debug)]
    struct MyAppState {
    counter: u32
    }

    struct MyApp;

    impl MyApp {
    fn new() -> MyAppState {
    MyAppState {
    counter: 0
    }
    }
    }

    impl State for MyAppState {
    fn component(&self, context: BuildContext<Self>) -> Component {
    println!("Current state: {:?}", self);

    button(&context)
    .on(Event::Pressed, Box::new(|state| {
    println!("pressed");

    MyAppState {
    counter: state.counter + 1
    }
    }))
    .on(Event::Released, Box::new(|state| {
    println!("released");

    MyAppState {
    counter: state.counter + 2
    }
    }))
    .children(vec![
    label(&context).caption(format!("You've clicked {} times!", self.counter)).into()
    ])
    .into()
    }
    }

    fn main() {
    let app = MyApp::new();
    let component = app.build()
    .invoke(Event::Pressed)
    .invoke(Event::Released)
    .invoke(Event::Pressed);

    println!("#children: {:?}", component.children().len());
    }